Statically linking against libc++

While considering statically linking against libc++ (and
other runtime libraries from LLVM), I rebuilt LLVM 4.0
with -DBUILD_SHARED_LIBS=OFF.

There are still some .so's in llvm/lib, and only one
of them seems to exist exclusively as a DSO (libLTO).
There's also livLLVMLTO.a, but I doubt LTO is used
after linking a binary so this just looks odd to an
uninformed LLVM outside and not insufficient or anything.

My question is two-fold:

1. when building a C++ program with clang, maybe making use
of clang-musl to avoid glibc as well, how do I statically
link libc++ and get a C++ program that runs on any Linux
kernel, allowing easy distribution of a single binary?

2. should the following .so's be built with -DBUILD_SHARED_LIBS=OFF?

$ ls *.so
BugpointPasses.so
LLVMHello.so
LLVMPolly.so
LLVMgold.so
libLTO.so
libc++.so
libc++abi.so
libclang.so
libgomp.so
libiomp5.so
liblldb.so
libomp.so

While considering statically linking against libc++ (and
other runtime libraries from LLVM), I rebuilt LLVM 4.0
with -DBUILD_SHARED_LIBS=OFF.

There are still some .so's in llvm/lib, and only one
of them seems to exist exclusively as a DSO (libLTO).
There's also livLLVMLTO.a, but I doubt LTO is used
after linking a binary so this just looks odd to an
uninformed LLVM outside and not insufficient or anything.

My question is two-fold:

1. when building a C++ program with clang, maybe making use
of clang-musl to avoid glibc as well, how do I statically
link libc++ and get a C++ program that runs on any Linux
kernel, allowing easy distribution of a single binary?

If you want to link just libc++ statically, you can use:

  -Wl,-Bstatic -lc++ -Wl,-Bdynamic

in your link flags. Otherwise, just use -static.

2. should the following .so's be built with -DBUILD_SHARED_LIBS=OFF?

$ ls *.so
BugpointPasses.so
LLVMHello.so
LLVMPolly.so
LLVMgold.so
libLTO.so
libc++.so
libc++abi.so
libclang.so
libgomp.so
libiomp5.so
liblldb.so
libomp.so

Indeed, those should probably be cleaned up. On the other hand, some
libraries do not really make sense as static ones, so those could be
completely disabled.

-Dimitry

So obvious and easy. I'm so used (stockholm syndrome?)
to not being able to link Linux (aka glibc+libstd++)
statically that I didn't expect this.

I'm surprised this clang++ foo.cc -static -o foo
produced a foo that doesn't required glibc. I would
have thought that this would have failed to link
without involving musl, which I don't know how to
include since musl outside a musl chroot/distro
only has musl-clang for building C code without
the C++ frontend, where one probably needs to
explicitly add -lc++.

