Clang does not come with its own C standard library. Rather, it "supports a wide variety of C standard library implementations".

Unix-like systems including Mac OS ship with their own. Windows does not. On Windows the default arrangement requires Microsoft's Visual C libraries to be installed. It seems that it's also possible to use Clang on Windows with MinGW's libraries though.

Answer from hippietrail on Stack Overflow
🌐
MaskRay
maskray.me › blog › 2021-10-10-when-can-glibc-be-built-with-clang
When can glibc be built with Clang? | MaskRay
February 5, 2026 - Updated in 2026: glibc 2.43 added experimental support for building with Clang. In September 2021, I wrote "So, dear glibc, will you be happy with my sending Clang patches?" in Build glibc with LLD 1
Discussions

how to assign glibc version when compile clangd?
since I use centos7 and the glibc vesion is 2.17, and I could not update it to 2.18, so I'd like to compile a 2.18 one and try to compile clangd and dynamic link it, how could I do this? More on github.com
🌐 github.com
2
October 27, 2021
linux - How can I link to a specific glibc version? - Stack Overflow
Using zig cc as your compiler, it's possible to target a specific version of glibc. ... zig cc is based on top of clang, so it's a pretty close to a drop in replacement if you are using either clang or gcc. More on stackoverflow.com
🌐 stackoverflow.com
When can glibc be built with Clang?
It's nice to see that finally something is moving, especially now that Linux is also finally buildable with LLVM · Edit - also, lack of updates. POSIX added a new feature to a tool 5 years ago? Well, the built-in tool that came with your classic Unix probably still doesn't support it yet. More on news.ycombinator.com
🌐 news.ycombinator.com
28
100
October 16, 2021
[BUG] libstdc++ glibc version mismatch when executing clang-built code
Describe the bug ./output.s: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by ./output.s) results when trying to use std::stringstream with clang compil... More on github.com
🌐 github.com
6
December 18, 2019
🌐
GitHub
github.com › intel › tbb › issues › 146
Glibc version detection is broken for Clang · Issue #146 · uxlfoundation/oneTBB
May 20, 2019 - TBB tries to detect the glibc version by looking at __GNUC__, __GNUC_MINOR__ etc. which is the version of GCC. However Clang always seems to set this to 4. The code notes this. // note that when ICC or Clang is in use, __TBB_GCC_VERSION ...
Author   uxlfoundation
🌐
Google Groups
groups.google.com › g › llvm-dev › c › 3p30PgoQZWg › m › maOm_vSKCwAJ
[llvm-dev] Targeting old glibc
On 2020-10-28, Alexandre Bique via llvm-dev wrote: >Hi, > >I wonder what is the right way to target an old glibc? > >I have a machine which is up to date (glibc 2.32 and clang+lld 10.0.1).
🌐
Google Groups
groups.google.com › g › llvm-dev › c › 9gOqjp9wzrg › m › _gyhxpiKDQAJ
[llvm-dev] How to compile glibc with clang/llvm?
LLVM support for GNU source code ... of glibc patches that make this work, including additional configure options mentioned below. The minimum version of clang is 6.0.0....
🌐
Collabora
collabora.com › news-and-blog › blog › 2021 › 09 › 30 › a-tale-of-two-toolchains-and-glibc
A tale of two toolchains and glibc
September 30, 2021 - There are some "clangify" branches in upstream glibc (e.g. shebs/clangify), but they are based on 2.26-2.29 versions and development seems to have stalled in the last few years.
🌐
GitHub
github.com › clangd › clangd › issues › 910
how to assign glibc version when compile clangd? · Issue #910 · clangd/clangd
October 27, 2021 - since I use centos7 and the glibc vesion is 2.17, and I could not update it to 2.18, so I'd like to compile a 2.18 one and try to compile clangd and dynamic link it, how could I do this?
Author   clangd
🌐
Linaro
linaro.org › blog › building-glibc-with-llvm-the-how-and-why
Building GLIBC with LLVM: The How and Why | Blog | Linaro
There is still some work to do, especially because glibc still requires a linker script to support some internal security hardening, which is only supported by recent LLD versions. Another front was to remove the usage of unsupported C extensions by Clang, such as nested functions, and to adapt the external header to be fully compatible with Clang.
Find elsewhere
Top answer
1 of 7
110

