Skip to content

Commit

Permalink
ci: build and cache LLVM from source
Browse files Browse the repository at this point in the history
Generalizes the build process for any LLVM version and any set of configuration options. To make it faster, the set of targets is reduced to only what we need for MrDocs. When we change the LLVM parameters, the first run will take slightly longer in CI and subsequent runs will reuse the cached binaries. This means we no longer need to host the binaries on mrdocs.com and update them manually, making the process of updating the LLVM version much simpler and cheaper since github will be hosting the binaries. It also allows us to explore other static ways to build LLVM in CI, which is required to create executables that are not associated with a specific ubuntu version.

fix #548
  • Loading branch information
alandefreitas committed Mar 22, 2024
1 parent b615e97 commit 03b55df
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 184 deletions.
127 changes: 80 additions & 47 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ jobs:
outputs:
matrix: ${{ steps.cpp-matrix.outputs.matrix }}
steps:
- name: Clone cpp-actions
uses: actions/checkout@v3

- name: Generate Test Matrix
uses: alandefreitas/cpp-actions/[email protected]
id: cpp-matrix
Expand Down Expand Up @@ -59,15 +56,90 @@ jobs:
contents: write

steps:
- name: Install git
- name: Install Essential Packages
if: ${{ matrix.container }}
env:
DEBIAN_FRONTEND: 'noninteractive'
TZ: 'Etc/UTC'
uses: alandefreitas/cpp-actions/[email protected]
with:
apt-get: git
apt-get: git build-essential python3

- name: Clone MrDocs
uses: actions/checkout@v3

- name: Setup CMake
uses: alandefreitas/cpp-actions/[email protected]
id: setup-cmake
with:
# Clang requires clang-scan-deps to work on the latest CMake versions
version: ${{ matrix.compiler == 'clang' && '3.26' || '>=3.26' }}
check-latest: 'true'
update-environment: 'true'

- name: Setup Ninja
uses: seanmiddleditch/gha-setup-ninja@v4
if: ${{ runner.os == 'Windows' }}

- name: LLVM Parameters
id: llvm-parameters
run: |
echo -E "llvm-hash=29b20829cc6ce3e6d9c3809164994c1659e0da56" >> $GITHUB_OUTPUT
echo -E "llvm-build-preset=${{ runner.os == 'Windows' && 'release-win' || 'release-unix' }}" >> $GITHUB_OUTPUT
cd ..
llvm_root=$(pwd)/third-party/llvm-project/install
if [[ ${{ runner.os }} == 'Windows' ]]; then
llvm_root=$(echo "$llvm_root" | sed 's/\\/\//g')
llvm_root=$(echo $llvm_root | sed 's|^/d/|D:/|')
echo "$llvm_root"
fi
echo -E "llvm-root=$llvm_root" >> $GITHUB_OUTPUT
- name: LLVM Binaries
id: llvm-cache
uses: actions/cache@v4
with:
path: ${{ steps.llvm-parameters.outputs.llvm-root }}
key: llvm-${{ runner.os }}-${{ steps.llvm-parameters.outputs.llvm-build-preset }}-${{ steps.llvm-parameters.outputs.llvm-hash }}

- name: Install LLVM
id: llvm-install
if: steps.llvm-cache.outputs.cache-hit != 'true'
shell: bash
run: |
# LLVM is be installed with the default compiler
set -x
# Shallow clone LLVM_HASH in ../third-party/llvm
cd ..
mkdir -p third-party/llvm-project
cd third-party/llvm-project
llvm_project_root=$(pwd)
git config --global init.defaultBranch master
git config --global advice.detachedHead false
git init
git remote add origin https://github.com/llvm/llvm-project.git
git fetch --depth 1 origin ${{ steps.llvm-parameters.outputs.llvm-hash }}
git checkout FETCH_HEAD
# Copy presets
cp ../../mrdocs/third-party/llvm/CMakePresets.json ./llvm
cp ../../mrdocs/third-party/llvm/CMakeUserPresets.json.example ./llvm/CMakeUserPresets.json
# Build
cd llvm
llvm_root=$(pwd)
cmake --version
cmake -S . -B ./build --preset=${{ steps.llvm-parameters.outputs.llvm-build-preset }}
if [[ ${{ runner.os }} == 'Linux' ]]; then
cmake --build ./build --target help
fi
N_CORES=$(nproc 2>/dev/null || echo 1)
cmake --build ./build --config Release --parallel $N_CORES
cmake --install ./build --prefix "$llvm_project_root"/install
# Setup C++ after installing LLVM to use the default compiler
# for LLVM and the specified compiler for MrDocs
- name: Setup C++
uses: alandefreitas/cpp-actions/[email protected]
id: setup-cpp
Expand All @@ -87,45 +159,6 @@ jobs:
cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx }}
cxxflags: ${{ matrix.cxxflags }}

