CtrlK
BlogDocsLog inGet started
Tessl Logo

himank-test/tessl-llvm

LLVM 22.x tile for building compilers, language runtimes, and out-of-tree tooling

88

1.23x
Quality

83%

Does it follow best practices?

Impact

96%

1.23x

Average score across 5 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

out-of-tree.mddocs/

Out-of-Tree LLVM 22 Projects — CMake Setup & Linking

Reference: Building LLVM with CMake | llvm-config


When to build out-of-tree

Build out-of-tree (against an installed LLVM) when you are:

  • Writing a standalone compiler frontend or language runtime
  • Developing a pass plugin loadable by opt --load-pass-plugin
  • Building tooling (e.g., a static analyzer, refactoring tool) on top of LLVM

Build in-tree (inside the LLVM source tree) when you are:

  • Adding a new target backend
  • Adding in-tree passes, intrinsics, or IR changes
  • Contributing to LLVM upstream

Installing LLVM 22

# macOS (Homebrew)
brew install llvm@22
# Headers: /opt/homebrew/opt/llvm@22/include
# CMake:   /opt/homebrew/opt/llvm@22/lib/cmake/llvm

# Ubuntu / Debian
apt install llvm-22-dev libclang-22-dev
# Headers: /usr/lib/llvm-22/include
# CMake:   /usr/lib/llvm-22/lib/cmake/llvm

# Build from source
cmake -S llvm -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_INSTALL_PREFIX=/usr/local/llvm-22 \
  -DLLVM_TARGETS_TO_BUILD="X86;AArch64;RISCV" \
  -DLLVM_ENABLE_PROJECTS="clang" \
  -G Ninja
ninja -C build install

Locate the cmake config directory:

llvm-config-22 --cmakedir
# /usr/lib/llvm-22/lib/cmake/llvm

Minimal CMakeLists.txt

cmake_minimum_required(VERSION 3.20)
project(MyCompiler CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# ── Locate LLVM 22 ────────────────────────────────────────────────────────────
find_package(LLVM 22 REQUIRED CONFIG)
message(STATUS "LLVM version: ${LLVM_PACKAGE_VERSION}")
message(STATUS "LLVM CMake dir: ${LLVM_DIR}")

include_directories(${LLVM_INCLUDE_DIRS})
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})

# ── Map LLVM components to link targets ───────────────────────────────────────
llvm_map_components_to_libnames(LLVM_LIBS
  Core          # LLVMContext, Module, IRBuilder, basic types
  Support       # raw_ostream, StringRef, Error, CommandLine
  Analysis      # DominatorTree, ScalarEvolution, AliasAnalysis
  Passes        # PassBuilder, NPM infrastructure
  IRReader      # parseIRFile, parseAssemblyString
  BitWriter     # WriteBitcodeToFile
  Target        # TargetMachine, TargetRegistry
  X86CodeGen    # X86 backend (replace with your target)
  X86AsmParser
  X86Desc
  X86Info
)

# ── Targets ───────────────────────────────────────────────────────────────────
add_executable(mycompiler
  src/main.cpp
  src/Frontend.cpp
  src/CodeGen.cpp
)

target_include_directories(mycompiler PRIVATE include)
target_link_libraries(mycompiler PRIVATE ${LLVM_LIBS})

Component reference

List all available components:

llvm-config-22 --components

Commonly used components

ComponentWhat it provides
CoreLLVMContext, Module, Function, IRBuilder, all IR types
Supportraw_ostream, StringRef, Error, Expected, CommandLine, MemoryBuffer
AnalysisDominatorTree, LoopInfo, ScalarEvolution, AAResults, CallGraph
PassesPassBuilder, ModulePassManager, all standard analyses
IRReaderparseIRFile(), parseAssemblyString()
BitReaderparseBitcodeFile()
BitWriterWriteBitcodeToFile()
LinkerLinker::linkModules()
TransformUtilsCloneFunction, InlineFunction, utility transforms
ScalarScalar optimization passes (instcombine, simplifycfg, etc.)
IPOInterprocedural passes (inliner, argument promotion, etc.)
VectorizeLoop and SLP vectorizers
TargetTargetMachine, TargetRegistry, TargetOptions
MCMCContext, MCInstrInfo, MCRegisterInfo — needed for MC layer
ExecutionEngineLLVM interpreter / JIT infrastructure
MCJITMCJIT execution engine
OrcJITORC JIT v2 (preferred JIT in LLVM 22)
X86CodeGenX86 target code generation
AArch64CodeGenAArch64 target code generation
RISCVCodeGenRISC-V target code generation