You are correct in that glibc uses symbol versioning. If you are curious, the symbol versioning implementation introduced in glibc 2.1 is described here and is an extension of Sun's symbol versioning scheme described here.

One option is to statically link your binary. This is probably the easiest option.

You could also build your binary in a chroot build environment, or using a glibc-new => glibc-old cross-compiler.

According to the http://www.trevorpounds.com blog post Linking to Older Versioned Symbols (glibc), it is possible to to force any symbol to be linked against an older one so long as it is valid by using the same .symver pseudo-op that is used for defining versioned symbols in the first place. The following example is excerpted from the blog post.

The following example makes use of glibc’s realpath, but makes sure it is linked against an older 2.2.5 version.

#include <limits.h>
#include <stdlib.h>
#include <stdio.h>

__asm__(".symver realpath,realpath@GLIBC_2.2.5");
int main()
{
    const char* unresolved = "/lib64";
    char resolved[PATH_MAX+1];

    if(!realpath(unresolved, resolved))
        { return 1; }

    printf("%s\n", resolved);

    return 0;
}
2 of 7
44

Setup 1: compile your own glibc without dedicated GCC and use it

Since it seems impossible to do just with symbol versioning hacks, let's go one step further and compile glibc ourselves.

This setup might work and is quick as it does not recompile the whole GCC toolchain, just glibc.

But it is not reliable as it uses host C runtime objects such as crt1.o, crti.o, and crtn.o provided by glibc. This is mentioned at: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Those objects do early setup that glibc relies on, so I wouldn't be surprised if things crashed in wonderful and awesomely subtle ways.

For a more reliable setup, see Setup 2 below.

Build glibc and install locally:

export glibc_install="$(pwd)/glibc/build/install"

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28
mkdir build
cd build
../configure --prefix "$glibc_install"
make -j `nproc`
make install -j `nproc`

Setup 1: verify the build

test_glibc.c

#define _GNU_SOURCE
#include <assert.h>
#include <gnu/libc-version.h>
#include <stdatomic.h>
#include <stdio.h>
#include <threads.h>

atomic_int acnt;
int cnt;

int f(void* thr_data) {
    for(int n = 0; n < 1000; ++n) {
        ++cnt;
        ++acnt;
    }
    return 0;
}

int main(int argc, char **argv) {
    /* Basic library version check. */
    printf("gnu_get_libc_version() = %s\n", gnu_get_libc_version());

    /* Exercise thrd_create from -pthread,
     * which is not present in glibc 2.27 in Ubuntu 18.04.
     * https://stackoverflow.com/questions/56810/how-do-i-start-threads-in-plain-c/52453291#52453291 */
    thrd_t thr[10];
    for(int n = 0; n < 10; ++n)
        thrd_create(&thr[n], f, NULL);
    for(int n = 0; n < 10; ++n)
        thrd_join(thr[n], NULL);
    printf("The atomic counter is %u\n", acnt);
    printf("The non-atomic counter is %u\n", cnt);
}

Compile and run with test_glibc.sh:

#!/usr/bin/env bash
set -eux
gcc \
  -L "${glibc_install}/lib" \
  -I "${glibc_install}/include" \
  -Wl,--rpath="${glibc_install}/lib" \
  -Wl,--dynamic-linker="${glibc_install}/lib/ld-linux-x86-64.so.2" \
  -std=c11 \
  -o test_glibc.out \
  -v \
  test_glibc.c \
  -pthread \
;
ldd ./test_glibc.out
./test_glibc.out

The program outputs the expected:

gnu_get_libc_version() = 2.28
The atomic counter is 10000
The non-atomic counter is 8674

Command adapted from https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location but --sysroot made it fail with:

cannot find /home/ciro/glibc/build/install/lib/libc.so.6 inside /home/ciro/glibc/build/install

so I removed it.

ldd output confirms that the ldd and libraries that we've just built are actually being used as expected:

+ ldd test_glibc.out
        linux-vdso.so.1 (0x00007ffe4bfd3000)
        libpthread.so.0 => /home/ciro/glibc/build/install/lib/libpthread.so.0 (0x00007fc12ed92000)
        libc.so.6 => /home/ciro/glibc/build/install/lib/libc.so.6 (0x00007fc12e9dc000)
        /home/ciro/glibc/build/install/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fc12f1b3000)

The gcc compilation debug output shows that my host runtime objects were used, which is bad as mentioned previously, but I don't know how to work around it, e.g. it contains:

