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=1by default (build commands are shown). - test: customizable,
ctest --output-on-failure .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.
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: unaffected.
Custom command to run before dependencies are installed. Use this to add third-party Debian repositories or increment the setup phase in other ways.
- Phase: setup
- Preset behavior: unaffected.
Project dependencies as Debian packages to install in the container, separated by spaces.
- Phase: setup
- Preset behavior: unaffected.
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 --output-on-failure . 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=cppchecktocmakeflags. - test: clear default.
- cmake: append
-
iwyu: run include-what-you-use static analysis.
- cmake: append
-DCMAKE_C/CXX_INCLUDE_WHAT_YOU_USE=iwyutocmakeflags. - test: clear default.
- cmake: append
-
install: test installation.
- cmake: append
'-DCMAKE_INSTALL_PREFIX'tocmakeflags. - test: use
make installas a test. - post: use
findto show all installed files.
- cmake: append
-
clang-tidy: run clang-tidy static analysis.
- cmake: append
-DCMAKE_C/CXX_CLANG_TIDY=clang-tidytocmakeflags. - 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
-
gcc-sanitize-<sanitizer>: compile with one of the gcc sanitizers and run the tests.
- cmake: append
-DCMAKE_C/CXX_COMPILER=gcc/g++ -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 --output-on-failure .
- test: set default test phase to
-
cpack: runs cpack after the build.
- test: cpack
-
coverage: runs the tests with coverage.
- cmake: append
-DCMAKE_C/CXX_FLAGS=--coveragetocmakeflags - 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‑sanitize‑<sanitizer> |
-DCMAKE_C/CXX_COMPILER=clang/clang++ -DCMAKE_C/CXX_FLAGS=-fno-omit-frame-pointer -fsanitize=<sanitizer> |
||
| valgrind | -DExperimentalMemCheck |
||
| cpack | cpack |
||
| 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, g++]
- [clang, 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[0] }}
- CXX: ${{ matrix.compiler[1] }}
steps:
- uses: actions/checkout@v2
- uses: docker://lpenz/ghaction-cmake:0.21.2
# 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@v2
# This examples uses the appropriate cmakeflags
- uses: docker://lpenz/ghaction-cmake:0.21.2
with:
cmakeflags: ${{ format('-DCMAKE_C_COMPILER={0}', matrix.compiler) }}
# Coverage with codecov:
codecov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: docker://lpenz/ghaction-cmake:0.21.2
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@v2
- uses: docker://lpenz/ghaction-cmake:0.21.2
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@v2
- uses: docker://lpenz/ghaction-cmake:0.21.2
with:
preset: ${{ matrix.preset }}
# Tests with various sanitizers and valgrind:
test:
strategy:
matrix:
preset:
- clang-sanitize-address
- clang-sanitize-memory
- clang-sanitize-undefined
- clang-sanitize-dataflow
- clang-sanitize-safe-stack
- valgrind
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: docker://lpenz/ghaction-cmake:0.21.2
with:
preset: ${{ matrix.preset }}
# Test installation:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: docker://lpenz/ghaction-cmake:0.21.2
with:
preset: install
# Create the .deb in Ubuntu Jammy:
install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: docker://lpenz/ghaction-cmake:0.21.2-ubuntu-jammy-amd64
with:
preset: cpackNote 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.
This github action is actually a docker image that can be used locally or even in travis-ci. To do that, first download the image from docker hub:
docker pull lpenz/ghaction-cmake:0.16Then, run a container in the project's directory, for instance:
docker run --rm -t -u "$UID" -w "$PWD" -v "${PWD}:${PWD}" -e INPUT_PRESET=valgrind lpenz/ghaction-cmake:0.16It's worth pointing out that action parameters are passed as
upper case environment variables, prefixed with INPUT_.
The following .travis.yml runs the same thing in travis-ci:
---
language: generic
jobs:
include:
- install: docker pull lpenz/ghaction-cmake:0.16
- script: docker run --rm -t -u "$UID" -w "$PWD" -v "${PWD}:${PWD}" -e INPUT_PRESET=valgrind lpenz/ghaction-cmake:0.16