Thanks Shoaib for a great summary. To summarize this as an answer to Louis’ questions:
- What is a “Standalone build”? What does it enable that a normal monorepo build can’t?
This means building any of the runtimes separately, where the runtime’s CMakeLists.txt (e.g. path/to/my/llvm-project/libcxx/CMakeLists.txt) is the top-level one. The reason for using this variant is the ability to build individual runtimes without the rest of LLVM (e.g. building only libc++) which is not something that the monorepo build can do.
- What is the “Runtimes” build? How does it work, what is it used for, and what does it expect from libc++/libc++abi/libunwind?
This means building runtimes with the just-built Clang. The reason why this is complicated is because at the point when you run CMake for runtimes (i.e. where path/to/my/llvm-project/llvm/runtimes/CMakeLists.txt is the top-level one), you may not have a fully working toolchain yet.
For example, in case of Fuchsia, our sysroot contains only libc, so when we’re doing the runtimes build, and one of the runtimes tries to use check_cxx_compiler_flag, which behind the scenes tries to compile and link a small C++ binary, that check is going to fail not because the flag isn’t supported, but because we don’t have libc++ yet (that’s what we’re trying to build right now). So we need to be really careful and avoid introducing cycles e.g. where libc++ CMake build depends C++ standard library (even if that dependency is not explicit).
Note that this is going to become significantly easier after we upgrade CMake because 3.6 introduced https://cmake.org/cmake/help/v3.6/variable/CMAKE_TRY_COMPILE_TARGET_TYPE.html which allows building static archives instead of executables when running check_* functions which can help and break these cycles.
- Are there other “hidden” ways to build the runtime libraries?
Not “hidden”, but there’s the default way which most developers use where you use the same host compiler to build both Clang and your runtimes. I think this mode should go away because it’s too fragile: it silently relies on your host compiler and the Clang you just built using the same ABI, which isn’t guaranteed (unless you’re using a multi-stage build) and I’m surprised we haven’t yet seen issues due to this (or maybe we did and people just aren’t aware of the problem).
(Why do we need HAVE_* flags?)
It’s because in the runtimes build, there’s no guarantee about the order in which runtimes are being built, so you cannot use e.g. if (TARGET cxxabi_shared) from within libc++ build because you don’t have any guarantee whether libc++abi has already been processed. So instead, runtimes build sets these flags for each runtime being built (that is each runtime specified in -DLLVM_ENABLE_RUNTIMES=) and you can at least check whether that runtime is being built at all (e.g. you can check from within libc++ whether libc++abi is also being built as part of the runtimes build).
There’s more discussion related to this in https://reviews.llvm.org/D68833, once we update CMake to >=3.11 we’ll eliminate all HAVE_* variables and replace them with generator expressions which is a much better solution.