App and Web Development Information and Services

How to Use Clang without GCC on Linux

GCC is the de-facto standard compiler on Linux systems today. However, there is an emerging competing compiler family, the LLVM-based Clang along with a separate standard C++ library implementation, libc++, that is claimed to be a full implementation of the C++11 standard as opposed to GCC's experimental support of C++11. In addition, LLVM is the technology behind Apple's new Swift programming language that is gaining acceptance fast, for now primarily in the Apple development world. Besides, Clang is the default compiler on Mac OS X and on FreeBSD starting with version 10.

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:

So, let's look at how to tackle these problems. We will try to keep this discussion at a general enough level so it is applicable to both RPM- and DEB-based systems, the more prominent examples of the former type being Fedora and CentOS, and of the latter - Ubuntu. We will try to point out major differences.

Prerequisites

It is possible to remove GCC and then use repo-provided Clang to build libc++/libc++abi, but we are going an easier route: start with a system that has GCC installed. We will get rid of it later, after we have libc++(abi).

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.

Installing Clang from Repository

There are two alternative approaches: installing Clang from a repository or building it from source. In the first case libc++ has to be built separately from source.

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.

Building libc++ and libc++abi
Now that we have installed Clang from repository, we need to build libc++. To use this library on Linux, we need an additional library that provides a low-level support for it, called Application Binary Interface, or ABI. There are a couple of alternatives described on the libc++ website, but we are going to stick with the libc++abi library supplied by the LLVM project. We will refer to this libc++/libc++abi combo as libc++(abi).

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:

  1. Unpack LLVM into llvm_src directory: [root@test1 ~]# tar xf llvm-3.6.2.src.tar.xz [root@test1 ~]# mv llvm-3.6.2.src llvm_src
  2. Change to llvm_src/projects and unpack libcxx into libcxx directory: [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
  3. Do the same for libcxxabi: [root@test1 projects]# tar xf ~/libcxxabi-3.6.2.src.tar.xz [root@test1 projects]# mv libcxxabi-3.6.2.src libcxxabi
  4. Create a separate build directory, change to it, and use CMake to configure the source: [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!
  5. Make lib++ and lib++abi: [root@test1 llvm_build]# make cxx [root@test1 llvm_build]# make cxxabi
  6. Install libc++(abi); they go to /usr/local by default: [root@test1 llvm_build]# cd projects/libcxx [root@test1 libcxx]# make install [root@test1 libcxx]# cd ../libcxxabi [root@test1 libcxxabi]# make install
It is now OK to delete the llvm_build and llvm_src directories if you want to save space.
Side Note: Using GCC with libc++
At this point you might be able to use your new installation of libc++(abi) with GCC, if you prefer to use GCC, but want a different C++ library implementation, i.e. libc++. Here is an example, where junk.cpp is a test C++ program you can write for yourself: [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.

Installing Clang from Source

If we want to build LLVM, Clang, and libc++(abi) from source instead of using repository-provided Clang, then we also need to download Clang source (cfe-3.6.2.src.tar.xz as of this writing) and do the following before creating the llvm_build directory and doing cmake; this is assuming the aforementioned directory layout and the tarball downloaded to the home directory. Please make sure libc++(abi) and LLVM sources are also placed in llvm_src as described earlier. [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.

RPM-based Systems: Before Removing GCC

If we want to get rid of GCC and use clang as our default compiler on the system, we may have to make some adjustments on some RPM-based systems.

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.

Making Clang Use libc++

To build a binary from a C++ source file, say junk.cpp, we need to do what we did earlier when using g++ with libc++(abi):

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