GitHub Action
cmake swiss army knife
ghaction-cmake is a github action for projects that use cmake. By default, it builds, tests and installs the project - but it can as easily run linters, tests with coverage, valgrind or sanitizers, by using presets.
ghaction-cmake runs in phases:
- setup: optionally install dependencies and go to a specified directory.
- cmake: run cmake in an empty directory, pointing to the source directory, with all other arguments appended. This guarantees that out-of-tree builds work.
- build: customizable,
make VERBOSE=1
by default (build commands are shown). - test: customizable,
ctest .
by default. - post: customizable, empty by default.
Set a preset, more information on the Presets section below.
- Phase: can changes the default command of any number of phases.
Project dependencies as Debian packages to install in the container, separated by spaces.
- Phase: setup
- Preset behavior: unnafected.
Use this directory as the source dir for cmake. Mostly used when the cmake project is in a subdirectory of the repository.
- Phase: setup
- Preset behavior: unnafected.
Flags for cmake. -DSOME_OPTION=On
, for instance, to pass an option
to CMakeLists.txt.
- Phase: cmake
- Preset behavior: most presets append to this input.
Custom test command. Defaults to make VERBOSE=1
.
- Phase: build
- Preset behavior: some presets change or remove the default build command.
Custom test command. Defaults to ctest .
if no preset is used.
- Phase: test
- Preset behavior: some presets change or remove the default test command.
Custom command to run after tests. Empty by default, if no preset is used.
- Phase: post
- Preset behavior: some presets add a default post command.
cmake
is a very versatile tool that can do a lot of different things given
the appropriate arguments. To make matrix builds easier, ghaction-cmake
provides presets that configure those options for specific modes.
The available presets are:
-
cppcheck: run cppcheck static analysis.
- cmake: append
-DCMAKE_C/CXX_CPPCHECK=cppcheck
tocmakeflags
. - test: clear default.
- cmake: append
-
iwyu: run include-what-you-use static analysis.
- cmake: append
-DCMAKE_C/CXX_INCLUDE_WHAT_YOU_USE=iwyu
tocmakeflags
. - test: clear default.
- cmake: append
-
install: test installation.
- cmake: append
'-DCMAKE_INSTALL_PREFIX'
tocmakeflags
. - test: use
make install
as a test. - post: use
find
to show all installed files.
- cmake: append
-
clang-tidy: run clang-tidy static analysis.
- cmake: append
-DCMAKE_C/CXX_CLANG_TIDY=clang-tidy
tocmakeflags
. - test: clear default.
- cmake: append
-
clang-sanitize-<sanitizer>: compile with one of the clang sanitizers and run the tests.
- cmake: append
-DCMAKE_C/CXX_COMPILER=clang/clang++ -DCMAKE_C/CXX_FLAGS=-fno-omit-frame-pointer -fsanitize=<sanitizer>
tocmakeflags
.
- cmake: append
-
valgrind: run the tests with valgrind.
- test: set default test phase to
ctest -DExperimentalMemCheck .
- test: set default test phase to
-
coverage: runs the tests with coverage.
- cmake: append
-DCMAKE_C/CXX_FLAGS=--coverage
tocmakeflags
- post: set default post phase to run
lcov with
lcov -c -d . -o lcov.info
This preset works well with github actions that upload coverage data results to online services like codecov and coveralls. The example below shows how that can be done.
- cmake: append
The table below summarizes the changes specific to each preset:
Preset | cmake | test | post |
---|---|---|---|
cppcheck | -DCMAKE_C/CXX_CPPCHECK=cppcheck |
(delete) | |
iwyu | -DCMAKE_C/CXX_INCLUDE_WHAT_YOU_USE=iwyu |
(delete) | |
install | -DCMAKE_INSTALL_PREFIX=/tmp/_install |
make install |
find /tmp_install -type f |
clang‑tidy | -DCMAKE_C/CXX_CLANG_TIDY=clang-tidy |
(delete) | |
clang‑sanitizer‑<sanitizer> |
-DCMAKE_C/CXX_COMPILER=clang/clang++ -DCMAKE_C/CXX_FLAGS=-fno-omit-frame-pointer -fsanitize=<sanitizer> |
||
valgrind | -DExperimentalMemCheck |
||
coverage | -DCMAKE_C/CXX_FLAGS=--coverage |
lcov -c -d . -o lcov.info |
Keep in mind that presets override the defaults, and are overriden by
the other more specific inputs build_command
, test_command
and
post_command
.
The workflow below shows how to use presets in a matrix job:
---
name: CI
on: [push, pull_request]
jobs:
# Regular C build with two compilers, using the environment:
build_using_compiler_in_environment:
strategy:
matrix:
compiler:
- gcc
- clang
runs-on: ubuntu-latest
# We can use cmakeflags for this, or we can just use
# regular environment variables, as they are already
# supported by github actions:
env:
- CC: ${{ matrix.compiler }}
steps:
- uses: actions/checkout@master
- uses: docker://lpenz/ghaction-cmake:latest
# Regular C build with two compilers, using cmakeflags:
build_using_compiler_in_cmakeflags:
strategy:
matrix:
compiler:
- gcc
- clang
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
# This examples uses the appropriate cmakeflags
- uses: docker://lpenz/ghaction-cmake:latest
with:
cmakeflags: ${{ format('-DCMAKE_C_COMPILER={0}', matrix.compiler) }}
# Coverage with codecov:
codecov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: docker://lpenz/ghaction-cmake:latest
with:
preset: coverage
# ghaction-cmake works well with the github action
# provided by codecov:
- uses: codecov/codecov-action@v1
with:
fail_ci_if_error: true
# Coverage with coveralls:
coveralls:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: docker://lpenz/ghaction-cmake:latest
with:
preset: coverage
# ghaction-cmake works well with the github action
# provided by coveralls if you pass path-to-lcov:
- uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: lcov.info
# Static analyzers:
linters:
strategy:
matrix:
preset: [ cppcheck, iwyu, clang-tidy ]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: docker://lpenz/ghaction-cmake:latest
with:
preset: ${{ matrix.preset }}
# Tests with various sanitizers and valgrind:
test:
strategy:
matrix:
preset:
- clang-sanitizer-address
- clang-sanitizer-memory
- clang-sanitizer-undefined
- clang-sanitizer-dataflow
- clang-sanitizer-safe-stack
- valgrind
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: docker://lpenz/ghaction-cmake:latest
with:
preset: ${{ matrix.preset }}
# Test installation:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: docker://lpenz/ghaction-cmake:latest
with:
preset: install
Note that the file above splits static analyzers from sanitizers, but they can actually be in the same matrix job, as the rest of the parameters is the same.