/ghaction-cmake

cmake swiss army knife github docker action

Primary LanguagePythonMIT LicenseMIT

marketplace CI github docker

ghaction-cmake

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.

Phases

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 --output-on-failure . by default.
  • post: customizable, empty by default.

Inputs

preset

Set a preset, more information on the Presets section below.

  • Phase: can changes the default command of any number of phases.

dependencies_debian

Project dependencies as Debian packages to install in the container, separated by spaces.

  • Phase: setup
  • Preset behavior: unnafected.

working-directory

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.

cmakeflags

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.

build_command

Custom test command. Defaults to make VERBOSE=1.

  • Phase: build
  • Preset behavior: some presets change or remove the default build command.

test_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.

post_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.

Presets

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 to cmakeflags.
    • test: clear default.
  • iwyu: run include-what-you-use static analysis.

    • cmake: append -DCMAKE_C/CXX_INCLUDE_WHAT_YOU_USE=iwyu to cmakeflags.
    • test: clear default.
  • install: test installation.

    • cmake: append '-DCMAKE_INSTALL_PREFIX' to cmakeflags.
    • test: use make install as a test.
    • post: use find to show all installed files.
  • clang-tidy: run clang-tidy static analysis.

    • cmake: append -DCMAKE_C/CXX_CLANG_TIDY=clang-tidy to cmakeflags.
    • test: clear default.
  • 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> to cmakeflags.
  • valgrind: run the tests with valgrind.

    • test: set default test phase to ctest -DExperimentalMemCheck --output-on-failure .
  • coverage: runs the tests with coverage.

    • cmake: append -DCMAKE_C/CXX_FLAGS=--coverage to cmakeflags
    • 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.

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.

Example:

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:v0.9
  # 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:v0.9
        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:v0.9
        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:v0.9
        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:v0.9
        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:v0.9
        with:
          preset: ${{ matrix.preset }}
  # Test installation:
  install:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@master
      - uses: docker://lpenz/ghaction-cmake:v0.9
        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.

Using in other environments

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:v0.9

Then, 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:v0.9

It'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:v0.9
    - script: docker run --rm -t -u "$UID" -w "$PWD" -v "${PWD}:${PWD}" -e INPUT_PRESET=valgrind lpenz/ghaction-cmake:v0.9