Dogfood part 4: native compiler-rt

In part 3 I created a native libc++ so now I can use this to build most of compiler-rt (leaving out libfuzzer which is another build of libc++) This ‘runtime only’ build is reasonably straight forward except for one small gotcha.

linker_flags = '-stdlib=libc++ -rtlib=compiler-rt -fuse-ld=lld'
subprocess.run (
    [
        'cmake',
        '-G',
        'Ninja',
        '-S',
        'runtimes',
        '-B',
        build,
        '--trace-expand',
        '--trace-redirect=' + build +'/cmake.log',
        '-DCMAKE_BUILD_TYPE=Release',
        '-DCMAKE_C_COMPILER=' + STAGING + '/bin/clang',
        '-DCMAKE_CXX_COMPILER=' + STAGING + '/bin/clang++',
        '-DCMAKE_CXX_FLAGS=-stdlib=libc++',
        '-DCMAKE_EXE_LINKER_FLAGS_INIT=' + linker_flags,
        '-DCMAKE_INSTALL_PREFIX=' + STAGING,
        '-DCMAKE_MODULE_LINKER_FLAGS_INIT=' + linker_flags,
        '-DCMAKE_SHARED_LINKER_FLAGS_INIT=' + linker_flags,
        '-DCOMPILER_RT_BUILD_LIBFUZZER=OFF',
        '-DCOMPILER_RT_USE_BUILTINS_LIBRARY=ON',
        '-DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=ON',
        '-DLLVM_ENABLE_RUNTIMES=compiler-rt',
        '-DLLVM_TARGETS_TO_BUILD=Native'
    ],
    check=True
)
subprocess.run (
    [
        'ninja',
        '-C',
        build,
        'compiler-rt'
    ],
    check=True
)
subprocess.run (
    [
        'ninja',
        '-C',
        build,
        'install-compiler-rt'
    ],
    check=True
)

Where

  • linker_flags clearly defines that I want to use llvm-project libraries and tools
  • build is set to ‘build-native-rt’
  • –trace-expand and --trace-redirect are used to debug cmake
  • STAGING is still set to ‘/staging’ (it is a constant after all)
  • CMAKE_CXX_FLAGS is the gotcha! The XRAY instrumentation code ignores the linker information expects -stdlib=libc++ to be found here instead.
  • COMPILER_RT_BUILD_LIBFUZZER is turned off as it kicks off another build of libc++. Its something I will have to finish later.

The CMAKE_CXX_FLAGS highlights the highly inconsistent use of flags thoughout the llvm-project.
I would have thought that the more general cmake flags would serve as the main flags for the llvm-project with perhaps the ability to override these in a consistent way at the llvm and runtimes level and then again for each project or runtime if it is neccessary.

Unfortunately, throughout the cmake code I have seen nearly every flag being overwritten, making it almost impossible to understand. You can see from my builds, that I now aviod any non-cmake flag unless it is absolutely neccessary (and probably a bug)

At this point we are ready to commit the files in STAGING to /usr/local
Now as I am developing on a raspberry Pi, based on Debian, my host triple is not aarch64-unknown-linux-gnu, it is aarch64-linux-gnu. So the libc++.so libc++abi.so libunwind.so libraries are in the wrong place. I could move them into the correct place, but then clang cannot find them. I compromise by copying them:

mkdir /usr/local/lib/aarch64-linux-gnu && \
	cp /usr/local/lib/aarch64-unknown-linux-gnu/libunwind.so.1.0 /usr/local/lib/aarch64-linux-gnu/libunwind.so.1.0 && \
	ln -s /usr/local/lib/aarch64-linux-gnu/libunwind.so.1.0 /usr/local/lib/aarch64-linux-gnu/libunwind.so.1 && \
	ln -s /usr/local/lib/aarch64-linux-gnu/libunwind.so.1 /usr/local/lib/aarch64-linux-gnu/libunwind.so && \
	cp /usr/local/lib/aarch64-unknown-linux-gnu/libc++abi.so.1.0  /usr/local/lib/aarch64-linux-gnu/libc++abi.so.1.0 && \
	ln -s /usr/local/lib/aarch64-linux-gnu/libc++abi.so.1.0  /usr/local/lib/aarch64-linux-gnu/libc++abi.so.1 && \
	ln -s /usr/local/lib/aarch64-linux-gnu/libc++abi.so.1  /usr/local/lib/aarch64-linux-gnu/libc++abi.so && \
	cp /usr/local/lib/aarch64-unknown-linux-gnu/libc++.so.1.0 /usr/local/lib/aarch64-linux-gnu/libc++.so.1.0 && \
	ln -s /usr/local/lib/aarch64-linux-gnu/libc++.so.1.0 /usr/local/lib/aarch64-linux-gnu/libc++.so.1 && \
	cp /usr/local/lib/aarch64-unknown-linux-gnu/libc++.so /usr/local/lib/aarch64-linux-gnu/ && \
	ldconfig /usr/local/lib/aarch64-linux-gnu

return to building clang again which is really part1 with the linker flags set to llvm-project

linker_flags = '-stdlib=libc++ -rtlib=compiler-rt -fuse-ld=lld'
subprocess.run (
    [
        'cmake',
        '-G',
        'Ninja',
        '-S',
        'llvm',
        '-B',
        build,
        '-DCMAKE_BUILD_TYPE=Release',
        '-DCMAKE_C_COMPILER=clang',
        '-DCMAKE_CXX_COMPILER=clang++',
        '-DCMAKE_EXE_LINKER_FLAGS_INIT=' + linker_flags,
        '-DCMAKE_INSTALL_PREFIX=' + STAGING,
        '-DCMAKE_MODULE_LINKER_FLAGS_INIT=' + linker_flags,
        '-DCMAKE_SHARED_LINKER_FLAGS_INIT=' + linker_flags,
        '-DLIBCLANG_BUILD_STATIC=ON',
        '-DLLVM_ENABLE_LIBCXX=ON',
        '-DLLVM_ENABLE_PROJECTS=clang;lld',
        '-DLLVM_TARGETS_TO_BUILD=Native',
    ],
    check=True
)

Where:

  • DLLVM_ENABLE_LIBCXX is used because -stdlib=libc++ is ignored in the linker commands
  • LIBCLANG_BUILD_STATIC is a failed attempt at statically linking libc++ into clang - still more work to do!

I have tested that these builds work without any of the (C++) GNU Compiler Collection:

	apt-get install -y --no-install-recommends \
		bzip2 \
		cmake \
		git \
		libc6-dev \
		ninja-build \
		python3 \
		python3-distutils \
		unzip \
		zip \
		zlib1g \

at least twice (to ensure they are repeatable)