- name: Install LLVM
id: llvm-install
shell: bash
run: |
set -xe
config_type="Release"
filename="${{ runner.os }}-$config_type-29b20829.${{ ( runner.os == 'Windows' && '7z' ) || 'tar.xz' }}"
url="https://mrdox.com/llvm+clang/$filename"
# Download
if command -v curl &> /dev/null
then
curl -L -o "$filename" "$url"
elif command -v wget &> /dev/null
then
wget -O "$filename" "$url"
else
echo "Neither curl nor wget are available"
exit 1
fi
# Extract
llvm_root="${{runner.tool_cache}}/llvm+clang"
llvm_root=$(echo "$llvm_root" | sed 's/\\/\//g')
mkdir -p "$llvm_root"
if [ "${{ runner.os }}" != "Windows" ]; then
tar -xvf "$filename" -C "$llvm_root" --strip-components=1
else
7z x "$filename"
cd "$config_type"
mv * "$llvm_root"
cd ..
rm -rf "$config_type"
fi
# Export
echo "llvm_root=$llvm_root"
echo -E "llvm-root=$llvm_root" >> $GITHUB_OUTPUT
- name: Install Node.js
uses: actions/setup-node@v3
with:
Expand All @@ -137,16 +170,16 @@ jobs:
cmake-version: '>=3.20'
cxxstd: ${{ matrix.cxxstd }}
cc: ${{ steps.setup-cpp.outputs.cc || matrix.cc }}
ccflags: ${{ matrix.ccflags }}
ccflags: ${{ matrix.ccflags }}${{ ( matrix.compiler == 'gcc' && ' -static-libstdc++') || '' }}${{ ( matrix.asan && ' -static-libasan') || '' }}${{ ( matrix.tsan && ' -static-libtsan') || '' }}
cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx }}
cxxflags: ${{ matrix.cxxflags }}${{ ( matrix.compiler == 'gcc' && ' -static-libstdc++') || '' }}${{ ( matrix.asan && ' -static-libasan') || '' }}${{ ( matrix.tsan && ' -static-libtsan') || '' }}
generator: Ninja
toolchain: ${{ steps.package-install.outputs.vcpkg_toolchain || steps.package-install.outputs.vcpkg-toolchain }}
build-type: ${{ matrix.build-type }}
install-prefix: .local
extra-args: |
-D LLVM_ROOT="${{ steps.llvm-install.outputs.llvm-root || '/usr/local' }}"
-D Clang_ROOT="${{ steps.llvm-install.outputs.llvm-root || '/usr/local' }}"
-D LLVM_ROOT="${{ steps.llvm-parameters.outputs.llvm-root || '../third-party/llvm-project/install' }}"
-D Clang_ROOT="${{ steps.llvm-parameters.outputs.llvm-root || '../third-party/llvm-project/install' }}"
export-compile-commands: true
run-tests: true
install: true
Expand Down
168 changes: 31 additions & 137 deletions docs/modules/ROOT/pages/install.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ Binary packages are available from our https://github.com/cppalliance/mrdocs/rel
== Source
The following instructions assume we are at a parent directory that's going to contain both the MrDocs and the third-party dependencies directories.
[source]
----
+ <parent-directory>
+ mrdocs
+ third-party
----
Clone the MrDocs repository with:
[source,bash]
Expand All @@ -33,128 +42,42 @@ Fell free to install them anywhere you want and adjust the main MrDocs configura
MrDocs uses LLVM to parse C++ code and extract documentation from it.
It depends on a recent version of LLVM: https://github.com/llvm/llvm-project/tree/29b20829cc6ce3e6d9c3809164994c1659e0da56[29b20829]
[#llvm-binaries]
**Binaries**:
Because building LLVM may take many hours to complete, we provide pre-built binaries for Windows and Linux:
|===
| | https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html[CMake Preset,window=_blank] | https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html[CMake Build,window=_blank] | Debug Info | Optimized | https://learn.microsoft.com/en-us/visualstudio/ide/understanding-build-configurations?view=vs-2022[MSVC Build,window=_blank]
| 🪟 https://mrdox.com/llvm+clang/Windows-Release-29b20829.7z[`Windows-Release-29b20829.7z`]
| 🚀 Release
| 🚀 Release
| ❌
| ✅
| 🚀 Release
| 🪟 https://mrdox.com/llvm+clang/Windows-Debug-29b20829.7z[`Windows-Debug-29b20829.7z`]
| 🐞 Debug
| 🐞 Debug
| ✅
| ❌
| 🐞 Debug
| 🪟 https://mrdox.com/llvm+clang/Windows-RelWithDebInfo-29b20829.7z[`Windows-RelWithDebInfo-29b20829.7z`]
| 🕵️‍♂️ RelWithDebInfo
| 🕵️‍♂️ RelWithDebInfo
| ✅
| ✅
| 🚀 Release
| 🪟 https://mrdox.com/llvm+clang/Windows-DebWithOpt-29b20829.7z[`Windows-DebWithOpt-29b20829.7z`]
| 🔬 DebWithOpt
| 🐞 Debug
| ✅
| ✅
| 🐞 Debug
| 🐧 https://mrdox.com/llvm+clang/Linux-Release-29b20829.tar.xz[`Linux-Release-29b20829.tar.xz`]
| 🚀 Release
| 🚀 Release
| ❌
| ✅
| N/A
| 🐧 https://mrdox.com/llvm+clang/Linux-Debug-29b20829.tar.xz[`Linux-Debug-29b20829.tar.xz`]
| 🐞 Debug
| 🐞 Debug
| ✅
| ❌
| N/A
| 🐧 https://mrdox.com/llvm+clang/Linux-RelWithDebInfo-29b20829.tar.xz[`Linux-RelWithDebInfo-29b20829.tar.xz`]
| 🕵️‍♂️ RelWithDebInfo
| 🕵️‍♂️ RelWithDebInfo
| ✅
| ✅
| N/A
| 🐧 https://mrdox.com/llvm+clang/Linux-DebWithOpt-29b20829.tar.xz[`Linux-DebWithOpt-29b20829.tar.xz`]
| 🔬 DebWithOpt
| 🐞 Debug
| ✅
| ✅
| N/A
|===
IMPORTANT: The Linux binaries are built on Ubuntu 22.04 and may not work on other distributions.
You can download the binaries and uncompress them in the `./third-party/llvm+clang` directory we created in the previous step.
LLVM binaries are provided in a number of preset configurations.
Here is a brief description of each preset:
- `Release`: this is the preset users will typically use.
It is optimized for speed and does not include debug information.
- `Debug`: this is a preset developers can use.
It includes debug information and no optimizations.
However, using a `Debug` build of LLVM to debug MrDocs might be too slow.
In this case, you can link MrDocs with `RelWithDebInfo` or `DebWithOpt`.
- `RelWithDebInfo`: this is a release build with debug information.
It is optimized for speed and includes debug information.
However, if you are working with Windows+MSVC, this preset has a `Release` build type at the MSVC level.
This means you can have conflicts with MrDocs in `Debug` mode because of LLVM setting flags such as the `_ITERATOR_DEBUG_LEVEL` and `/MDd`.
In this case, you can use `DebWithOpt` instead to avoid the conflict and subsequent workarounds.
- `DebWithOpt`: this is a debug build with optimizations.
It includes all the default Debug flags for LLVM, it's optimized for speed, includes debug information, and causes no conflicts with MrDocs in `Debug` mode.
If you chose to use the provided binaries instead of building LLVM from source, you can skip to the <<duktape>> section.
**Download**:
Alternatively, if building LLVM from source, you can clone the project from the official repository:
You can shallow-clone the project from the official repository:
[source,bash]
----
git clone https://github.com/llvm/llvm-project.git
mkdir -p llvm-project
cd llvm-project
git checkout 29b20829cc6ce3e6d9c3809164994c1659e0da56
cd llvm
git init
git remote add origin https://github.com/llvm/llvm-project.git
git fetch --depth 1 origin 29b20829cc6ce3e6d9c3809164994c1659e0da56
git checkout FETCH_HEAD
----
**Configure**:
There are two ways to configure LLVM: using <<llvm-configure-presets, CMake presets>> or using <<llvm-configure-cmd-line, CMake directly>>.
[#llvm-configure-presets]
_Configure with CMake Presets_
The `mrdocs/third-party/llvm` directory provides https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html[CMake presets,window=_blank] to build LLVM.
We recommend using preset files as they contain a replicable set of CMake configuration values that can be used for a project.
From `third-party/llvm-project`, you can copy the `CMakePresets.json` and `CMakeUserPresets.json` files to the `llvm-project/llvm` directory.
We recommend using https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html[CMake presets,window=_blank] to build LLVM.
Preset files contain a replicable set of CMake configuration values that can be used to configure a project.
[source,bash]
----
cp ../../mrdocs/third-party/llvm/CMakePresets.json ./llvm
cp ../../mrdocs/third-party/llvm/CMakeUserPresets.json.example ./llvm/CMakeUserPresets.json
----
Instead of passing all CMake configuration values on the command line, a template for the `CMakePresets.json` and `CMakeUserPresets.json` files is provided in the repository's `third-party/llvm` directory.
Copy these files to the `llvm-project/llvm` directory and run a command such as the following to configure LLVM:
Run a command such as the following to configure LLVM:
[source,bash]
----
cmake -preset=relwithdebinfo-win
cd llvm
cmake -S . -B ./build --preset=release-win
----
In the example above, we configure a `RelWithDebInfo` version of LLVM for MrDocs: a release build with debug information.
In the example above, we configure a `Release` version of LLVM for MrDocs.
Choose one of the presets from `CMakePresets.json` or edit the variants in `CMakeUserPresets.json` to customize the configurations.
The `CMakeUserPresets.json` file comes with presets for all the configurations described in the <<llvm-binaries,Binaries>> section.
[NOTE]
====
Expand All @@ -166,48 +89,19 @@ This should give you an optimized build with all debug features and flags, such
In other platforms, this should give you a release somewhat equivalent to `RelWithDebInfo` optimized for debugging experience. `-Og` offers a reasonable level of optimization while maintaining fast compilation and a good debugging experience.
====
[#llvm-configure-cmd-line]
_Configure with Command Line Arguments_:

You can also configure LLVM directly with the settings required by MrDocs:

Windows (from administrator `cmd.exe`, after running `vcvars64.bat`):

[source,commandline]
----
cmake -S llvm -B build/MSVC/RelWithDebInfo -G "Ninja" -A x64 -D LLVM_ENABLE_PROJECTS="clang" -D CMAKE_CONFIGURATION_TYPES="RelWithDebInfo" -D LLVM_ENABLE_RTTI=ON -D CMAKE_INSTALL_PREFIX=../llvm+clang/RelWithDebInfo -D LLVM_ENABLE_IDE=OFF -D LLVM_ENABLE_DIA_SDK=OFF
----

Unix variants:

[source,bash]
----
cmake -S llvm -B build/Linux/RelWithDebInfo -D LLVM_ENABLE_PROJECTS="clang" -D CMAKE_BUILD_TYPE=RelWithDebInfo -D LLVM_ENABLE_RTTI=ON -D CMAKE_INSTALL_PREFIX=../llvm+clang/RelWithDebInfo
----

Unlike the <<llvm-configure-presets,CMake presets>>, this command does not a number of parameters that removes features that are not required by MrDocs, thus increasing the build time and size of the installation.

**Build**:
Build and install the configured version of LLVM with:
[source,bash]
----
cd build
cmake --build . --config RelWithDebInfo
cmake --install . --prefix ../../llvm+clang/RelWithDebInfo" --config RelWithDebInfo
cmake --build ./build --config Release --parallel 4
cmake --install ./build --prefix ../install
----
If you prefer using the provided CMake presets, you can also use the `--preset` option for the `build` command:

[source,bash]
----
cd build
cmake --build --preset=relwithdebinfo-win
cmake --install MSVC/RelWithDebInfo --config RelWithDebInfo
----
Replace 4 with the number of cores you want to use for building LLVM.
Return from `./third-party/llvm-project/build` to the parent `third-party` directory to install other dependencies:
Return from `./third-party/llvm-project/llvm` to the parent `third-party` directory to install other dependencies:
[source,bash]
----
Expand Down
1 change: 1 addition & 0 deletions third-party/llvm/CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"LLVM_BUILD_TESTS": false,
"LLVM_BUILD_DOCS": false,
"LLVM_BUILD_EXAMPLES": false,
"LLVM_ENABLE_TERMINFO": false,
"CLANG_ENABLE_ARCMT": true,
"CLANG_ENABLE_HLSL": false,
"CLANG_ENABLE_OBJC_REWRITER": false,
Expand Down

0 comments on commit 03b55df

Please sign in to comment.