COLLECT_GCC_OPTIONS=/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crt1.o

Setup 1: modify glibc

Now let's modify glibc with:

diff --git a/nptl/thrd_create.c b/nptl/thrd_create.c
index 113ba0d93e..b00f088abb 100644
--- a/nptl/thrd_create.c
+++ b/nptl/thrd_create.c
@@ -16,11 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */

+#include <stdio.h>
+
 #include "thrd_priv.h"

 int
 thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
 {
+  puts("hacked");
   _Static_assert (sizeof (thr) == sizeof (pthread_t),
                   "sizeof (thr) != sizeof (pthread_t)");

Then recompile and re-install glibc, and recompile and re-run our program:

cd glibc/build
make -j `nproc`
make -j `nproc` install
./test_glibc.sh

and we see hacked printed a few times as expected.

This further confirms that we actually used the glibc that we compiled and not the host one.

Tested on Ubuntu 18.04.

Setup 2: crosstool-NG pristine setup

This is an alternative to setup 1, and it is the most correct setup I've achieved far: everything is correct as far as I can observe, including the C runtime objects such as crt1.o, crti.o, and crtn.o.

In this setup, we will compile a full dedicated GCC toolchain that uses the glibc that we want.

The only downside to this method is that the build will take longer. But I wouldn't risk a production setup with anything less.

crosstool-NG is a set of scripts that downloads and compiles everything from source for us, including GCC, glibc and binutils.

Yes the GCC build system is so bad that we need a separate project for that.

This setup is only not perfect because crosstool-NG does not support building the executables without extra -Wl flags, which feels weird since we've built GCC itself. But everything seems to work, so this is only an inconvenience.

Get crosstool-NG and configure it:

git clone https://github.com/crosstool-ng/crosstool-ng
cd crosstool-ng
git checkout a6580b8e8b55345a5a342b5bd96e42c83e640ac5
export CT_PREFIX="$(pwd)/.build/install"
export PATH="/usr/lib/ccache:${PATH}"
./bootstrap
./configure --enable-local
make -j `nproc`
./ct-ng x86_64-unknown-linux-gnu
./ct-ng menuconfig

The only mandatory option that I can see, is making it match your host kernel version to use the correct kernel headers. Find your host kernel version with:

uname -a

which shows me:

4.15.0-34-generic

so in menuconfig I do:

  • Operating System
    • Version of linux

so I select:

4.14.71

which is the first equal or older version. It has to be older since the kernel is backwards compatible.

Now you can build with:

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

and now wait for about thirty minutes to two hours for compilation.

Setup 2: optional configurations

The .config that we generated with ./ct-ng x86_64-unknown-linux-gnu has:

CT_GLIBC_V_2_27=y

To change that, in menuconfig do:

  • C-library
  • Version of glibc

save the .config, and continue with the build.

Or, if you want to use your own glibc source, e.g. to use glibc from the latest git, proceed like this:

  • Paths and misc options
    • Try features marked as EXPERIMENTAL: set to true
  • C-library
    • Source of glibc
      • Custom location: say yes
      • Custom location
        • Custom source location: point to a directory containing your glibc source

where glibc was cloned as:

git clone git://sourceware.org/git/glibc.git
cd glibc
git checkout glibc-2.28

Setup 2: test it out

Once you have built he toolchain that you want, test it out with:

#!/usr/bin/env bash
set -eux
install_dir="${CT_PREFIX}/x86_64-unknown-linux-gnu"
PATH="${PATH}:${install_dir}/bin" \
  x86_64-unknown-linux-gnu-gcc \
  -Wl,--dynamic-linker="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib/ld-linux-x86-64.so.2" \
  -Wl,--rpath="${install_dir}/x86_64-unknown-linux-gnu/sysroot/lib" \
  -v \
  -o test_glibc.out \
  test_glibc.c \
  -pthread \
;
ldd test_glibc.out
./test_glibc.out

Everything seems to work as in Setup 1, except that now the correct runtime objects were used:

COLLECT_GCC_OPTIONS=/home/ciro/crosstool-ng/.build/install/x86_64-unknown-linux-gnu/bin/../x86_64-unknown-linux-gnu/sysroot/usr/lib/../lib64/crt1.o

Setup 2: failed efficient glibc recompilation attempt

It does not seem possible with crosstool-NG, as explained below.

If you just re-build;

env -u LD_LIBRARY_PATH time ./ct-ng build CT_JOBS=`nproc`

then your changes to the custom glibc source location are taken into account, but it builds everything from scratch, making it unusable for iterative development.

If we do:

./ct-ng list-steps

it gives a nice overview of the build steps:

Available build steps, in order:
  - companion_tools_for_build
  - companion_libs_for_build
  - binutils_for_build
  - companion_tools_for_host
  - companion_libs_for_host
  - binutils_for_host
  - cc_core_pass_1
  - kernel_headers
  - libc_start_files
  - cc_core_pass_2
  - libc
  - cc_for_build
  - cc_for_host
  - libc_post_cc
  - companion_libs_for_target
  - binutils_for_target
  - debug
  - test_suite
  - finish
Use "<step>" as action to execute only that step.
Use "+<step>" as action to execute up to that step.
Use "<step>+" as action to execute from that step onward.

therefore, we see that there are glibc steps intertwined with several GCC steps, most notably libc_start_files comes before cc_core_pass_2, which is likely the most expensive step together with cc_core_pass_1.

In order to build just one step, you must first set the "Save intermediate steps" in .config option for the intial build:

  • Paths and misc options
    • Debug crosstool-NG
      • Save intermediate steps

and then you can try:

env -u LD_LIBRARY_PATH time ./ct-ng libc+ -j`nproc`

but unfortunately, the + required as mentioned at: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536

Note however that restarting at an intermediate step resets the installation directory to the state it had during that step. I.e., you will have a rebuilt libc - but no final compiler built with this libc (and hence, no compiler libraries like libstdc++ either).

and basically still makes the rebuild too slow to be feasible for development, and I don't see how to overcome this without patching crosstool-NG.

Furthermore, starting from the libc step didn't seem to copy over the source again from Custom source location, further making this method unusable.

Bonus: stdlibc++

A bonus if you're also interested in the C++ standard library: How to edit and re-build the GCC libstdc++ C++ standard library source?

🌐
LLVM
lists.llvm.org › pipermail › llvm-dev › 2018-December › 128719.html
[llvm-dev] How to compile glibc with clang/llvm? - Mailing Lists
June 5, 2019 - LLVM support for GNU source code ... of glibc patches that make this work, including additional configure options mentioned below. The minimum version of clang is 6.0.0....
🌐
Hacker News
news.ycombinator.com › item
When can glibc be built with Clang? | Hacker News
October 16, 2021 - It's nice to see that finally something is moving, especially now that Linux is also finally buildable with LLVM · Edit - also, lack of updates. POSIX added a new feature to a tool 5 years ago? Well, the built-in tool that came with your classic Unix probably still doesn't support it yet.
🌐
GitHub
github.com › mattgodbolt › compiler-explorer › issues › 1740
[BUG] libstdc++ glibc version mismatch when executing clang-built code · Issue #1740 · compiler-explorer/compiler-explorer
December 18, 2019 - Describe the bug ./output.s: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.26' not found (required by ./output.s) results when trying to use std::stringstream with clang compiler To Reproduce Attempt to compile and link ...
Author   compiler-explorer
🌐
Reddit
reddit.com › r/linux › when can glibc be built with clang?
r/linux on Reddit: When can glibc be built with Clang?
October 11, 2021 - Awesome to see a positive response from the glibc people. It’s very interesting reading about all the gcc-isms that have to be adapted for building stuff with clang.
🌐
MaskRay
maskray.me › blog › 2022-05-29-glibc
Everything I know about glibc | MaskRay
January 20, 2026 - When the condition is true, the version range [introduced, obsoleted) overlaps the version range of the port, and therefore _OTHER_SHLIB_COMPAT expands to true. compat_symbol (libpthread, __old_sem_init, sem_init, GLIBC_2_0); sets __old_sem_init to "sem_init" "@" "VERSION_libpthread_GLIBC_2_1" which expands to "sem_init" "@" "GLIBC_2.2.5".
🌐
Hacker News
news.ycombinator.com › item
Show HN: A 166 KB file for cross compiling glibc for any version, any target | Hacker News
December 16, 2021 - In master branch of Zig right now (before https://github.com/ziglang/zig/pull/10330 is merged), status quo: · With this new glibc-abi-tool:
🌐
LLVM Discussion Forums
discourse.llvm.org › clang frontend
minimum glibc (on Linux) needed to work with clang in -c99 mode? - Clang Frontend - LLVM Discussion Forums
December 15, 2010 - A Linux user mentioned to me an ... of the 'inline' keyword is different, likely to deal with compatibility issues between c89 and c99)....
🌐
GitHub
github.com › muttleyxd › clang-tools-static-binaries › issues › 7
Support clang-format and clangd for GLIBC 2.12 · Issue #7 · muttleyxd/clang-tools-static-binaries
March 11, 2021 - The compiler installed on it is GCC 4.4.6. On that machine clang is not installed, nor LLVM. $ rpm -q glibc glibc-2.12-1.80.el6.x86_64 glibc-2.12-1.80.el6.i686 $ cat /proc/version Linux version 2.6.32-279.el6.x86_64 (mockbuild@x86-008.build...
Author   muttleyxd
🌐
GitHub
github.com › clangd › vscode-clangd › issues › 16
GLIBCs not found on host · Issue #16 · clangd/vscode-clangd
November 27, 2020 - /home/reiss/.vscode-server/data/User/globalStorage/llvm-vs-code-extensions.vscode-clangd/install/10rc3/clangd_10rc3/bin/clangd: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by /home/reiss/.vscode-server/data/User/globalStorage/llvm-vs-code-extensions.vscode-clangd/install/10rc3/clangd_10rc3/bin/clangd) /home/reiss/.vscode-server/data/User/globalStorage/llvm-vs-code-extensions.vscode-clangd/install/10rc3/clangd_10rc3/bin/clangd: /lib64/libc.so.6: version `GLIBC_2.18' not found (required by /home/reiss/.vscode-server/data/User/globalStorage/llvm-vs-code-extensions.vscode-clangd/install/10rc3/clangd_10rc3/bin/clangd) Would it make sense to do a check on existing GLIBC on the host before installing the new version?
Author   clangd
🌐
Reddit
reddit.com › r/cpp_questions › some questions about libc, libc++, libstdc++
r/cpp_questions on Reddit: Some questions about libc, libc++, libstdc++
September 18, 2020 -

Can someone elaborate on what are libc, libc++, libstdc++

  1. What the difference between libc++ and libstdc++? Why can't we just use one of them for all times?

  2. How to determine which versions of these libs support specific standard version? For example which version of c++ standard does libstdc++-4.6 support?

  3. Can i just "copy-paste" these libs into target OS to run my project if that OS lacks newer versions of these ones available in repositories?

    1. Can i just "copy-paste" all dependent `.so` files into target OS? What should i consider when "copy-pasting" libraries from my development workstation to user's one?

Top answer
1 of 2
4
What the difference between libc++ and libstdc++? libc++ is part of clang project and libstdc++ is part of GCC project. They are compatible for C++17 and older versions, but C++20 implementation is not ready, so they have differences in implemented features, we'll have to wait until they are done. How to determine which versions of these libs support specific standard version? For example which version of c++ standard does libstdc++-4.6 support? In their documentation, for example you can check what version GCC libstdc++ supports here: https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html Copy pasting libs may or may not work, depending on many things. It's best to just install standard library using package manager of your operating system.
2 of 2
1
(mine) 0. What are libc++ and libstdc++ They are compiler-specific implementations of the C++ standard library. libc++ is bundled with Clang and libstdc++ with GCC. On many unix platforms Clang works with libstdc++ by default for better ABI compatibility. 1. What the difference between libc++ and libstdc++? Why can't we just use one of them for all times? They are different implementations of the same library. Your code should not really care which one it is using, unless you also want to use compiler-specific extensions. 2. How to determine which versions of these libs support specific standard version? Not sure. Look into GCC and Clang documentation. 3. Can i just "copy-paste" these libs into target OS to run my project if that OS lacks newer versions of these ones available in repositories? Can i just "copy-paste" all dependent .so files into target OS? What should i consider when "copy-pasting" libraries from my development workstation to user's one? Generally, yes but you need to take care of few things: Your executable must be able to locate the library object. This might require to edit LD_LIBRARY_PATH or inject rpath information into the executable. Licensing concerns (???) - IIRC even majority of commercial uses are fine though It's possible to use static version of the standard library - then it's inside the executable. Whatever linking you are using, the target OS must support all dependencies of the standard library implementation. This will usually be dependent on supported syscalls which are the border between user-space and kerner-space.