I’m working on a macOS app, and I use the git HEAD of Clang and libc++ so I can play with C++ modules and other new stuff. I’ve built up some CMake files and they appear to work, but it also looks like it loads multiple versions of libc++ – the new one I compiled, and the one installed by default on macOS.
I realize I don’t understand linking and loading very well. It seems like a dark art. If there’s a good book or website explaining it, please let me know.
I set the env var DYLD_PRINT_LIBRARIES and start my executable, and I can see it appears to link to multiple copies of libc++, along with various system libs from Apple. Example:
Is that bad? Or is libc++ designed to do this in a robust way, perhaps with some changes to my CMake file and compiler and linker flags? I don’t know if the runtime has a way of keep these libraries separate or if all the symbol exist in a global namespace and step on each other.
This can all be a bit complicated. It depends very much on what you are trying to achieve. It looks like you currently link against two libc++ dylibs which have the same symbols. That’s definitely not a good idea. Even worse, you have two libc++abi dylibs. Could you elaborate a bit on what you are trying to achieve? E.g. do you plan to use other system-provided functionality?
System libraries also link against libc++. Because of that, the other library also gets loaded. The interesting question is how you configure your custom libc++. To avoid having multiple libc++abi libraries you can set LIBCXX_CXX_ABI to system-libcxxabi. To avoid having the same symbols in the libc++ dylib you can set LIBCXX_ABI_NAMESPACE to something else, like __robnik_libcxx. If you want you can also set LIBCXX_ENABLE_SHARED to False, so you link against your libc++ statically (you should still change the ABI namespace).
Thanks. I will try to rebuild using these definitions and see how it goes.
I’m hitting some error with libunwind now. Maybe I don’t need it. I followed the “bootstrapping build” instructions here: Building libc++ — libc++ documentation.
It built clang, but then it seems to think exception support is disabled.
% cmake -S llvm -B build \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
-DLIBCXX_CXX_ABI=system-libcxxabi \
-DLIBCXX_ABI_NAMESPACE=__robnik_libcxx \
-DCMAKE_BUILD_TYPE=Release \
-G Ninja
% ninja -C build runtimes
... [lots of building, forgot to limit the targets] ...
[3783/3787] Performing configure step for 'runtimes'
...
-- Looking for pthread_once in pthread
-- Looking for pthread_once in pthread - found
-- Performing Test CXX_SUPPORTS_WNO_UNUSED_FUNCTION_FLAG
-- Performing Test CXX_SUPPORTS_WNO_UNUSED_FUNCTION_FLAG - Failed
-- Performing Test CXX_SUPPORTS_FUNWIND_TABLES_FLAG
-- Performing Test CXX_SUPPORTS_FUNWIND_TABLES_FLAG - Success
-- Performing Test CXX_SUPPORTS_FNO_EXCEPTIONS_FLAG
-- Performing Test CXX_SUPPORTS_FNO_EXCEPTIONS_FLAG - Failed
-- Performing Test CXX_SUPPORTS_FNO_RTTI_FLAG
-- Performing Test CXX_SUPPORTS_FNO_RTTI_FLAG - Failed
CMake Error at /Users/rob/Dev/llvm-project/libunwind/src/CMakeLists.txt:109 (message):
Compiler doesn't support generation of unwind tables if exception support
is disabled. Building libunwind DSO with runtime dependency on C++ ABI
library is not supported.
-- Configuring incomplete, errors occurred!
FAILED: runtimes/runtimes-stamps/runtimes-configure /Users/rob/Dev/llvm-project/build/runtimes/runtimes-stamps/runtimes-configure
cd /Users/rob/Dev/llvm-project/build/runtimes/runtimes-bins && /usr/local/Cellar/cmake/HEAD-3d6075d/bin/cmake --no-warn-unused-cli -DCMAKE_C_COMPILER=/Users/rob/Dev/llvm-project/build/./bin/clang -DCMAKE_CXX_COMPILER=/Users/rob/Dev/llvm-project/build/./bin/clang++ -DCMAKE_ASM_COMPILER=/Users/rob/Dev/llvm-project/build/./bin/clang -DCMAKE_AR=/Users/rob/Dev/llvm-project/build/./bin/llvm-ar -DCMAKE_LIBTOOL=/Users/rob/Dev/llvm-project/build/./bin/llvm-libtool-darwin -DCMAKE_LIPO=/Users/rob/Dev/llvm-project/build/./bin/llvm-lipo -DCMAKE_RANLIB=/Users/rob/Dev/llvm-project/build/./bin/llvm-ranlib -DCMAKE_NM=/Users/rob/Dev/llvm-project/build/./bin/llvm-nm -DCMAKE_OBJDUMP=/Users/rob/Dev/llvm-project/build/./bin/llvm-objdump -DCMAKE_C_COMPILER_TARGET=x86_64-apple-darwin22.2.0 -DCMAKE_CXX_COMPILER_TARGET=x86_64-apple-darwin22.2.0 -DCMAKE_ASM_COMPILER_TARGET=x86_64-apple-darwin22.2.0 -DCMAKE_INSTALL_PREFIX=/usr/local -DLLVM_BINARY_DIR=/Users/rob/Dev/llvm-project/build -DLLVM_CONFIG_PATH=/Users/rob/Dev/llvm-project/build/bin/llvm-config -DLLVM_ENABLE_WERROR=OFF -DLLVM_HOST_TRIPLE=x86_64-apple-darwin22.2.0 -DLLVM_HAVE_LINK_VERSION_SCRIPT=0 -DLLVM_USE_RELATIVE_PATHS_IN_DEBUG_INFO=OFF -DLLVM_USE_RELATIVE_PATHS_IN_FILES=OFF -DLLVM_LIT_ARGS=-sv -DLLVM_SOURCE_PREFIX= -DPACKAGE_VERSION=17.0.0git -DCMAKE_BUILD_TYPE=Release -DCMAKE_MAKE_PROGRAM=/usr/local/bin/ninja -DCMAKE_C_COMPILER_LAUNCHER= -DCMAKE_CXX_COMPILER_LAUNCHER= -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DCOMPILER_RT_BUILD_BUILTINS=Off -DLLVM_INCLUDE_TESTS=ON -DLLVM_DEFAULT_TARGET_TRIPLE=x86_64-apple-darwin22.2.0 -DLLVM_ENABLE_PROJECTS_USED=ON -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=OFF -DLLVM_BUILD_TOOLS=ON -DCMAKE_C_COMPILER_WORKS=ON -DCMAKE_CXX_COMPILER_WORKS=ON -DCMAKE_ASM_COMPILER_WORKS=ON -DHAVE_LLVM_LIT=ON "-DLLVM_ENABLE_RUNTIMES=libcxx;libcxxabi;libunwind" -DLIBCXX_ABI_NAMESPACE=__robnik_libcxx -DLIBCXX_CXX_ABI=system-libcxxabi -GNinja -S /Users/rob/Dev/llvm-project/llvm/runtimes/../../runtimes -B /Users/rob/Dev/llvm-project/build/runtimes/runtimes-bins && /usr/local/Cellar/cmake/HEAD-3d6075d/bin/cmake -E touch /Users/rob/Dev/llvm-project/build/runtimes/runtimes-stamps/runtimes-configure
ninja: build stopped: subcommand failed.
You don’t have to build libc++abi or libunwind. These should be provided by the OS. There is also not a lot gained compiling it yourself, so it’s probably easier to just use the already built ones.
That controls what it links to as I build libc++, right? Shouldn’t it also be possible to control that later when I’m building my app binary? If I had a new libc++abi, and the system’s libc++abi, I should be able to use linker flags to statically or dynamically link to either one, when I build my app, no?
I wanted to look at the symbols in the system’s libunwind and libc++abi, just to see what they are, but I can’t find the binaries. On macOS Ventura it appears everything has disappeared into some files in:
ls /System/Cryptexes/OS/System/Library/dyld/
dyld_shared_cache_x86_64h dyld_shared_cache_x86_64h.02 ....
As opposed to the old .dylib files that I could look at.