So, what if you have a Linux box and want to be able to take LLVM/Clang/libc++ out for a spin? This is doable, but there are a few obstacles to overcome:
We also need CMake, a tool for creating customized installation scripts for setting up software on the system. It provides functionality similar to that of the ubiquitous Linux configure scripts. We can install CMake from a repository. However, on some systems LLVM or Clang will complain that the CMake version is too old. If you run into this, you can build CMake from source that can be downloaded from the CMake website. It is possible to build Clang and LLVM using traditional configure scripts, without CMake, but libc++(abi) have to be built using CMake.
In addition it is assumed that you are comfortable compiling and linking C/C++ code, managing software installation on your Linux system, and have a good working knowledge of the Linux command line.
The www.llvm.org website offers pre-compiled binaries of LLVM and Clang with libc++ for some Linux distributions, and it's the easiest way, but only if your distro is supported.
Installing Clang (and LLVM that it depends on) from a repository should be trivial. However, you will still need to build libc++(abi). Also, Clang version provided by the repository is likely to be older than the most recent available source. Another difference between using repository-provided Clang and one built from source is that the former doesn't seem to understand the -stdlib=libc++
flag; we have to use -I<libc++ header location> instead.
To build libc++(abi) we have to download and unpack LLVM and libc++(abi) source. We are only building libc++(abi) from source, but to accomplish this we must also have LLVM source code available. As of this writing, the tarballs available at llvm.org are:
libcxx-3.6.2.src.tar.xz
libcxxabi-3.6.2.src.tar.xz
llvm-3.6.2.src.tar.xz
So, here are the steps, assuming we are in the root's home directory, normally /root:
[root@test1 ~]# tar xf llvm-3.6.2.src.tar.xz
[root@test1 ~]# mv llvm-3.6.2.src llvm_src
[root@test1 ~]# cd llvm_src/projects/
[root@test1 projects]# tar xf ~/libcxx-3.6.2.src.tar.xz
[root@test1 projects]# mv libcxx-3.6.2.src libcxx
[root@test1 projects]# tar xf ~/libcxxabi-3.6.2.src.tar.xz
[root@test1 projects]# mv libcxxabi-3.6.2.src libcxxabi
[root@test1 projects]# cd
[root@test1 ~]# mkdir llvm_build; cd llvm_build
[root@test1 llvm_build]# cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" ../llvm_src
Please see here for additional options that can be used with CMake. The build type is very important!
[root@test1 llvm_build]# make cxx
[root@test1 llvm_build]# make cxxabi
[root@test1 llvm_build]# cd projects/libcxx
[root@test1 libcxx]# make install
[root@test1 libcxx]# cd ../libcxxabi
[root@test1 libcxxabi]# make install
[root@test1 ~]# g++ -I/usr/local/include/c++/v1 junk.cpp
However, this will result in a bunch of linker warnings. The problem is that GCC will try to link the code using libstdc++, which is incompatible with libc++ headers located in /usr/local/include/c++/v1. Solution:
[root@test1 ~]# g++ -I/usr/local/include/c++/v1 junk.cpp -lc++ -lc++abi
[root@test1 ~]# ldd a.out
linux-vdso.so.1 => (0x00007ffc06f78000)
libc++.so.1 => /lib64/libc++.so.1 (0x00007fe5948df000)
libc++abi.so.1 => /lib64/libc++abi.so.1 (0x00007fe594668000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fe594360000)
...
From ldd's output we see that the binary still shows a dependency on libstdc++. If you want to get rid of it:
[root@ip-172-31-17-25 ~]# g++ -I/usr/local/include/c++/v1 junk.cpp -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc
[root@ip-172-31-17-25 ~]# ldd a.out
linux-vdso.so.1 => (0x00007fff69df5000)
libc++.so.1 => /usr/local/lib/libc++.so.1 (0x00007f2c98c98000)
libc++abi.so.1 => /usr/local/lib/libc++abi.so.1 (0x00007f2c98a67000)
libm.so.6 => /lib64/libm.so.6 (0x00007f2c98765000)
libc.so.6 => /lib64/libc.so.6 (0x00007f2c983a4000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f2c9818e000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f2c97f72000)
librt.so.1 => /lib64/librt.so.1 (0x00007f2c97d6a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f2c98f50000)
[root@ip-172-31-17-25 ~]#
Please note that GCC works with libc++(abi) for some code, but may fail for other. For instance, if you try to build LLVM+Clang, it may not work. If you want to build LLVM+Clang that doesn't depend on libstdc++, you will need to bootstrap, i.e. build it using libstdc++-dependent Clang.
[root@test1 ~]# cd llvm_src/tools
[root@test1 tools]# tar xf ~/cfe-3.6.2.src.tar.xz
[root@test1 tools]# mv cfe-3.6.2.src clang
Then do cmake as described earlier. Please be sure to use the release build type! Otherwise you will end up with a compiler that is an order of magnitude slower than one built in release mode and is about 5 times the size of the release version!
Once cmake has completed, do
make
in the llvm_src directory. Building the software may take awhile, so be patient. Also make sure the system has at leas 2GB of RAM available, otherwise the build may fail. Once the build is complete, do
make install
By default this will install LLVM, Clang, and the libs to /usr/local.
Clang does not provide a linker, but relies on the system's linker, typically ld
, to link executables. This is the case even on FreeBSD and Mac OS X systems where Clang is the default compiler. We can see this using the -v option to clang++.
Now, ld won't work without the following files:
libgcc.a
libgcc_s.so
crtbegin.o
crtbeginT.o
crtbeginS.o
crtendS.o
crtend.o
These are needed by ld, called by Clang, even on FreeBSD systems without GCC. So, logically they really seem to better belong in the libgcc package, and they are indeed part of libgcc-dev on Ubuntu, but on systems like Fedora and CentOS they are in the gcc package.
On an RPM-based system libgcc_s.so, provided by the gcc package, is typically a symlink to libgcc_s.so.1 provided by the libgcc package. So, before we uninstall GCC, we may want to create
libgcc_s.so -> libgcc_s.so.1
in the directory where libgcc_s.so.1 is located and copy the rest of the libgcc* and crt* files listed above to the same directory. Sometimes we may also need
crtfastmath.o
crtprec32.o
crtprec80.o
crtprec64.o
libgcc_eh.a
so it's a good idea to copy those out as well. In fact, make check-all
will fail without libgcc_eh.
Now it's OK to remove the gcc package. BTW, if you are tempted to get rid of libgcc and libstdc++, which are related to GCC, it won't work: too much of the system depends on those packages, as can be seen by trying to remove them.
clang++ -I/usr/local/include/c++/v1 junk.cpp -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc
If we want to use clang/clang++ with a typical ./configure script, we would need to set some environment variables, e.g.:
export LIBS="-nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc"
export CXX=clang++
export CC=clang
export CXXFLAGS=-I/usr/local/include/c++/v1
If we want to use CMake, we might be able to do something like
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_CXX_FLAGS="-I/usr/local/include/c++/v1"
-DCMAKE_EXE_LINKER_FLAGS="-nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc" -G "Unix Makefiles" /source/location
Unfortunately, depending on how CMake configuration is set up, the above may not work. Strictly speaking, the CMAKE_EXE_LINKER_FLAGS variable is for flags, not libraries. Creative editing of CMake configuration may be required; use your CMake knowledge, read the docs, and see my article on bootstrapping Clang. Also, sometimes we may run into a situation where we cannot build software because the build system performs tests assuming that no extra linker flags are needed. In such situations we can use a wrapper script like
#!/bin/bash
MYLFLAGS="-nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc"
# Catch the case when we only want to compile; this helps us avoid some warnings:
if echo "$@" | egrep "(^-c | -c | -c$)" >/dev/null 2>&1; then
MYLFLAGS=""
fi
# Use -stdlib=libc++ w/ clang built from source; otherwise use -I/usr/local/include/c++/v1
#/usr/bin/clang++ -stdlib=libc++ "$@" $MYLFLAGS
/usr/bin/clang++ -I/usr/local/include/c++/v1 "$@" $MYLFLAGS
Then, when configuring the software we are trying to build, we need to set the CXX variable to the name of the wrapper. You may need to adjust things to suit your particular setup. Or, if using CMake, we can do:
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++w
-G "Unix Makefiles" /source/location
Of course, we can also use the wrapper directly from the command line, e.g. (assuming the wrapper is clang++w and is in the path):
clang++w junk.cpp