diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -1,5 +1,6 @@ include "config/public_api.td" +include "spec/posix.td" include "spec/stdc.td" def FloatT : TypeDecl<"float_t"> { @@ -28,6 +29,13 @@ }]; } +def ErrnoMacro : MacroDef<"errno"> { + let Defn = [{ + int *__errno_location() __attribute__((const)); + #define errno (*__errno_location()) + }]; +} + def MathAPI : PublicAPI<"math.h"> { let Functions = [ "acos", @@ -83,3 +91,149 @@ "snprintf", ]; } + +def ErrnoAPI : PublicAPI<"errno.h"> { + string EAgainValue = "14"; + string ENotSupValue = "96"; + + let Macros = [ + // C standard + ErrnoMacro, + SimpleMacroDef<"EDOM", "1">, + SimpleMacroDef<"EILSEQ", "2">, + SimpleMacroDef<"ERANGE", "3">, + + // POSIX + SimpleMacroDef<"EPERM", "4">, + SimpleMacroDef<"ENOENT", "5">, + SimpleMacroDef<"ESRCH", "6">, + SimpleMacroDef<"EINTR", "7">, + SimpleMacroDef<"EIO", "8">, + SimpleMacroDef<"ENXIO", "9">, + SimpleMacroDef<"E2BIG", "10">, + SimpleMacroDef<"ENOEXEC", "11">, + SimpleMacroDef<"EBADF", "12">, + SimpleMacroDef<"ECHILD", "13">, + SimpleMacroDef<"EAGAIN", EAgainValue>, + SimpleMacroDef<"ENOMEM", "15">, + SimpleMacroDef<"EACCES", "16">, + SimpleMacroDef<"EFAULT", "17">, + SimpleMacroDef<"ENOTBLK", "18">, + SimpleMacroDef<"EBUSY", "19">, + SimpleMacroDef<"EEXIST", "20">, + SimpleMacroDef<"EXDEV", "21">, + SimpleMacroDef<"ENODEV", "22">, + SimpleMacroDef<"ENOTDIR", "23">, + SimpleMacroDef<"EISDIR", "24">, + SimpleMacroDef<"EINVAL", "25">, + SimpleMacroDef<"ENFILE", "26">, + SimpleMacroDef<"EMFILE", "27">, + SimpleMacroDef<"ENOTTY", "28">, + SimpleMacroDef<"ETXTBSY", "29">, + SimpleMacroDef<"EFBIG", "30">, + SimpleMacroDef<"ENOSPC", "31">, + SimpleMacroDef<"ESPIPE", "32">, + SimpleMacroDef<"EROFS", "33">, + SimpleMacroDef<"EMLINK", "34">, + SimpleMacroDef<"EPIPE", "35">, + SimpleMacroDef<"EDEADLK", "36">, + SimpleMacroDef<"ENAMETOOLONG", "37">, + SimpleMacroDef<"ENOLCK", "38">, + SimpleMacroDef<"ENOSYS", "39">, + SimpleMacroDef<"ENOTEMPTY", "40">, + SimpleMacroDef<"ELOOP", "41">, + SimpleMacroDef<"EWOULDBLOCK", EAgainValue>, + SimpleMacroDef<"ENOMSG", "43">, + SimpleMacroDef<"EIDRM", "44">, + SimpleMacroDef<"ECHRNG", "45">, + SimpleMacroDef<"EL2NSYNC", "46">, + SimpleMacroDef<"EL3HLT", "47">, + SimpleMacroDef<"EL3RST", "48">, + SimpleMacroDef<"ELNRNG", "49">, + SimpleMacroDef<"EUNATCH", "50">, + SimpleMacroDef<"ENOCSI", "51">, + SimpleMacroDef<"EL2HLT", "52">, + SimpleMacroDef<"EBADE", "53">, + SimpleMacroDef<"EBADR", "54">, + SimpleMacroDef<"EXFULL", "55">, + SimpleMacroDef<"ENOANO", "56">, + SimpleMacroDef<"EBADRQC", "57">, + SimpleMacroDef<"EBADSLT", "58">, + SimpleMacroDef<"EDEADLOCK", "59">, + SimpleMacroDef<"EBFONT", "60">, + SimpleMacroDef<"ENOSTR", "61">, + SimpleMacroDef<"ENODATA", "62">, + SimpleMacroDef<"ETIME", "63">, + SimpleMacroDef<"ENOSR", "64">, + SimpleMacroDef<"ENONET", "65">, + SimpleMacroDef<"ENOPKG", "66">, + SimpleMacroDef<"EREMOTE", "67">, + SimpleMacroDef<"ENOLINK", "68">, + SimpleMacroDef<"EADV", "69">, + SimpleMacroDef<"ESRMNT", "70">, + SimpleMacroDef<"ECOMM", "71">, + SimpleMacroDef<"EPROTO", "72">, + SimpleMacroDef<"EMULTIHOP", "73">, + SimpleMacroDef<"EDOTDOT", "74">, + SimpleMacroDef<"EBADMSG", "75">, + SimpleMacroDef<"EOVERFLOW", "76">, + SimpleMacroDef<"ENOTUNIQ", "77">, + SimpleMacroDef<"EBADFD", "78">, + SimpleMacroDef<"EREMCHG", "79">, + SimpleMacroDef<"ELIBACC", "80">, + SimpleMacroDef<"ELIBBAD", "81">, + SimpleMacroDef<"ELIBSCN", "82">, + SimpleMacroDef<"ELIBMAX", "83">, + SimpleMacroDef<"ELIBEXEC", "84">, + SimpleMacroDef<"ERESTART", "85">, + SimpleMacroDef<"ESTRPIPE", "86">, + SimpleMacroDef<"EUSERS", "87">, + SimpleMacroDef<"ENOTSOCK", "88">, + SimpleMacroDef<"EDESTADDRREQ", "89">, + SimpleMacroDef<"EMSGSIZE", "90">, + SimpleMacroDef<"EPROTOTYPE", "91">, + SimpleMacroDef<"ENOPROTOOPT", "92">, + SimpleMacroDef<"EPROTONOSUPPORT", "93">, + SimpleMacroDef<"ESOCKTNOSUPPORT", "94">, + SimpleMacroDef<"EOPNOTSUPP", ENotSupValue>, + SimpleMacroDef<"ENOTSUP", ENotSupValue>, + SimpleMacroDef<"EPFNOSUPPORT", "97">, + SimpleMacroDef<"EAFNOSUPPORT", "98">, + SimpleMacroDef<"EADDRINUSE", "99">, + SimpleMacroDef<"EADDRNOTAVAIL", "100">, + SimpleMacroDef<"ENETDOWN", "101">, + SimpleMacroDef<"ENETUNREACH", "102">, + SimpleMacroDef<"ENETRESET", "103">, + SimpleMacroDef<"ECONNABORTED", "104">, + SimpleMacroDef<"ECONNRESET", "105">, + SimpleMacroDef<"ENOBUFS", "106">, + SimpleMacroDef<"EISCONN", "107">, + SimpleMacroDef<"ENOTCONN", "108">, + SimpleMacroDef<"ESHUTDOWN", "109">, + SimpleMacroDef<"ETOOMANYREFS", "110">, + SimpleMacroDef<"ETIMEDOUT", "111">, + SimpleMacroDef<"ECONNREFUSED", "112">, + SimpleMacroDef<"EHOSTDOWN", "113">, + SimpleMacroDef<"EHOSTUNREACH", "114">, + SimpleMacroDef<"EALREADY", "115">, + SimpleMacroDef<"EINPROGRESS", "116">, + SimpleMacroDef<"ESTALE", "117">, + SimpleMacroDef<"EUCLEAN", "118">, + SimpleMacroDef<"ENOTNAM", "119">, + SimpleMacroDef<"ENAVAIL", "120">, + SimpleMacroDef<"EISNAM", "121">, + SimpleMacroDef<"EREMOTEIO", "122">, + SimpleMacroDef<"EDQUOT", "123">, + SimpleMacroDef<"ENOMEDIUM", "124">, + SimpleMacroDef<"EMEDIUMTYPE", "125">, + SimpleMacroDef<"ECANCELED", "126">, + SimpleMacroDef<"ENOKEY", "127">, + SimpleMacroDef<"EKEYEXPIRED", "128">, + SimpleMacroDef<"EKEYREVOKED", "129">, + SimpleMacroDef<"EKEYREJECTED", "130">, + SimpleMacroDef<"EOWNERDEAD", "131">, + SimpleMacroDef<"ENOTRECOVERABLE", "132">, + SimpleMacroDef<"ERFKILL", "133">, + SimpleMacroDef<"EHWPOISON", "134">, + ]; +} diff --git a/libc/config/public_api.td b/libc/config/public_api.td --- a/libc/config/public_api.td +++ b/libc/config/public_api.td @@ -10,6 +10,10 @@ string Defn = ""; } +class SimpleMacroDef : MacroDef { + let Defn = !strconcat("#define ", name, " ", defn); +} + class PublicAPI { string HeaderName = name; list Macros = []; diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -28,3 +28,9 @@ DEPENDS llvm_libc_common_h ) + +add_gen_header( + errno_h + DEF_FILE errno.h.def + GEN_HDR errno.h +) diff --git a/libc/include/errno.h.def b/libc/include/errno.h.def new file mode 100644 --- /dev/null +++ b/libc/include/errno.h.def @@ -0,0 +1,14 @@ +//===---------------- C standard library header errno.h ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_ERRNO_H +#define LLVM_LIBC_ERRNO_H + +%%public_api() + +#endif // LLVM_LIBC_ERRNO_H diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt --- a/libc/lib/CMakeLists.txt +++ b/libc/lib/CMakeLists.txt @@ -2,8 +2,10 @@ add_entrypoint_library( llvmlibc DEPENDS + # errno.h entrypoints + __errno_location + # string.h entrypoints - ## C standard library entrypoints strcpy strcat ) diff --git a/libc/spec/posix.td b/libc/spec/posix.td new file mode 100644 --- /dev/null +++ b/libc/spec/posix.td @@ -0,0 +1,144 @@ +def POSIX : StandardSpec<"POSIX"> { + HeaderSpec Errno = HeaderSpec< + "errno.h", + [ + Macro<"EPERM">, + Macro<"ENOENT">, + Macro<"ESRCH">, + Macro<"EINTR">, + Macro<"EIO">, + Macro<"ENXIO">, + Macro<"E2BIG">, + Macro<"ENOEXEC">, + Macro<"EBADF">, + Macro<"ECHILD">, + Macro<"EAGAIN">, + Macro<"ENOMEM">, + Macro<"EACCES">, + Macro<"EFAULT">, + Macro<"ENOTBLK">, + Macro<"EBUSY">, + Macro<"EEXIST">, + Macro<"EXDEV">, + Macro<"ENODEV">, + Macro<"ENOTDIR">, + Macro<"EISDIR">, + Macro<"EINVAL">, + Macro<"ENFILE">, + Macro<"EMFILE">, + Macro<"ENOTTY">, + Macro<"ETXTBSY">, + Macro<"EFBIG">, + Macro<"ENOSPC">, + Macro<"ESPIPE">, + Macro<"EROFS">, + Macro<"EMLINK">, + Macro<"EPIPE">, + Macro<"EDEADLK">, + Macro<"ENAMETOOLONG">, + Macro<"ENOLCK">, + Macro<"ENOSYS">, + Macro<"ENOTEMPTY">, + Macro<"ELOOP">, + Macro<"EWOULDBLOCK">, + Macro<"ENOMSG">, + Macro<"EIDRM">, + Macro<"ECHRNG">, + Macro<"EL2NSYNC">, + Macro<"EL3HLT">, + Macro<"EL3RST">, + Macro<"ELNRNG">, + Macro<"EUNATCH">, + Macro<"ENOCSI">, + Macro<"EL2HLT">, + Macro<"EBADE">, + Macro<"EBADR">, + Macro<"EXFULL">, + Macro<"ENOANO">, + Macro<"EBADRQC">, + Macro<"EBADSLT">, + Macro<"EDEADLOCK">, + Macro<"EBFONT">, + Macro<"ENOSTR">, + Macro<"ENODATA">, + Macro<"ETIME">, + Macro<"ENOSR">, + Macro<"ENONET">, + Macro<"ENOPKG">, + Macro<"EREMOTE">, + Macro<"ENOLINK">, + Macro<"EADV">, + Macro<"ESRMNT">, + Macro<"ECOMM">, + Macro<"EPROTO">, + Macro<"EMULTIHOP">, + Macro<"EDOTDOT">, + Macro<"EBADMSG">, + Macro<"EOVERFLOW">, + Macro<"ENOTUNIQ">, + Macro<"EBADFD">, + Macro<"EREMCHG">, + Macro<"ELIBACC">, + Macro<"ELIBBAD">, + Macro<"ELIBSCN">, + Macro<"ELIBMAX">, + Macro<"ELIBEXEC">, + Macro<"ERESTART">, + Macro<"ESTRPIPE">, + Macro<"EUSERS">, + Macro<"ENOTSOCK">, + Macro<"EDESTADDRREQ">, + Macro<"EMSGSIZE">, + Macro<"EPROTOTYPE">, + Macro<"ENOPROTOOPT">, + Macro<"EPROTONOSUPPORT">, + Macro<"ESOCKTNOSUPPORT">, + Macro<"EOPNOTSUPP">, + Macro<"ENOTSUP">, + Macro<"EPFNOSUPPORT">, + Macro<"EAFNOSUPPORT">, + Macro<"EADDRINUSE">, + Macro<"EADDRNOTAVAIL">, + Macro<"ENETDOWN">, + Macro<"ENETUNREACH">, + Macro<"ENETRESET">, + Macro<"ECONNABORTED">, + Macro<"ECONNRESET">, + Macro<"ENOBUFS">, + Macro<"EISCONN">, + Macro<"ENOTCONN">, + Macro<"ESHUTDOWN">, + Macro<"ETOOMANYREFS">, + Macro<"ETIMEDOUT">, + Macro<"ECONNREFUSED">, + Macro<"EHOSTDOWN">, + Macro<"EHOSTUNREACH">, + Macro<"EALREADY">, + Macro<"EINPROGRESS">, + Macro<"ESTALE">, + Macro<"EUCLEAN">, + Macro<"ENOTNAM">, + Macro<"ENAVAIL">, + Macro<"EISNAM">, + Macro<"EREMOTEIO">, + Macro<"EDQUOT">, + Macro<"ENOMEDIUM">, + Macro<"EMEDIUMTYPE">, + Macro<"ECANCELED">, + Macro<"ENOKEY">, + Macro<"EKEYEXPIRED">, + Macro<"EKEYREVOKED">, + Macro<"EKEYREJECTED">, + Macro<"EOWNERDEAD">, + Macro<"ENOTRECOVERABLE">, + Macro<"ERFKILL">, + Macro<"EHWPOISON">, + ], + [], // Types + [] // Functions + >; + + let Headers = [ + Errno, + ]; +} diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -170,7 +170,20 @@ ] >; + HeaderSpec Errno = HeaderSpec< + "errno.h", + [ + Macro<"errno">, + Macro<"EDOM">, + Macro<"EILSEQ">, + Macro<"ERANGE">, + ], + [], // Types + [] // Functions + >; + let Headers = [ + Errno, Math, String, StdIO, diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt --- a/libc/src/CMakeLists.txt +++ b/libc/src/CMakeLists.txt @@ -1,4 +1,5 @@ -add_subdirectory(string) +add_subdirectory(errno) add_subdirectory(math) +add_subdirectory(string) add_subdirectory(__support) diff --git a/libc/src/errno/CMakeLists.txt b/libc/src/errno/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/errno/CMakeLists.txt @@ -0,0 +1,19 @@ +add_entrypoint_object( + __errno_location + SRCS + errno_location.cpp + HDRS + llvmlibc_errno.h +) + +add_custom_target(libc_errno_unittests) + +add_libc_unittest( + errno_test + SUITE + libc_errno_unittests + SRCS + errno_test.cpp + DEPENDS + __errno_location +) diff --git a/libc/src/errno/errno_location.cpp b/libc/src/errno/errno_location.cpp new file mode 100644 --- /dev/null +++ b/libc/src/errno/errno_location.cpp @@ -0,0 +1,22 @@ +//===----------------- Implementation of __errno_location -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/errno/llvmlibc_errno.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +static thread_local int __errno = 0; + +// __errno_location is not really an entry point but we still want it to behave +// like an entry point because the errno macro resolves to the C symbol +// "__errno_location". +int *LLVM_LIBC_ENTRYPOINT(__errno_location)() { return &__errno; } + +} // namespace __llvm_libc diff --git a/libc/src/errno/errno_test.cpp b/libc/src/errno/errno_test.cpp new file mode 100644 --- /dev/null +++ b/libc/src/errno/errno_test.cpp @@ -0,0 +1,17 @@ +//===---------------------- Unittests for errno --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/errno/llvmlibc_errno.h" + +#include "gtest/gtest.h" + +TEST(ErrnoTest, Basic) { + int test_val = 123; + llvmlibc_errno = test_val; + ASSERT_EQ(test_val, llvmlibc_errno); +} diff --git a/libc/src/errno/llvmlibc_errno.h b/libc/src/errno/llvmlibc_errno.h new file mode 100644 --- /dev/null +++ b/libc/src/errno/llvmlibc_errno.h @@ -0,0 +1,22 @@ +//===------------------ Implementation header for errno -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H +#define LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H + +// Internal code should use this and not use the errno macro from the +// public header. +#define llvmlibc_errno (*__llvm_libc::__errno_location()) + +namespace __llvm_libc { + +int *__errno_location(); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_ERRNO_LLVMLIBC_ERRNO_H