Build and configure

# Using LLVM_DIR explicitly
cmake -S . -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_DIR=$(llvm-config-22 --cmakedir)

# Or via CMAKE_PREFIX_PATH
cmake -S . -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DCMAKE_PREFIX_PATH=/usr/local/llvm-22

cmake --build build -j$(nproc)

Pass plugin CMake setup

To build a pass loadable by opt --load-pass-plugin:

add_library(MyPassPlugin MODULE
  src/MyPass.cpp
)

target_include_directories(MyPassPlugin PRIVATE
  ${LLVM_INCLUDE_DIRS}
  include
)

target_compile_definitions(MyPassPlugin PRIVATE ${LLVM_DEFINITIONS})

set_target_properties(MyPassPlugin PROPERTIES
  CXX_STANDARD 17
  POSITION_INDEPENDENT_CODE ON
  # No default lib prefix on macOS/Linux
  PREFIX ""
)

# Do NOT link LLVM libs into the plugin — use symbols from the host (opt)
# target_link_libraries(MyPassPlugin PRIVATE ${LLVM_LIBS})  ← DON'T DO THIS

Test the plugin:

opt --load-pass-plugin=./MyPassPlugin.so \
    -passes=my-pass -S input.ll

LLVM_ENABLE_ASSERTIONS and build types

# Debug build with assertions (slow, catches bugs early)
cmake -DCMAKE_BUILD_TYPE=Debug \
      -DLLVM_ENABLE_ASSERTIONS=ON ...

# Release with assertions (recommended for development)
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo \
      -DLLVM_ENABLE_ASSERTIONS=ON ...

# Release (production / benchmarking)
cmake -DCMAKE_BUILD_TYPE=Release \
      -DLLVM_ENABLE_ASSERTIONS=OFF ...

Match LLVM_ENABLE_ASSERTIONS to what your LLVM install was built with to avoid ABI mismatches.


Multiple LLVM installs

If you have multiple LLVM versions installed, avoid mixing them:

# Ensure cmake finds LLVM 22, not LLVM 21:
export PATH=/usr/local/llvm-22/bin:$PATH
cmake -DLLVM_DIR=/usr/local/llvm-22/lib/cmake/llvm ...

# Check version after configure:
# The cmake output should show: "LLVM version: 22.x.x"

Useful cmake variables set by LLVMConfig.cmake

VariableDescription
LLVM_PACKAGE_VERSIONFull version string, e.g. 22.1.2
LLVM_VERSION_MAJORMajor version integer, e.g. 22
LLVM_INCLUDE_DIRSHeader search paths
LLVM_LIBRARY_DIRSLibrary search paths
LLVM_DEFINITIONSCompiler definitions (e.g. -D_GNU_SOURCE)
LLVM_TOOLS_BINARY_DIRPath to opt, llc, llvm-lit, etc.
LLVM_BUILD_MAIN_SRC_DIRSource tree (only set for build-tree installs)
LLVM_ENABLE_ASSERTIONSWhether assertions were enabled
LLVM_ENABLE_EHWhether exceptions are enabled in LLVM
LLVM_ENABLE_RTTIWhether RTTI is enabled in LLVM

Important: If LLVM_ENABLE_RTTI=OFF (the default), your project must also disable RTTI:

if(NOT LLVM_ENABLE_RTTI)
  target_compile_options(mycompiler PRIVATE -fno-rtti)
endif()

Common mistakes

  • Do NOT hardcode -lLLVMCore etc. — use llvm_map_components_to_libnames so CMake handles ordering and transitive deps.
  • Do NOT link LLVM libs into a pass plugin — the plugin is loaded into opt which already has them; double-linking causes symbol conflicts.
  • Do NOT mix LLVM 22 headers with LLVM 21 libraries — always verify LLVM_PACKAGE_VERSION in the cmake output.
  • Do NOT forget to match RTTI and exception settings between your project and the LLVM install.
  • ALWAYS call InitializeAll*() target init functions before using TargetRegistry or creating TargetMachine.

docs

alias-analysis.md

attributes-metadata.md

calling-conventions.md

codegen.md

debug-info.md

exception-handling.md

frontend-to-ir.md

gc-statepoints.md

index.md

ir-types.md

jit.md

lto.md

new-pass-manager.md

out-of-tree.md

tablegen.md

version-notes.md

AUDIT.md

tile.json