Distribution packages in Ubuntu often trail the upstream LLVM release cycle. When a newer compiler is needed before it reaches the official repositories, the prebuilt archives published on the LLVM GitHub Releases page provide a reliable alternative. The following steps outline how to install a modern Clang toolchain from a .tar.xz bundle while preserving the conventional filesystem layout used by the APT packages.
Extracting and Staging the Compiler
After downloading the release archive matching your architecture and Ubuntu version, extract it into /usr/lib/ following the standard llvm-<version naming convention.
sudo tar -xJf clang+llvm-18.1.8-x86_64-linux-gnu-ubuntu-22.04.tar.xz
sudo mv clang+llvm-18.1.8-x86_64-linux-gnu-ubuntu-22.04 /usr/lib/llvm-18
sudo ln -sf /usr/lib/llvm-18/bin/clang /usr/bin/clang
sudo ln -sf /usr/lib/llvm-18/bin/clang++ /usr/bin/clang++
If the libc++ standard-library implementation will be used, its run-time libraries must be visible to the dynamic linker. Create /etc/ld.so.conf.d/libcxx.conf containing the following path:
/usr/lib/llvm-18/lib/x86_64-unknown-linux-gnu
Then refresh the shared-library cache:
sudo ldconfig
Build Configuration with CMake Presets
Projects using C++20 Modules require CMake 3.28 or later. A CMakePresets.json entry for a Ninja-based debug build might resemble the following:
{
"version": 6,
"configurePresets": [
{
"name": "clang-debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/${presetName}",
"installDir": "${sourceDir}/install/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_C_COMPILER": "clang",
"CMAKE_CXX_COMPILER": "clang++",
"CMAKE_CXX_STANDARD": "20"
},
"environment": {
"CPLUS_INCLUDE_PATH": "/usr/lib/llvm-18/include/c++/v1:/usr/lib/gcc/x86_64-linux-gnu/12/include:/usr/lib/llvm-18/include/x86_64-unknown-linux-gnu/c++/v1"
},
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
}
],
"buildPresets": [
{
"name": "clang-debug",
"configurePreset": "clang-debug",
"jobs": 8
}
]
}
Fixing Header Search Paths
When clang-scan-deps runs inside CMake, it may fail to locatee system headers such as stddef.h because the search path does not automatically include the GCC compatibility layer or the platform-specific libc++ configuration directory.
Inspect the active include directories to identify what is missing:
echo '' | clang++ -x c++ -v -E - -stdlib=libc++
For a typical libc++ setup, append three directories:
/usr/lib/llvm-18/include/c++/v1— the libc++ headers/usr/lib/gcc/x86_64-linux-gnu/12/include— compiler intrinsics supplied by GCC (the version directory may differ)/usr/lib/llvm-18/include/x86_64-unknown-linux-gnu/c++/v1—__config_siteand target-specific libc++ files
If the project uses libstdc++ instead of libc++, only the GCC internal include directory usually needs to be added.
Clang recognizes several environment variables for supplemental include paths:
C_INCLUDE_PATH— used only when preprocessing C sourcesCPLUS_INCLUDE_PATH— used only when preprocessing C++ sourcesCPATH— used for both C and C++
For a system-wide default, append the paths in ~/.bashrc:
export CPLUS_INCLUDE_PATH="/usr/lib/llvm-18/include/c++/v1:/usr/lib/gcc/x86_64-linux-gnu/12/include:/usr/lib/llvm-18/include/x86_64-unknown-linux-gnu/c++/v1${CPLUS_INCLUDE_PATH:+:${CPLUS_INCLUDE_PATH}}"
Removing Older APT Installations
Once the upstream toolchain is functional, the older distribution packages can be removed to avoid conflicts:
sudo apt autoremove --purge llvm-15 clang-15
Upgrading CMake and Ninja
C++20 Modules support also depends on recant versions of the build tools. Remove the default packages first:
sudo apt autoremove --purge cmake ninja-build
Run the official CMake self-extracting archive. The following non-interactive command installs direct into /usr/local:
chmod +x cmake-3.29.2-linux-x86_64.sh
sudo ./cmake-3.29.2-linux-x86_64.sh --prefix=/usr/local --skip-license
For Ninja, extract the official release binary onto a directory in PATH:
sudo unzip ninja-linux.zip -d /usr/local/bin
Rebuilding lldb-mi from Source
Uninstalling the prior LLVM version breaks any existing lldb-mi binary that was linked against the old shared objects (for example, liblldb-15.so.1). Compile a replacement from the lldb-tools/lldb-mi sources against the new LLVM libraries.
Several development packages are required to satisfy LLVM’s CMake exported targets:
| CMake Target | Ubuntu Package |
|---|---|
ZLIB::ZLIB |
zlib1g-dev |
zstd::libzstd_shared |
libzstd-dev |
Terminfo::terminfo |
libncurses-dev |
LibXml2 |
libxml2-dev |
Install them together:
sudo apt install -y zlib1g-dev libzstd-dev libncurses-dev libxml2-dev
Configure and build:
mkdir build && cd build
cmake .. -DCMAKE_PREFIX_PATH=/usr/lib/llvm-18
cmake --build . --parallel
Finally, stage the binary so both the shell PATH and IDE integrations (such as the VS Code CMake extension) can locate it:
sudo install -m 755 src/lldb-mi /usr/local/bin/
sudo install -m 755 src/lldb-mi /usr/lib/llvm-18/bin/