[libcxx-commits] [libcxx] [libcxx]support freestanding libc++ (PR #208900)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jul 12 19:29:43 PDT 2026
https://github.com/trcrsired updated https://github.com/llvm/llvm-project/pull/208900
>From 38cf359bf0349ec5b915a7e1d5793635aabb4c3b Mon Sep 17 00:00:00 2001
From: trcrsired <oyzawqgcfc at gmail.com>
Date: Sat, 11 Jul 2026 17:56:19 +0800
Subject: [PATCH] [libc++] Support freestanding libc++
---
libcxx/CMakeLists.txt | 55 +++++++--
libcxx/include/__algorithm/sort.h | 3 +
libcxx/include/__config | 13 +-
libcxx/include/__config_site.in | 3 +
libcxx/include/__mbstate_t.h | 10 ++
libcxx/include/ctime | 4 +
libcxx/include/math.h | 37 ++++++
libcxx/include/stdio.h | 14 +++
libcxx/include/stdlib.h | 19 +++
libcxx/include/string.h | 41 ++++++-
libcxx/test/libcxx/libcpp_freestanding.sh.cpp | 111 ++++++++++++++++++
11 files changed, 293 insertions(+), 17 deletions(-)
create mode 100644 libcxx/test/libcxx/libcpp_freestanding.sh.cpp
diff --git a/libcxx/CMakeLists.txt b/libcxx/CMakeLists.txt
index 31aaf2977a9af..ee9be266975fc 100644
--- a/libcxx/CMakeLists.txt
+++ b/libcxx/CMakeLists.txt
@@ -156,21 +156,44 @@ option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
the shared library they shipped should turn this on and see `include/__configuration/availability.h`
for more details." OFF)
-if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
- set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
-elseif(MINGW)
- set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-mingw.cfg.in")
-elseif(WIN32) # clang-cl
- if (LIBCXX_ENABLE_SHARED)
- set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-clangcl.cfg.in")
- else()
- set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static-clangcl.cfg.in")
- endif()
+option(LIBCXX_FREESTANDING
+ "Build libc++ in freestanding mode. This toggle allows the libc++ to work without libc
+ for environments like operating systems kernels or embedded systems." OFF)
+
+if (LIBCXX_FREESTANDING)
+ set(LIBCXX_ENABLE_FILESYSTEM OFF)
+ set(LIBCXX_ENABLE_RANDOM_DEVICE OFF)
+ set(LIBCXX_ENABLE_PARALLEL_ALGORITHMS OFF)
+ set(LIBCXX_ENABLE_SHARED OFF)
+ set(LIBCXX_ENABLE_STATIC OFF)
+ set(CMAKE_ASM_COMPILER_WORKS ON)
+ set(CMAKE_C_COMPILER_WORKS ON)
+ set(CMAKE_CXX_COMPILER_WORKS ON)
+ set(LIBCXX_ENABLE_LOCALIZATION OFF)
+ set(LIBCXX_ENABLE_FSTREAM OFF)
+ set(LIBCXX_ENABLE_STD_MODULES OFF)
+ set(LIBCXX_INCLUDE_BENCHMARKS OFF)
+ set(LIBCXX_ENABLE_WIDE_CHARACTERS OFF)
+ set(LIBCXX_ENABLE_TIME_ZONE_DATABASE OFF)
+ set(LIBCXX_INCLUDE_TESTS Off)
+ set(LIBCXX_ENABLE_THREADS Off)
else()
- if (LIBCXX_ENABLE_SHARED)
- set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared.cfg.in")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+ set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-gcc.cfg.in")
+ elseif(MINGW)
+ set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-mingw.cfg.in")
+ elseif(WIN32) # clang-cl
+ if (LIBCXX_ENABLE_SHARED)
+ set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared-clangcl.cfg.in")
+ else()
+ set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static-clangcl.cfg.in")
+ endif()
else()
- set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static.cfg.in")
+ if (LIBCXX_ENABLE_SHARED)
+ set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-shared.cfg.in")
+ else()
+ set(LIBCXX_DEFAULT_TEST_CONFIG "llvm-libc++-static.cfg.in")
+ endif()
endif()
endif()
set(LIBCXX_TEST_CONFIG "${LIBCXX_DEFAULT_TEST_CONFIG}" CACHE STRING
@@ -901,6 +924,10 @@ if (WIN32 AND LIBCXX_ENABLE_STATIC_ABI_LIBRARY)
add_definitions(-D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
endif()
+if (LIBCXX_FREESTANDING)
+ config_define(LIBCXX_FREESTANDING _LIBCPP_FREESTANDING)
+endif()
+
# Setup all common build flags =================================================
function(cxx_add_common_build_flags target)
cxx_add_basic_build_flags(${target})
@@ -920,9 +947,11 @@ add_custom_target(cxx-test-depends
COMMENT "Build dependencies required to run the libc++ test suite.")
add_subdirectory(include)
+if (NOT LIBCXX_FREESTANDING)
add_subdirectory(src)
add_subdirectory(utils)
add_subdirectory(modules)
+endif()
if (LIBCXX_INCLUDE_TESTS)
add_subdirectory(test)
diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 0a936db78e5fd..bea314fc5473e 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -832,6 +832,7 @@ _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
template <class _Comp, class _RandomAccessIterator>
void __sort(_RandomAccessIterator, _RandomAccessIterator, _Comp);
+#if _LIBCPP_FREESTANDING == 0
extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
#if _LIBCPP_HAS_WIDE_CHARACTERS
extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less<wchar_t>&, wchar_t*>(wchar_t*, wchar_t*, __less<wchar_t>&);
@@ -857,6 +858,8 @@ extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less<float>&, float*>(fl
extern template _LIBCPP_EXPORTED_FROM_ABI void __sort<__less<double>&, double*>(double*, double*, __less<double>&);
extern template _LIBCPP_EXPORTED_FROM_ABI void
__sort<__less<long double>&, long double*>(long double*, long double*, __less<long double>&);
+#endif
+
_LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 3f271ff504767..219014b8bc01a 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -37,6 +37,10 @@
// Given a LLVM release LLVM XX.YY.ZZ (e.g. LLVM 17.0.1 == 17.00.01), _LIBCPP_VERSION is
// defined to XXYYZZ.
# define _LIBCPP_VERSION 230000
+# if __STDC_HOSTED__ == 0
+# undef _LIBCPP_FREESTANDING
+# define _LIBCPP_FREESTANDING 1
+# endif
# if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_NO_VCRUNTIME)
# define _LIBCPP_ABI_VCRUNTIME
@@ -111,8 +115,13 @@
# define _LIBCPP_ALIGNOF(...) alignof(__VA_ARGS__)
# define _ALIGNAS_TYPE(x) alignas(x)
# define _ALIGNAS(x) alignas(x)
-# define _NOEXCEPT noexcept
-# define _NOEXCEPT_(...) noexcept(__VA_ARGS__)
+# ifdef __cplusplus
+# define _NOEXCEPT noexcept
+# define _NOEXCEPT_(...) noexcept(__VA_ARGS__)
+# else
+# define _NOEXCEPT
+# define _NOEXCEPT_(...)
+# endif
# define _LIBCPP_CONSTEXPR constexpr
# else
diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in
index e6e33a2eeb2a9..4470ce4ca3400 100644
--- a/libcxx/include/__config_site.in
+++ b/libcxx/include/__config_site.in
@@ -32,6 +32,9 @@
#cmakedefine01 _LIBCPP_HAS_TIME_ZONE_DATABASE
#cmakedefine01 _LIBCPP_INSTRUMENTED_WITH_ASAN
+// Freestanding
+#cmakedefine01 _LIBCPP_FREESTANDING
+
// PSTL backends
#cmakedefine _LIBCPP_PSTL_BACKEND_SERIAL
#cmakedefine _LIBCPP_PSTL_BACKEND_STD_THREAD
diff --git a/libcxx/include/__mbstate_t.h b/libcxx/include/__mbstate_t.h
index 1ce5f0cd6da1d..dce7ad7ca9196 100644
--- a/libcxx/include/__mbstate_t.h
+++ b/libcxx/include/__mbstate_t.h
@@ -51,6 +51,16 @@
# include_next <wchar.h> // use the C standard provider of mbstate_t if present
#elif __has_include_next(<uchar.h>)
# include_next <uchar.h> // Try <uchar.h> in absence of <wchar.h> for mbstate_t
+#elif _LIBCPP_FREESTANDING != 0
+# ifdef __cplusplus
+extern "C" {
+# endif
+typedef struct {
+ int __fill[6];
+} mbstate_t;
+# ifdef __cplusplus
+}
+# endif
#else
# error "We don't know how to get the definition of mbstate_t on your platform."
#endif
diff --git a/libcxx/include/ctime b/libcxx/include/ctime
index 1e845a8de0930..3fb2c7d4a67fb 100644
--- a/libcxx/include/ctime
+++ b/libcxx/include/ctime
@@ -57,6 +57,10 @@ int timespec_get( struct timespec *ts, int base); // C++17
# ifdef _LIBCPP_TIME_H
# error "If libc++ starts defining <time.h>, the __has_include check should move to libc++'s <time.h>"
# endif
+# else
+extern "C" {
+typedef __UINT_LEAST64_TYPE__ time_t;
+}
# endif
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/math.h b/libcxx/include/math.h
index 1db61538e995f..190daf23285fa 100644
--- a/libcxx/include/math.h
+++ b/libcxx/include/math.h
@@ -302,6 +302,43 @@ long double truncl(long double x);
# if __has_include_next(<math.h>)
# include_next <math.h>
+# else
+
+# ifndef NAN
+# define NAN __builtin_nanf("")
+# endif
+
+# ifndef INFINITY
+# define INFINITY __builtin_inff()
+# endif
+
+# ifndef FP_NAN
+# define FP_NAN 0
+# endif
+
+# ifndef FP_INFINITE
+# define FP_INFINITE 1
+# endif
+
+# ifndef FP_ZERO
+# define FP_ZERO 2
+# endif
+
+# ifndef FP_SUBNORMAL
+# define FP_SUBNORMAL 3
+# endif
+
+# ifndef FP_NORMAL
+# define FP_NORMAL 4
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif
+float atan2f(float, float) _NOEXCEPT;
+long double atan2l(long double, long double) _NOEXCEPT;
+# ifdef __cplusplus
+}
+# endif
# endif
# ifdef __cplusplus
diff --git a/libcxx/include/stdio.h b/libcxx/include/stdio.h
index 4ce98d178ed2f..b1985625d5b09 100644
--- a/libcxx/include/stdio.h
+++ b/libcxx/include/stdio.h
@@ -118,4 +118,18 @@ void perror(const char* s);
# undef getchar
# endif // __cplusplus
+
+# if !__has_include_next(<stdio.h>)
+# ifndef EOF
+# define EOF (-1)
+# endif
+# ifdef __cplusplus
+extern "C" {
+# endif // __cplusplus
+int remove(const char*) _NOEXCEPT;
+# ifdef __cplusplus
+}
+# endif // __cplusplus
+# endif
+
#endif // _LIBCPP_STDIO_H
diff --git a/libcxx/include/stdlib.h b/libcxx/include/stdlib.h
index 8dfdfa416f088..43f1d24320fcb 100644
--- a/libcxx/include/stdlib.h
+++ b/libcxx/include/stdlib.h
@@ -92,6 +92,25 @@ void *aligned_alloc(size_t alignment, size_t size); // C11
# if !defined(_LIBCPP_STDLIB_H)
# define _LIBCPP_STDLIB_H
+# if !__has_include_next(<stdlib.h>)
+# ifdef __cplusplus
+extern "C" {
+# endif
+struct ldiv_t {
+ long quot;
+ long rem;
+};
+struct lldiv_t {
+ long long quot;
+ long long rem;
+};
+ldiv_t ldiv(long x, long y) _NOEXCEPT;
+lldiv_t lldiv(long long x, long long y) _NOEXCEPT;
+# ifdef __cplusplus
+}
+# endif
+# endif
+
# ifdef __cplusplus
extern "C++" {
// abs
diff --git a/libcxx/include/string.h b/libcxx/include/string.h
index 2ffcb913010b6..fd70bcf621e1b 100644
--- a/libcxx/include/string.h
+++ b/libcxx/include/string.h
@@ -60,11 +60,48 @@ size_t strlen(const char* s);
# pragma GCC system_header
# endif
+# include <stddef.h>
# if __has_include_next(<string.h>)
# include_next <string.h>
-# endif
+# else
+# ifdef __cplusplus
+extern "C" {
+# endif
-# include <stddef.h>
+/*
+We offer declarations for these C functions,
+leaving the implementations to be handled by users.
+*/
+
+void* memcpy(void* __restrict, const void* __restrict, size_t) _NOEXCEPT;
+void* memmove(void*, const void*, size_t) _NOEXCEPT;
+char* strcpy(char* __restrict, const char* __restrict) _NOEXCEPT;
+char* strncpy(char* __restrict, const char* __restrict, size_t) _NOEXCEPT;
+char* strcat(char* __restrict, const char* __restrict) _NOEXCEPT;
+char* strncat(char* __restrict, const char* __restrict, size_t) _NOEXCEPT;
+int memcmp(const void*, const void*, size_t) _NOEXCEPT;
+int strcmp(const char*, const char*) _NOEXCEPT;
+int strncmp(const char*, const char*, size_t) _NOEXCEPT;
+const void* memchr(const void*, int, size_t) _NOEXCEPT;
+const char* strchr(const char*, int) _NOEXCEPT;
+size_t strcspn(const char*, const char*) _NOEXCEPT;
+const char* strpbrk(const char*, const char*) _NOEXCEPT;
+const char* strrchr(const char*, int) _NOEXCEPT;
+size_t strspn(const char*, const char*) _NOEXCEPT;
+const char* strstr(const char*, const char*) _NOEXCEPT;
+char* strtok(char* __restrict, const char* __restrict) _NOEXCEPT;
+void* memset(void*, int, size_t) _NOEXCEPT;
+size_t strlen(const char*) _NOEXCEPT;
+size_t strnlen(const char*, size_t) _NOEXCEPT;
+void* memset_explicit(void*, int, size_t) _NOEXCEPT;
+int strcoll(const char*, const char*) _NOEXCEPT;
+size_t strxfrm(char* __restrict, const char* __restrict, size_t) _NOEXCEPT;
+char* strerror(int) _NOEXCEPT;
+
+# ifdef __cplusplus
+}
+# endif
+# endif
// MSVCRT, GNU libc and its derivates may already have the correct prototype in
// <string.h>. This macro can be defined by users if their C library provides
diff --git a/libcxx/test/libcxx/libcpp_freestanding.sh.cpp b/libcxx/test/libcxx/libcpp_freestanding.sh.cpp
new file mode 100644
index 0000000000000..2dc5d90b3b4ec
--- /dev/null
+++ b/libcxx/test/libcxx/libcpp_freestanding.sh.cpp
@@ -0,0 +1,111 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// Test that _LIBCPP_FREESTANDING is not defined when -ffreestanding is not passed
+// to the compiler but defined when -ffreestanding is passed to the compiler.
+
+// RUN: %{cxx} %{flags} %{compile_flags} -fsyntax-only -ffreestanding %s
+
+#include <__config>
+
+#if defined(__has_feature)
+# if __has_feature(modules)
+# define _LIBCPP_FREESTANDING_NO_TEST_MODULES
+# endif
+#elif defined(__cpp_modules)
+# define _LIBCPP_FREESTANDING_NO_TEST_MODULES
+#endif
+
+#if _LIBCPP_FREESTANDING && !defined(_LIBCPP_FREESTANDING_NO_TEST_MODULES)
+# include <cstddef>
+# include <limits>
+# include <climits>
+# include <cfloat>
+# include <version>
+# include <cstdint>
+# include <cstdlib>
+# include <new>
+# include <typeinfo>
+# if __has_include(<source_location>)
+# include <source_location>
+# endif
+# include <exception>
+# include <initializer_list>
+# include <compare>
+# include <coroutine>
+# include <cstdarg>
+# include <concepts>
+# include <type_traits>
+# include <bit>
+# include <atomic>
+# include <utility>
+# include <tuple>
+# include <memory>
+# include <functional>
+# include <ratio>
+# include <iterator>
+# include <ranges>
+# include <typeinfo>
+# include <execution>
+
+/*
+We tested these headers are for preventing build issues
+*/
+# include <iosfwd>
+# include <cstdio>
+# include <cerrno>
+# include <cstring>
+# include <cmath>
+# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+# include <cwchar>
+# endif
+# include <array>
+# include <span>
+# include <algorithm>
+# include <bitset>
+# include <variant>
+# include <optional>
+# include <numbers>
+# include <scoped_allocator>
+# include <typeindex>
+# include <string_view>
+# include <numeric>
+# include <complex>
+# include <chrono>
+# include <charconv>
+# include <expected>
+# include <random>
+# include <any>
+
+/*
++ * libc++ Containers Extensions
++ */
+# include <vector>
+# include <deque>
+# include <string>
+# include <stack>
+# include <queue>
+# include <list>
+# include <forward_list>
+# include <map>
+# include <set>
+# include <unordered_set>
+# include <unordered_map>
+# if __has_include(<mdspan>)
+# include <mdspan>
+# endif
+# include <valarray>
+
+# if _LIBCPP_STD_VER < 20
+# include <ciso646>
+# if __has_include(<cstdalign>)
+# include <cstdalign>
+# endif
+# include <cstdbool>
+# endif
+#endif
More information about the libcxx-commits
mailing list