may contain source code

published: • tags:

LLVM 3.9.1 was just released. It’s time to build the new LLVM/Clang with MinGW.

I managed to build the following things successfully:

  • LLVM: the base for everything else
  • Clang: C++ and C compilers, libClang, clang-format
  • Clang Tools Extra: mostly because it contains clang-tidy
  • LLD: the LLVM linker; haven’t played around with it yet, but it builds ;-)

These do not build, even after some coercion:

  • OpenMP: generally supports Windows, but not MinGW
  • libc++: from what I could gather from the docs, does not have Windows support at all

Without libc++ we’re missing a C++ standard library, so Clang has to rely on GNU’s libstdc++. Which brings us to the build environment.

I used the current MinGW-w64 in 64bit with GCC 6.2.0, POSIX threads and SEH exception handling, installed as a compiler toolchain in my toolchain ecosystem. With a standalone MinGW installation you’ll have to tinker with some paths, but otherwise building should work the same.

Setting up the sources

I used C:\tc\src\std as the base directory where I unpacked all sources archives. Everything will be located under C:\tc\src\std\llvm-3.9.1.src. You’ll get all necessary files on the LLVM 3.9.1 download page.

LLVM uses tar.xz as the archive format: 7-Zip can handle it. However, make sure you start 7-Zip with admin priviledges or you won’t be able to extract the symlinks contained in the Clang archive.

source code unpack to creates folder rename it to
LLVM base directory llvm-3.9.1.src doesn’t matter
Clang llvm-3.9.1.src\tools cfe-3.9.1.src clang
Clang tools extra llvm-3.9.1.src\tools\clang\tools clang-tools-extra-3.9.1.src extra
LLD llvm-3.9.1.src\tools lld-3.9.1.src lld

Patch

LibClang has a bug that makes it leak file handles of header files in some situations. The problem first hit me when Qt Creator started to sometimes be unable to save a header file because the Clang code model had leaked the file handle.

A bug report for Qt Creator exists as well as a proposed patch for Clang. I applied it to the affected file:
llvm-3.9.1.src\tools\clang\lib\Basic\FileManager.cpp
without any issues.

Building

I used GCC 6.2.0 provided by the MinGW installation to compile. You’ll also need CMake 3.0 or newer. Finally, I highly recommend using Ninja instead of Make, because it is a lot faster.

OK, we’re set with all the tools. Open a console with a properly set up environment for your compiler and create yourself a build directory. On my machine:

md %tcroot%\src\std\_build\llvm-3.9.1-static-win64
cd %tcroot%\src\std\_build\llvm-3.9.1-static-win64

Configuring a Static Build

A static build has the nice property that everything will be self-contained. That’s especially useful for the Clang tools – like clang-format. Being able to copy clang-format.exe around and use it from anywhere without the need of a properly set up toolchain environment definitely outweighs the disadvantage of slightly larger sizes of the binaries.

Run CMake from the build directory. Adjust paths as needed. If you need a full overview over the valid options, have a look at llvm-3.9.1.src\docs\CMake.rst.

cmake %tcroot%\src\std\llvm-3.9.1.src -G Ninja -DCMAKE_BUILD_TYPE=Release ^
-DLLVM_TARGETS_TO_BUILD=AArch64;ARM;X86;AMDGPU ^
-DLLVM_BUILD_TOOLS=ON -DLLVM_INCLUDE_EXAMPLES=OFF ^
-DLLVM_BUILD_TESTS=OFF -DLLVM_INCLUDE_TESTS=OFF ^
-DLLVM_ENABLE_EH=ON -DLLVM_ENABLE_RTTI=ON ^
-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ ^
-DCMAKE_CXX_FLAGS=-std=c++11 ^
-DGCC_INSTALL_PREFIX=%syspath% -DCMAKE_INSTALL_PREFIX=%syspath% ^
-DCMAKE_EXE_LINKER_FLAGS="-static-libgcc -static-libstdc++ -static -lstdc++ -lpthread" ^
-DBUILD_SHARED_LIBS=OFF ^
-DLLVM_PARALLEL_COMPILE_JOBS=6 -DLLVM_PARALLEL_LINK_JOBS=6

Some notes about the command line:

  • The targets are the target architectures LLVM/Clang will be able to produce binaries for. Shown here are ARM 64bit, ARM 32bit, x86 (both 64bit and 32bit) and AMD graphics cards, as these are the only architectures I’ll ever need. The directories in llvm-3.9.1.src\lib\Target seem to represent the list of all available targets.
  • GCC_INSTALL_PREFIX must point to the directory that contains the main bin directory of your MinGW installation. It tells Clang where to find libstdc++ so you don’t manually have to add the header locations every time you compile something with the new Clang.
  • CMAKE_INSTALL_PREFIX can probably be different from GCC_INSTALL_PREFIX. But since Clang is tied to libstdc++ anyway I think it makes sense to install it as kind of an extension of the the MinGW/GCC distribution.
  • The best number of parallel jobs obviously depends on how many CPUs/cores your machine has.

CMake will take some seconds to run. Make sure to check the output for anything fishy. Especially all your target architectures should be listed as well as LLD and Clang with their versions.

Configuring a Shared Build

The CMake command line looks very similar. You only need to change two things:

  • Omit the complete -DCMAKE_EXE_LINKER_FLAGS option.
  • Use -DBUILD_SHARED_LIBS=ON instead of OFF.

Compiling and Installing

Run:

cmake --build .

Even though we build in release mode the binaries still contain debug symbols. I like to save some space and strip the symbols from the .exe files. For the DLLs, especially libClang, the symbols might come in handy for debugging at some point, so I keep them.

strip bin\*.exe
cmake --build . --target install

Using Make instead of Ninja

Running jobs in parallel with Make is really unrealiable. You have to keep the number low or you’ll run into weird race condition errors that may or may not be solved by simply running Make again. In my experience two parallel jobs are the safe-ish maximum. Of course that makes Make a lot slower than Ninja.

When configuring a Make-based build, the CMake command line looks very similar to the Ninja one. Except:

  • Use -G "MinGW Makefiles" instead of -G Ninja.
  • Omit the two LLVM_PARALLEL options. They only work with Ninja.

To compile, run:

mingw32-make -j2 && echo Success!
  • Don’t omit the success sentinel. When running in multi-job mode Make is extremely bad at indicating failure. The end of the output might look completely ok, but an error can be hidden several pages above.
  • If you run into a Permission denied error during linking, don’t panic. That is such a race conditions between parallel jobs. Just run Make again. If the error doesn’t go away after 2–3 tries, lower your job count and try again. The worst thing that can happen is that you’ll have to finish building with a single job.

Comments