foo.cc wasn't tiny either, it includes fcntl.h,
sys/*.h, etc., in addition to the C++ standard
lib headers.

I'm on Arch Linux where there isn't any .a like
you would get on Gentoo or Debian's -dev packages,
so I wonder how this linked statically without me
telling it to use musl libc for the C symbols.
Do you know why?

While considering statically linking against libc++ (and
other runtime libraries from LLVM), I rebuilt LLVM 4.0
with -DBUILD_SHARED_LIBS=OFF.

What you build with clang and how clang is built aren’t related at all.
You can build LLVM as a set of dynamic libraries, and still use clang to generate a statically linked binary.

There are still some .so's in llvm/lib, and only one
of them seems to exist exclusively as a DSO (libLTO).
There's also livLLVMLTO.a, but I doubt LTO is used
after linking a binary so this just looks odd to an
uninformed LLVM outside and not insufficient or anything.

My question is two-fold:

1. when building a C++ program with clang, maybe making use
of clang-musl to avoid glibc as well, how do I statically
link libc++ and get a C++ program that runs on any Linux
kernel, allowing easy distribution of a single binary?

2. should the following .so's be built with -DBUILD_SHARED_LIBS=OFF?

Yes, most of them are intended to stay .so.

Note that -DBUILD_SHARED_LIBS=OFF is not a special settings, this is the default.

Of course not and I can see how my message was ambiguous.

Since C++ code almost always needs a standard lib and
given past precedents on Linux with glibc/libgcc/libstdc++,
I asked myself if and how I can statically link libc++.
This is a little more important because libc++ - unlike
FreeBSD and macOS - is not necessarily on a system. Hence
my static linking question. Looking closer, Arch linux
has libc.a even though it doesn't install .a for packages
by default so glibc's C stdlib must have been used in
that clang++ -static foo.cc invocation.

This is good but since glibc may not link statically in
all scenarios, do you know how I could run clang++ on a glibc
Linux while delegating C stdlib to musl-libc? I mean,
-nostdlib or -nodefaultlib could be used but then stuff
gets hairy or too explicit quickly. I'm hoping -static
could be made to use libc++.a, musl libc.a and maybe
libunwind compiler-rt etc.

Is there a so=NEVER setting?

-DBUILD_SHARED_LIBS=OFF should be exactly that, but as I think someone
else indicated there's a bit of work for it to actually be what it
advertises to be.

This could get gray when you consider that you really need to decide -
did you mean compiler internal libs or runtime stuff. libomp.so vs
libLLVM.so is two entirely different use cases.

Did you want to disable ever being able to use a shared lib or just
build a static version of the compiler so that it's portable.

Shameless self promotion, but this does the latter while preserving the former..
Nice clean wrapper around everything that makes a compiler that is
portable and has all the pieces you need bundled together..
https://github.com/pathscale/clang-suite

# To avoid confusion - that link depends only on open source stuff

-DBUILD_SHARED_LIBS=OFF should be exactly that, but as I think
someone else indicated there's a bit of work for it to actually be
what it advertises to be.

Mehdi wrote it's correct for all of the listed dynlibs to be
installed.

This could get gray when you consider that you really need to decide
- did you mean compiler internal libs or runtime stuff. libomp.so vs
libLLVM.so is two entirely different use cases.

Yep, I'm talking about zero LLVM libs needed at runtime after linking,
unlike say libstdc++ and libgcc needed in your typical Linux
executable.

Did you want to disable ever being able to use a shared lib or just
build a static version of the compiler so that it's portable.

Building a static compiler wasn't on my agenda, but since it takes a
long time to build it all, I would love such a target for sharing it
between all Linux distros.

Shameless self promotion, but this does the latter while preserving
the former.. Nice clean wrapper around everything that makes a
compiler that is portable and has all the pieces you need bundled
together.. https://github.com/pathscale/clang-suite

Do you mind going into the differences of me running
cmake _many_opts_ && ninja install?

-DBUILD_SHARED_LIBS=OFF should be exactly that, but as I think
someone else indicated there’s a bit of work for it to actually be
what it advertises to be.

Mehdi wrote it’s correct for all of the listed dynlibs to be
installed.

I can be wrong as well :slight_smile:

But here that’s not my reading of the documentation: http://llvm.org/docs/CMake.html

**BUILD_SHARED_LIBS**:BOOL
Flag indicating if each LLVM component (e.g. Support) is built as a shared library (ON) or as a static library (OFF). Its default value is OFF. On Windows, shared libraries may be used when building with MinGW, including mingw-w64, but not when building with the Microsoft toolchain.

This applies to the individual LLVM component. I don’t think the shared lib you mentioned are part of this.

This could get gray when you consider that you really need to decide

  • did you mean compiler internal libs or runtime stuff. libomp.so vs
    libLLVM.so is two entirely different use cases.

Yep, I’m talking about zero LLVM libs needed at runtime after linking,
unlike say libstdc++ and libgcc needed in your typical Linux
executable.

When I build clang, I always get libc++.so and libc++.a ; I don’t think there is an option to have clang always link libc++ statically afterward though. I believe it requires to opt-in explicitly when you link with clang.

—Mehdi

I can be wrong as well :slight_smile:

But here that’s not my reading of the documentation:
Building LLVM with CMake — LLVM 18.0.0git documentation

BUILD_SHARED_LIBS:BOOL
Flag indicating if each LLVM component (e.g. Support) is built as a shared
library (ON) or as a static library (OFF). Its default value is OFF. On
Windows, shared libraries may be used when building with MinGW, including
mingw-w64, but not when building with the Microsoft toolchain.

This applies to the individual LLVM component. I don’t think the shared lib
you mentioned are part of this.

I set this in the cmake invocation for all of llvm from the root.
Do I need to do this differently for it to affect every project?

When I build clang, I always get libc++.so and libc++.a ; I don’t think
there is an option to have clang always link libc++ statically afterward
though. I believe it requires to opt-in explicitly when you link with clang.

Yeah you need -static globally in the CXX call which may not be
flexible enough, but you could argue that if one needs to link
libc++ statically they should run it where everything is used
is available for -static use.

No, what I meant is that there are components for which we don’t want to do anything else than generate a shared library. For example your list includes LLVMHello.so which is intended to showcase/test how passes can be dynamically loaded in LLVM.