errno and libc_errno in LLVM-libc#
Many C and POSIX functions report errors by setting errno. Because LLVM-libc
supports multiple build and deployment modes (Full Host Build,
Full Cross Build, Overlay Mode, baremetal, GPU, and
header-only libc/shared/), internal code and unit tests access errno
through libc_errno.
Targets Overview#
errno support is split across three targets:
CMake Target |
Bazel Target |
Header / Source |
Purpose |
|---|---|---|---|
|
|
|
Error constants ( |
|
|
|
Declares |
|
|
|
Defines the backing storage ( |
Usage Guidelines#
1. Header Inclusion#
Never
#include <errno.h>inlibc/src/**or unit tests (libc/test/src/**).Only need error constants (
EINVAL,ERANGE,EDOM, etc.)? Include"hdr/errno_macros.h":#include "hdr/errno_macros.h"
Read or write
errno? Include"src/__support/libc_errno.h"(which also includes"hdr/errno_macros.h") and uselibc_errno:#include "src/__support/libc_errno.h" libc_errno = EINVAL;
2. Where to Set libc_errno#
Set
libc_errnoonly at the public entrypoint boundary (LLVM_LIBC_FUNCTION) just before returning an error, or viafputil::set_errno_if_requiredin math implementations.Internal helpers in
libc/src/__support/should not setlibc_errnodirectly; returnErrorOr<T>orcpp::optional<T>instead and setlibc_errnoin the entrypoint:LLVM_LIBC_FUNCTION(int, close, (int fd)) { auto res = linux_syscalls::close(fd); if (!res) { libc_errno = res.error(); return -1; } return 0; }
3. Build Dependencies#
Target Type |
Only Needs Error Constants ( |
Reads or Writes |
|---|---|---|
|
|
|
Public Entrypoints ( |
|
|
Tests / Fuzzers / Benchmarks |
|
Linked automatically ( |
While public entrypoints normally cannot depend on other entrypoints,
libc.src.errno.errnois explicitly allowed inALLOWED_DEPSinlibc/cmake/modules/LLVMLibCObjectRules.cmake.
4. Testing errno#
Test rules (
add_libc_test,add_fp_unittest,add_integration_test,add_libc_fuzzer, andperf_test) automatically linklibc.src.errno.errno.Unit tests that check
errnoshould useErrnoCheckingTest(test/UnitTest/ErrnoCheckingTest.h) orErrnoSetterMatcher(test/UnitTest/ErrnoSetterMatcher.h):ErrnoCheckingTestresetslibc_errno = 0before each test and verifieslibc_errno == 0at the end.ErrnoSetterMatcher(ASSERT_THAT(..., Fails(EINVAL))/Succeeds()) checks and resetslibc_errnoautomatically.
Header-only
libc/shared/*tests (libc/test/shared/*): Compiled withLIBC_ERRNO_MODE_SYSTEM_INLINEin overlay mode; checkerrnodirectly when testing error conditions.
LIBC_ERRNO_MODE Configurations#
LIBC_CONF_ERRNO_MODE (passed to the compiler as -DLIBC_ERRNO_MODE=<mode>)
controls how libc_errno is implemented:
Mode |
|
Backing Storage in |
Typical Use Case |
|---|---|---|---|
|
Resolves to |
|
Default configuration. |
|
Inline |
|
Full builds; overlay unit tests. |
|
Inline |
Global |
Single-threaded or thread-local-free targets (GPU, UEFI). |
|
Inline |
Provided by external embedder. |
Baremetal ( |
|
Inline no-op ( |
None (empty TU). |
Minimal embedded environments without |
|
|
None (empty TU). |
Overlay public archive ( |
How LIBC_ERRNO_MODE_DEFAULT Resolves#
When LIBC_ERRNO_MODE is unset or set to LIBC_ERRNO_MODE_DEFAULT:
Full build (
LIBC_FULL_BUILD): resolves toLIBC_ERRNO_MODE_THREAD_LOCAL.Overlay public archive (
LIBC_COPT_PUBLIC_PACKAGING): resolves toLIBC_ERRNO_MODE_SYSTEM_INLINE(libc/shared/libc_common.handlibc/test/shared/also configureLIBC_ERRNO_MODE_SYSTEM_INLINEin non-full builds).Overlay tests, fuzzers, and benchmarks: resolves to
LIBC_ERRNO_MODE_THREAD_LOCAL.
Why libc_errno Header and Runtime Storage Are Separated#
Keeping libc.src.__support.libc_errno (header) separate from
libc.src.errno.errno (runtime object) is necessary for several reasons:
Isolating unit tests from host
errnoin overlay mode: Public overlay archives (libllvmlibc.a) are built with-DLIBC_COPT_PUBLIC_PACKAGINGand use the host’s<errno.h>(LIBC_ERRNO_MODE_SYSTEM_INLINE). Unit tests are built without-DLIBC_COPT_PUBLIC_PACKAGINGand use LLVM-libc’s internalthread_errno(LIBC_ERRNO_MODE_THREAD_LOCAL), preventing tested functions from clobbering the hosterrnoused by the test harness. Conversely, if internal code or tests mistakenly#include <errno.h>and useerrnodirectly, reads and writes will hit different thread-local variables in the same thread.Header-only
libc/shared/*consumption: External LLVM subprojects (such aslibc++andoffload) include headers underlibc/shared/, which setLIBC_ERRNO_MODE_SYSTEM_INLINEand maplibc_errnoto<errno.h>without compiling or linkinglibc_errno.cpp.errno-free math and archive separation (libc.avs.libm.a/libmvec.a):FEnvImpl.hincludessrc/__support/libc_errno.hto definefputil::set_errno_if_required, which is guarded by#ifndef LIBC_MATH_HAS_NO_ERRNO. BecauseErrnomethods are inline, functions that never callset_errno_if_required(such asceil,floor,copysign, vector math, orLIBC_MATH_NO_ERRNObuilds) emit no reference to__llvm_libc_errno(), andlibc.src.errno.errnostays inlibc.arather than being pulled intolibm.aorlibmvec.a.CMake directory ordering:
libc/src/CMakeLists.txtaddssrc/__supportbeforesrc/errnobecauselibc.src.errno.errnodepends onlibc.src.__support.*. Targets underlibc/src/__support/therefore cannot depend onlibc.src.errno.errno.