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 @@ -28,6 +28,13 @@ }]; } +def ErrnoMacro : MacroDef<"errno"> { + let Defn = [{ + extern int *__errno_location(); + #define errno *__errno_location() + }]; +} + def MathAPI : PublicAPI<"math.h"> { let Functions = [ "acos", @@ -83,3 +90,9 @@ "snprintf", ]; } + +def ErrnoAPI : PublicAPI<"errno.h"> { + let Macros = [ + ErrnoMacro, + ]; +} 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/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -170,7 +170,17 @@ ] >; + HeaderSpec Errno = HeaderSpec< + "errno.h", + [ + Macro<"errno">, + ], + [], // 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, Smoke) { + 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 macro 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