Deploying Clang from LLVM Prebuilt Tarballs on Ubuntu

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_site and 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 sources
  • CPLUS_INCLUDE_PATH — used only when preprocessing C++ sources
  • CPATH — 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/

Tags: llvm Clang Ubuntu toolchain CMake

Posted on Thu, 08 Oct 2026 16:17:08 +0000 by jtbaker