Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 108 additions & 71 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
uses: actions/checkout@v4

- name: Generate Test Matrix
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
id: cpp-matrix
with:
compilers: |
Expand All @@ -42,7 +42,7 @@ jobs:
latest-factors: |
msvc Optimized-Debug
gcc UBSan Coverage
clang UBSan ASan
clang UBSan ASan MSan
apple-clang UBSan ASan
factors: ''
runs-on: |
Expand All @@ -66,21 +66,29 @@ jobs:
clang: git build-essential pkg-config python3 curl openjdk-11-jdk pkg-config libncurses-dev libxml2-utils libxml2-dev g++-14=14.2.0-4ubuntu2~24.04
msvc: ''
extra-values: |
llvm-hash: a1b6e7ff393533a5c4f3bdfd4efe5da106e2de2b
llvm-build-preset-prefix: {{#if optimized-debug}}debwithopt{{else}}{{{lowercase build-type}}}{{/if}}
use-libcxx: {{#if (and (ieq compiler 'clang') (or (eq major 19) (eq major 20) (eq major 21))) }}true{{else}}false{{/if}}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang will be always tested with libcxx now? Even on linux? Even when unrelated to sanitizers.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't there a ge (an "operator>=") handlebars helper?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find an operator equivalent to >=, it should be spelled 'ge' I think for consistency with naming of existing operators.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I felt that there was some value in using these on clang even without sanitizers, because at least the libcxx built here will be controlled by the same flags, so it will have debug info, will have runtime assertions if we choose to enable it, and so on. It would give some extra variation on top of what we already do on the GCC jobs.

libcxx-runtimes: libcxx{{#if (ne compiler 'msvc')}};libcxxabi{{/if}}
llvm-runtimes: {{#if (ine use-libcxx 'true') }}{{{ libcxx-runtimes }}}{{/if}}
llvm-path: {{#if (ieq compiler 'msvc') }}D:/a{{else if (ieq compiler 'apple-clang')}}/Users/runner/work{{else}}/__w{{/if}}/llvm
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding this is very unstable. Any new container will keep breaking this.

I know it's so we can -isystem{{{ llvm-path }}}/include/c++/v1{{/if}} later on, but the expression can still be evaluated at the job step because we're allowed to use more than one variable in the cmake workflow step or wherever you might want these flags.

In GHA actions, expressions are represented with ${{ ... }}, such as:

https://github.com/doxygen/doxygen/releases/download/Release_1_9_7/doxygen-1.9.7.{{ os }}${{ ( runner.os == 'Windows' && '.x64' ) || '' }}.bin.${{ ( runner.os == 'Windows' && 'zip' ) || 'tar.gz' }}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good if cpp-actions supported expanding these '${{ ' expressions later, but that doesn't work ATM,
this string would end up used as-is.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know hard-coding these paths is not ideal, but GitHub is not very helpful here, and the options to avoid this end up being much more complicated.

llvm-hash: 3f797a8342c3dbe4a260b26f948d8776ff490431
llvm-build-preset-prefix: {{#if optimized-debug}}optimizeddebug{{else}}{{{lowercase build-type}}}{{/if}}
llvm-build-preset-os: {{#if (ieq os 'windows') }}win{{else}}unix{{/if}}
llvm-sanitizer: {{#if (eq compiler 'gcc')}}{{else if ubsan}}-UBSan{{else if asan}}-ASan{{else if msan}}-MSan{{/if}}
llvm-build-preset: {{{ llvm-build-preset-prefix }}}-{{{ llvm-build-preset-os }}}
llvm-compiler-version: {{#if (or (contains version '*') (contains version '^'))}}{{else}}-{{{ version }}}{{/if}}
llvm-archive-basename: llvm-{{{ lowercase os }}}-{{{ compiler }}}{{{ llvm-compiler-version }}}-{{{ llvm-build-preset-prefix }}}{{{ llvm-sanitizer }}}-{{{ substr llvm-hash 0 7 }}}
llvm-root: ../third-party/llvm-project/install
llvm-archive-extension: {{#if (ieq os 'windows') }}7z{{else}}tar.bz2{{/if}}
llvm-archive-filename: {{{ llvm-archive-basename }}}.{{{ llvm-archive-extension }}}
llvm-sanitizer-config: {{#if (and (ne compiler 'clang') (ne compiler 'apple-clang'))}}{{else if ubsan}}Undefined{{else if asan}}Address{{else if msan}}MemoryWithOrigins{{/if}}
mrdocs-flags: {{#if (and (eq compiler 'gcc') (not asan)) }}-static{{/if}}{{#if (and (eq compiler 'clang') msan) }}-fsanitize-memory-track-origins{{/if}}
mrdocs-ccflags: {{{ ccflags }}} {{{ mrdocs-flags }}}
mrdocs-cxxflags: {{{ cxxflags }}} {{{ mrdocs-flags }}}
mrdocs-linkflags: {{#if asan }}-fsanitize=address{{/if}}
common-flags-base: {{#if (ieq compiler 'clang')}}-gz=zstd {{/if}}
common-flags: {{{ common-flags-base }}}{{#if msan }}-fsanitize-memory-track-origins {{/if}}
common-cxxflags-base: {{#if (ieq use-libcxx 'true') }}-nostdinc++ -nostdlib++ -isystem{{{ llvm-path }}}/include/c++/v1{{/if}}
common-ccflags: {{{ ccflags }}} {{{ common-flags }}}
common-cxxflags: {{{ cxxflags }}} {{{ common-flags }}} {{{ common-cxxflags-base }}}
common-ldflags: {{{ ldflags }}} {{#if (ieq use-libcxx 'true') }}-L{{{ llvm-path }}}/lib -lc++abi -lc++ -Wl,-rpath,{{{ llvm-path }}}/lib {{/if}}{{#if ubsan }}-fsanitize=undefined {{/if}}{{#if asan }}-fsanitize=address {{/if}}{{#if msan }}-fsanitize=memory {{/if}}
mrdocs-flags: {{#if (and (eq compiler 'gcc') (not asan)) }}-static{{/if}}
mrdocs-ccflags: {{{ common-ccflags }}} {{{ mrdocs-flags }}}
mrdocs-cxxflags: {{{ common-cxxflags }}} {{{ mrdocs-flags }}}
mrdocs-package-generators: {{#if (ieq os 'windows') }}7Z ZIP WIX{{else}}TGZ TXZ{{/if}}
mrdocs-release-package-artifact: release-packages-{{{ lowercase os }}}
output-file: matrix.json
Expand Down Expand Up @@ -135,7 +143,7 @@ jobs:
# We need git to ensure actions/checkout@v4 will use git and
# for the next steps that need to clone repositories
- name: Install Git
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
if: matrix.container != ''
env:
DEBIAN_FRONTEND: 'noninteractive'
Expand Down Expand Up @@ -164,7 +172,7 @@ jobs:
uses: seanmiddleditch/gha-setup-ninja@v5

- name: Setup C++
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
id: setup-cpp
with:
compiler: ${{ matrix.compiler }}
Expand All @@ -189,7 +197,7 @@ jobs:
${{ steps.setup-cpp.outputs.cxx }} --print-target-triple

- name: Install System Packages
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
if: matrix.compiler != 'msvc'
id: package-install
env:
Expand All @@ -198,18 +206,15 @@ jobs:
with:
apt-get: ${{ matrix.install }}

- name: Resolve LLVM Root
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This was the step resolving it.

id: resolve-llvm-root
- name: Install LLVM packages
if: matrix.compiler == 'clang'
env:
DEBIAN_FRONTEND: 'noninteractive'
TZ: 'Etc/UTC'
run: |
set -x
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
echo "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-21 main" >> /etc/apt/sources.list
apt-get update
apt-get install -y libclang-18-dev libclang-19-dev libclang-20-dev libclang-21-dev

- name: Resolve Third-Party Directory
id: resolve-third-party-dir
Expand All @@ -228,7 +233,7 @@ jobs:
id: llvm-cache
uses: actions/cache@v4
with:
path: ${{ steps.resolve-llvm-root.outputs.llvm-root }}
path: ${{ matrix.llvm-path }}
key: ${{ matrix.llvm-archive-basename }}

- name: Download LLVM Binaries
Expand All @@ -242,7 +247,7 @@ jobs:
found="true"
echo "found=$found" >> $GITHUB_OUTPUT
curl -L -o ${{ matrix.llvm-archive-filename }} "$url"
install_prefix=$(pwd)/../third-party/llvm-project/install
install_prefix=${{ matrix.llvm-path }}
mkdir -p $install_prefix
if [[ ${{ matrix.llvm-archive-extension }} == '7z' ]]; then
7z x ${{ matrix.llvm-archive-filename }} -o$install_prefix
Expand All @@ -261,9 +266,50 @@ jobs:
echo "found=$found" >> $GITHUB_OUTPUT
fi

# Installs libc++ separately, using the LLVM standalone runtimes build.
# The libc++ built here will be built using the host compiler, so this is
# limited by what libc++ at the current LLVM revision supports.
# This will be only built for configurations where 'use-libcxx' is true,
# and in which case libc++ will **not** be built again later using the
# bootstrapping runtimes build.
- name: Install libc++
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good to include some comments here because this is very confusing. I undertand why this is being done, but it's very confusing to anyone new at this.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait... Now I'm not sure even I understand it. The "Install LLVM" step is building libc++ again, right? Like, every single time for all workflows. Is that correct? Isn't there a better way?

Copy link
Collaborator Author

@mizvekov mizvekov Sep 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it's not building it again. Either this step runs because we have 'use-libcxx' true, and then we don't build libc++ later using the LLVM bootstrap build, or this step is skipped because 'use-libcxx' is not true, but then we build libc++ on the bootstrap build later.

The libc++ on this step is built using the host compiler, and this can only be done with the compilers which are supported by it: [apple-]clang >= 19 and gcc >= 15.

id: install_libcxx
uses: alandefreitas/cpp-actions/[email protected]
if: matrix.use-libcxx == 'true' && steps.llvm-cache.outputs.cache-hit != 'true' && steps.llvm-download.outputs.found != 'true'
with:
cmake-version: '>=3.26'
source-dir: ../third-party/llvm-project/runtimes
git-repository: https://github.com/llvm/llvm-project.git
git-tag: ${{ matrix.llvm-hash }}
download-dir: ../third-party/llvm-project
build-dir: ${sourceDir}/build
build-type: ${{ matrix.build-type }}
extra-args: |
-D LLVM_USE_SANITIZER=${{ matrix.llvm-sanitizer-config }}
-D LLVM_OPTIMIZED_TABLEGEN=ON
-D LLVM_ENABLE_LIBCXX=OFF
-D LLVM_ENABLE_PROJECT=""
-D LLVM_ENABLE_RUNTIMES="${{ matrix.libcxx-runtimes }}"
-D LIBCXXABI_USE_LLVM_UNWINDER=OFF
-D CMAKE_C_FLAGS="${{ matrix.common-flags-base }}"
-D CMAKE_CXX_FLAGS="${{ matrix.common-flags-base }}"

cc: ${{ steps.setup-cpp.outputs.cc }}
cxx: ${{ steps.setup-cpp.outputs.cxx }}
generator: Ninja
install: true
install-prefix: ${{ matrix.llvm-path }}
run-tests: false
trace-commands: true

- name: Remove libcxx build-dir
if: steps.install_libcxx.outcome == 'success'
run: |
rm -r ../third-party/llvm-project/runtimes/build

- name: Install LLVM
id: install_llvm
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
if: steps.llvm-cache.outputs.cache-hit != 'true' && steps.llvm-download.outputs.found != 'true'
with:
cmake-version: '>=3.26'
Expand All @@ -274,29 +320,37 @@ jobs:
patches: |
./third-party/llvm/CMakePresets.json
./third-party/llvm/CMakeUserPresets.json
build-dir: ${sourceDir}/llvm/build
build-dir: ${sourceDir}/build
preset: ${{ matrix.llvm-build-preset }}
build-type: ${{ matrix.build-type }}
# The LLVM_USE_SANITIZER option doesn't support GCC.
extra-args: |
-DLLVM_USE_SANITIZER=${{ matrix.llvm-sanitizer-config }}
-D LLVM_ENABLE_ASSERTIONS=ON
-D LLVM_USE_SANITIZER="${{ matrix.llvm-sanitizer-config }}"
-D LLVM_OPTIMIZED_TABLEGEN=ON
-D LLVM_COMPILER_CHECKED=ON
-D LLVM_BUILD_TOOLS=OFF
-D CLANG_BUILD_TOOLS=OFF
-D LLVM_ENABLE_RUNTIMES="${{ matrix.llvm-runtimes }}"
-D LIBCXXABI_USE_LLVM_UNWINDER=OFF
-D CMAKE_C_FLAGS="${{ matrix.common-flags-base }}"
-D CMAKE_CXX_FLAGS="${{ matrix.common-flags-base }} ${{ matrix.common-cxxflags-base }}"
-D CMAKE_SHARED_LINKER_FLAGS="${{ matrix.common-ldflags }}"
-D CMAKE_EXE_LINKER_FLAGS="${{ matrix.common-ldflags }}"
cc: ${{ steps.setup-cpp.outputs.cc }}
cxx: ${{ steps.setup-cpp.outputs.cxx }}
ccflags: -gz=zstd
cxxflags: -gz=zstd
generator: Ninja
install: true
install-prefix: ${sourceDir}/../install
install-prefix: ${{ matrix.llvm-path }}
run-tests: false
trace-commands: true

- name: Remove LLVM build-dir
if: steps.install_llvm.outcome == 'success'
run: |
rm -r ../third-party/llvm-project/llvm/llvm/build
rm -r ../third-party/llvm-project

- name: Install Duktape
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
with:
source-dir: ../third-party/duktape
url: https://github.com/svaarala/duktape/releases/download/v2.7.0/duktape-2.7.0.tar.xz
Expand All @@ -306,8 +360,8 @@ jobs:
build-dir: ${sourceDir}/build
cc: ${{ steps.setup-cpp.outputs.cc }}
cxx: ${{ steps.setup-cpp.outputs.cxx }}
ccflags: ${{ matrix.ccflags }}
cxxflags: ${{ matrix.cxxflags }}
ccflags: ${{ matrix.common-ccflags }}
cxxflags: ${{ matrix.common-cxxflags }}
build-type: ${{ matrix.build-type }}
shared: false
install: true
Expand All @@ -316,7 +370,7 @@ jobs:
trace-commands: true

- name: Install Libxml2
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
if: matrix.compiler == 'msvc'
with:
source-dir: ../third-party/libxml2
Expand All @@ -325,11 +379,12 @@ jobs:
build-dir: ${sourceDir}/build
cc: ${{ steps.setup-cpp.outputs.cc }}
cxx: ${{ steps.setup-cpp.outputs.cxx }}
ccflags: ${{ matrix.ccflags }}
cxxflags: ${{ matrix.cxxflags }}
ccflags: ${{ matrix.common-ccflags }}
cxxflags: ${{ matrix.common-cxxflags }}
build-type: Release
shared: false
extra-args: |
-D CMAKE_SHARED_LINKER_FLAGS="${{ matrix.common-ldflags }}"
-D LIBXML2_WITH_PROGRAMS=ON
-D LIBXML2_WITH_FTP=OFF
-D LIBXML2_WITH_HTTP=OFF
Expand Down Expand Up @@ -374,7 +429,7 @@ jobs:
node-version: '20'

- name: CMake Workflow
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
with:
cmake-version: '>=3.26'
cxxstd: ${{ matrix.cxxstd }}
Expand All @@ -388,11 +443,10 @@ jobs:
install-prefix: .local
extra-args: |
-D MRDOCS_BUILD_DOCS=OFF
-D CMAKE_EXE_LINKER_FLAGS=${{ matrix.mrdocs-linkflags }}
-D LLVM_ROOT=${{ steps.resolve-third-party-dir.outputs.third-party-dir }}/llvm-project/install
-D Clang_ROOT=${{ steps.resolve-third-party-dir.outputs.third-party-dir }}/llvm-project/install
-D duktape_ROOT=${{ steps.resolve-third-party-dir.outputs.third-party-dir }}/duktape/install
-D Duktape_ROOT=${{ steps.resolve-third-party-dir.outputs.third-party-dir }}/duktape/install
-D CMAKE_EXE_LINKER_FLAGS="${{ matrix.common-ldflags }}"
-D LLVM_ROOT="${{ matrix.llvm-path }}"
-D duktape_ROOT="${{ steps.resolve-third-party-dir.outputs.third-party-dir }}/duktape/install"
-D Duktape_ROOT="${{ steps.resolve-third-party-dir.outputs.third-party-dir }}/duktape/install"
${{ runner.os == 'Windows' && '-D libxml2_ROOT=../third-party/libxml2/install' || '' }}
${{ runner.os == 'Windows' && '-D LibXml2_ROOT=../third-party/libxml2/install' || '' }}
export-compile-commands: true
Expand Down Expand Up @@ -423,7 +477,7 @@ jobs:
retention-days: 1

- name: FlameGraph
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
if: matrix.time-trace
with:
build-dir: build
Expand Down Expand Up @@ -493,7 +547,7 @@ jobs:

steps:
- name: Install packages
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
id: package-install
with:
apt-get: build-essential asciidoctor cmake bzip2 git
Expand Down Expand Up @@ -555,7 +609,7 @@ jobs:
$MRDOCS_ROOT/bin/mrdocs --version

- name: Clone Boost.URL
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
id: boost-url-clone
with:
branch: develop
Expand Down Expand Up @@ -822,7 +876,7 @@ jobs:
scp -o StrictHostKeyChecking=no -r $(pwd)/demos/* [email protected]:$demo_dir/

- name: Create changelog
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
with:
output-path: CHANGELOG.md
thank-non-regular: ${{ startsWith(github.ref, 'refs/tags/') }}
Expand Down Expand Up @@ -864,7 +918,7 @@ jobs:

steps:
- name: Install packages
uses: alandefreitas/cpp-actions/[email protected].10
uses: alandefreitas/cpp-actions/[email protected].11
id: package-install
with:
apt-get: ${{ matrix.install }}
Expand All @@ -882,25 +936,12 @@ jobs:
fi
echo "exists=$exists" >> $GITHUB_OUTPUT

- name: Resolve LLVM Root
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here...

id: resolve-llvm-root
run: |
set -x
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
if: steps.website-releases.outputs.exists != 'true'
uses: actions/cache@v4
with:
path: ${{ steps.resolve-llvm-root.outputs.llvm-root }}
path: ${{ matrix.llvm-path }}
key: ${{ matrix.llvm-archive-basename }}

- name: Compress LLVM
Expand All @@ -910,20 +951,16 @@ jobs:
run: |
# LLVM is be installed with the default compiler
set -x

# Compress the LLVM installation
cd ../third-party/llvm-project


# Use 7z on windows
if [[ ${{ runner.os }} == 'Windows' ]]; then
7z a -t7z -m0=lzma2 -mx=9 -mfb=64 -md=32m -ms=on ${{ matrix.llvm-archive-filename }} install
7z a -t7z -m0=lzma2 -mx=9 -mfb=64 -md=32m -ms=on "${{ matrix.llvm-archive-filename }}" "${{ matrix.llvm-path }}"
else
tar -cjf ${{ matrix.llvm-archive-filename }} -C install .
tar -cjf "${{ matrix.llvm-archive-filename }}" -C "${{ matrix.llvm-path }}/.." llvm
fi

- name: Website LLVM Releases
if: steps.llvm-cache.outputs.cache-hit == 'true' && github.event_name == 'push' && (contains(fromJSON('["master", "develop"]'), github.ref_name) || startsWith(github.ref, 'refs/tags/'))
working-directory: ../third-party/llvm-project
run: |
set -x

Expand Down
Loading
Loading