marp | class |
---|---|
true |
invert |
Duncan Ogilvie
Sharing dependencies for C++ projects comes with a lot of challenges:
- Compilation time
- LLVM can take an hour to build on a powerful machine
- We observed more than 4 hours on GitHub Actions
- Disk usage
- More than 15 GiB required while building
- Distributions are around 1 GiB compressed
- Reproducible environment
- Local builds on developer machines
- Continuous integration (GitHub Actions)
The library is built in 3 stages:
- Configuration:
cmake -G Ninja -B build -DMYPROJECT_OPTION=ON
- Build:
cmake --build build
- Install:
cmake --install build --prefix build/install
┌── bin
│ └── cstool
├── include
│ └── capstone
│ ├── capstone.h
│ └── *.h
└── lib
├── cmake
│ └── capstone
│ ├── capstone-config-version.cmake
│ ├── capstone-config.cmake
│ ├── capstone-targets-noconfig.cmake
│ └── capstone-targets.cmake
├── libcapstone.a
└── pkgconfig
└── capstone.pc
In your project's CMakeLists.txt
:
cmake_minimum_required(VERSION 3.24)
project(MyProject)
find_package(capstone REQUIRED)
add_executable(myproject src/main.cpp)
target_link_libraries(myproject PRIVATE capstone::capstone)
Configuration command line:
cmake -B build -DCMAKE_PREFIX_PATH=/capstone/build/install
┌── dependencies <== Superbuild project
│ ├── CMakeLists.txt
│ ├── build <== Superbuild build directory
│ └── install <== Superbuild install prefix
│ └── bin/lib/...
├── src
│ └── main.cpp
└── CMakeLists.txt <== Main project
Compilation:
# Build the dependencies
cmake -B dependencies/build -S dependencies
cmake --build dependencies/build
# Build the main project
cmake -B build -DCMAKE_PREFIX_PATH=dependencies/install
cmake --build build
option(LLVM_ENABLE_ASSERTIONS "Enable assertions in LLVM" ON)
ExternalProject_Add(llvm
URL
"https://github.com/llvm/llvm-project/releases/download/llvmorg-19.1.0/llvm-project-19.1.0.src.tar.xz"
URL_HASH
"SHA256=5042522b49945bc560ff9206f25fb87980a9b89b914193ca00d961511ff0673c"
CMAKE_CACHE_ARGS
${CMAKE_ARGS}
"-DLLVM_ENABLE_PROJECTS:STRING=lld;clang;clang-tools-extra"
"-DLLVM_ENABLE_ASSERTIONS:STRING=${LLVM_ENABLE_ASSERTIONS}"
"-DLLVM_ENABLE_DUMP:STRING=${LLVM_ENABLE_ASSERTIONS}"
"-DLLVM_ENABLE_RTTI:STRING=ON"
"-DLLVM_ENABLE_LIBEDIT:STRING=OFF"
"-DLLVM_PARALLEL_LINK_JOBS:STRING=1"
"-DLLVM_ENABLE_DIA_SDK:STRING=OFF"
CMAKE_GENERATOR
"Ninja"
SOURCE_SUBDIR
"llvm"
)
The ExternalProject_Add
command allows you to specify custom build/patch/install commands:
ExternalProject_Add(xed
GIT_REPOSITORY
"https://github.com/intelxed/xed"
GIT_TAG
"v2022.10.11"
GIT_PROGRESS
ON
GIT_SHALLOW
ON
CMAKE_CACHE_ARGS
${CMAKE_ARGS}
CONFIGURE_COMMAND
"${CMAKE_COMMAND}" -E true
BUILD_COMMAND
"${Python3_EXECUTABLE}" "<SOURCE_DIR>/mfile.py" ${MFILE_ARGS}
INSTALL_COMMAND
"${CMAKE_COMMAND}" -E copy_directory <BINARY_DIR>/install "${CMAKE_INSTALL_PREFIX}"
PREFIX
xed-prefix
)
# TODO: generate XEDVersion.cmake as well file
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/XEDConfig.cmake.in" "${CMAKE_INSTALL_PREFIX}/lib/cmake/XED/XEDConfig.cmake" @ONLY)
- Base:
ubuntu:22.04
- LLVM:
ghcr.io/llvmparty/packages/llvm:22.04-llvm19.1.0
- Takes the longest time to build, so we create a separate layer
- Final:
ghcr.io/llvmparty/packages/dependencies:22.04-llvm19.1.0-xxx
Note: we use multi-stage builds to limit the final image size!
docker buildx build --platform linux/arm64,linux/amd64 -t "$LLVM_TAG" . -f llvm.Dockerfile
The final images are pushed to a (public) docker registry.
jobs:
build:
runs-on: ubuntu-22.04
container:
image: ghcr.io/llvmparty/packages/dependencies:22.04-llvm19-20241007-3f858ff9
steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Build Project
run: |
cmake -B build -G Ninja
cmake --build build
.devcontainer/devcontainer.json
:
{
"name": "MyProject",
"image": "ghcr.io/llvmparty/packages/dependencies:22.04-llvm19-20241007-3f858ff9",
"customizations": {
"vscode": {
"extensions": [
"llvm-vs-code-extensions.vscode-clangd",
// Add more extensions here
]
},
"codespaces": {
"openFiles": [
"src/main.cpp"
]
}
},
"remoteEnv": {
"PATH": "${containerWorkspaceFolder}/build:${containerEnv:PATH}"
},
"postCreateCommand": ".devcontainer/post-create.sh"
}
Questions?