Building LLVM
LLVM+Clang is a bit of a beast to build due to its size, the fact that it’s nearly all C++ and the number of its dependencies. It also tends to assume that a Linux environment will either be Glibc-based or Android.
The following are notes and build instructions that have worked well for building llvm against musl as of 2013-06-18. The instructions should work in any musl and gcc based environment, but the notes below have been specifically developed and tested in the LightCube bootstrap environment. If using that environment, the instructions below assume you are chrooted into that environment and are working as the root user in the /root directory. So even though it is not explicitly stated, each section starts the commands off from the perspective of root in /root.
Environment
Just set up a PM variable for use with make in order to have it take advantage of multiple processors and build in parallel. The value should be the # of processors the kernel is aware of.
export PM=$(grep -c processor /proc/cpuinfo)
Specific to the LightCube environment, add a /usr directory and some symlinks to its top-level counterpart. An alternative to this would be to find and replace all instances of /usr in the llvm codebase, which has not yet been tested:
install -d /usr
ln -s /{bin,sbin,include,man,share} /usr/
chmod 500 /usr
Build cmake
curl -LO http://www.cmake.org/files/v2.8/cmake-2.8.11.1.tar.gz
tar -xf cmake-2.8.11.1.tar.gz
cd cmake-2.8.11.1
sed -i 's@__GNUC__@__GLIBC__@g' Source/kwsys/SystemInformation.cxx
./configure --prefix=/
make -j${PM}
make install
Build libunwind
git clone --depth 1 git://github.com/pathscale/libunwind.git
mkdir libunwind-build
cd libunwind-build
cmake -DCMAKE_C_FLAGS="-m64" ../libunwind
make
cp -a src/libunwind.* /lib/
Build llvm against libgcc/libstdc++
curl -LO https://gist.github.com/jhuntwork/5800888/raw/80538b7f5aaad6427e5f22d2428b9d644d2c93c8/llvm-musl_compat.patch
curl -LO https://gist.github.com/jhuntwork/5800919/raw/89b3fe54925888007ef4f9ec0906bffae1176979/compiler-rt-musl_compat.patch
curl -LO https://raw.github.com/path64/compiler/master/src/csu/elf-x86_64/crtbegin.S
curl -LO https://raw.github.com/path64/compiler/master/src/csu/elf-x86_64/crtend.S
git clone --depth 1 http://llvm.org/git/llvm
cd llvm
patch -Np1 -i ../llvm-musl_compat.patch
cd tools/
git clone --depth 1 http://llvm.org/git/clang
cd ../projects/
git clone --depth 1 http://llvm.org/git/compiler-rt
cd compiler-rt
patch -Np1 -i ../../../compiler-rt-musl_compat.patch
cd ..
git clone --depth 1 http://llvm.org/git/test-suite
cd ..
sed -i 's@/lib64/ld-linux-x86-64.so.2@/lib/ld-musl-x86_64.so.1@' tools/clang/lib/Driver/Tools.cpp
The below change sets the compiler up to avoid a hard-coded dependency on libgcc. It will get most of the necessary symbols from libunwind instead.
sed -i -e 's@"-lgcc[^"]*"@"-lunwind"@g' tools/clang/lib/Driver/Tools.cpp
This change is specific to the binutils version used in the LightCube environment. If using a newer version, the below should not be necessary
sed -i '/--build-id/s@.*@{}@' tools/clang/lib/Driver/ToolChains.cpp
The following two changes just set up our target description to be linux-musl instead of linux-gnu throughout the llvm code:
sed -i -e 's/linux-gnu/linux-musl/g' -e 's@LIBC=gnu@LIBC=musl@' `find . -name "confi*.guess" -o -name "confi*.sub"`
sed -i 's@linux-gnu@linux-musl@g' `grep -lr linux-gnu .`
Setup the build directory and compile:
mkdir ../llvm-build
cd ../llvm-build
../llvm/configure --prefix=/ --enable-targets=host --disable-docs --enable-optimized
make VERBOSE=1 -j${PM}
make install
Add the Pathscale crtbegin and crtend files to avoid future dependency on gcc.
as ../crtbegin.S -o /lib/clang/3.4/crtbegin.o
ln /lib/clang/3.4/crtbegin.o /lib/clang/3.4/crtbeginS.o
ln /lib/clang/3.4/crtbegin.o /lib/clang/3.4/crtbeginT.o
as ../crtend.S -o /lib/clang/3.4/crtend.o
ln /lib/clang/3.4/crtend.o /lib/clang/3.4/crtendS.o
ln /lib/clang/3.4/crtend.o /lib/clang/3.4/crtendT.o
Perform a very basic sanity check
echo 'int main(){return 1;}' | clang++ -x c++ - -v -Wl,--verbose
Build libcxxrt
This library will be replaced later with libcxxabi which performs the same function, but requires libc++ to build which we don’t have yet. llvm works better with libcxxabi when using libc++, but libcxxrt is enough to build libc++ the first time around.
git clone --depth 1 git://github.com/pathscale/libcxxrt.git
mkdir libcxxrt-build
cd libcxxrt-build
CC="clang -fPIC" CXX="clang++ -fPIC" cmake ../libcxxrt
make
cp -a lib/libcxxrt.* /lib/
Build libcxx against libcxxrt
curl -LO https://gist.github.com/jhuntwork/5805941/raw/5c80b24491c0c947e5e8ce178a44571b6b273ae9/libcxx-musl_compat.patch
git clone --depth 1 http://llvm.org/git/libcxx
cd libcxx
patch -Np1 -i ../libcxx-musl_compat.patch
mkdir ../libcxx-build
cd ../libcxx-build
CC="clang -fPIC" CXX="clang++ -fPIC -D__musl__" cmake -G "Unix Makefiles" \
-DLIBCXX_CXX_ABI=libcxxrt -DLIBCXX_LIBCXXRT_INCLUDE_PATHS="../libcxxrt/src" \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/ ../libcxx
make
make install
Build libcxxabi
curl -LO https://gist.github.com/jhuntwork/5805976/raw/110325d22d689a87727a03ebe8c5fee4bf45cede/libcxxabi.patch
git clone --depth 1 http://llvm.org/git/libcxxabi.git
cd libcxxabi
patch -Np1 -i ../libcxxabi.patch
cd lib
./buildit
cp -a libc++abi.* /lib
Build libcxx against libcxxabi
Get rid of the build data from a previous run
rm -rf libcxx-build
mkdir libcxx-build
cd libcxx-build
Latest libcxxabi no longer has this header, so remove it from the libcxx list
sed -i 's/;cxa_demangle.h//' ../libcxx/CMakeLists.txt
Configure and build
CC="clang -fPIC" CXX="clang++ -fPIC -D__musl__" cmake -G "Unix Makefiles" \
-DLIBCXX_CXX_ABI=libcxxabi -DLIBCXX_LIBCXXABI_INCLUDE_PATHS="../libcxxabi/include " \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/ ../libcxx
make install
Rebuild llvm+clang against libcxx/libcxxabi
This should remove any dependency on gcc and libstdc++ First clean up remnants of the previous build
rm -rf llvm-build
Next, make libcxx the default C++ library, instead of libstdc++
cd llvm
sed -i '/^ return ToolChain::CST_Libstdcxx/s@stdcxx@cxx@' tools/clang/lib/Driver/ToolChain.cpp
Build
mkdir ../llvm-build
cd ../llvm-build
CC=clang CXX="clang++ -stdlib=libc++" \
../llvm/configure --prefix=/ --enable-targets=host \
--disable-docs --enable-optimized --enable-libcpp
make VERBOSE=1 -j${PM}
make install
Sanity check
echo 'int main(){return 1;}' | clang++ -x c++ - -v -Wl,--verbose
Move gcc/g++ out of the way (to a temporary location)
mkdir -p /tmp/gcc.bak/{bin,lib,include}
mv /bin/gcc /tmp/gcc.bak/bin/
mv /bin/g++ /tmp/gcc.bak/bin/
mv /lib/gcc /tmp/gcc.bak/lib/
mv /lib/libgomp* /tmp/gcc.bak/lib/
mv /lib/libstdc++.* /tmp/gcc.bak/lib/
mv /include/c++/4.2.4 /tmp/gcc.bak/include/
ln -sf clang /bin/cc
ln -sf clang++ /bin/c++
Another sanity check now without gcc around
echo 'int main(){return 1;}' | cc -x c - -v -Wl,--verbose
echo 'int main(){return 1;}' | c++ -x c++ - -v -Wl,--verbose
Lastly, as an ultimate sanity check, you could repeat the last section and completely rebuild llvm+clang again. This will prove if the toolchain can build itself successfully. When done, you can execute the included test suite:
make check-all