Skip to content
Merged
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
8 changes: 1 addition & 7 deletions .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,7 @@ ignore:
- "build/_deps/**/*"
- "test/**/*"

# Strip the GitHub Actions container-mount prefix (/__w/<owner>/<repo>/)
# from paths emitted by gcovr --root "$GITHUB_WORKSPACE".
# Without this, Codecov cannot match coverage lines to repo files.
fixes:
- "/__w/git-wip/git-wip/::"

comment:
layout: "reach,diff,flags,files,footer"
behavior: default
require_changes: no
require_changes: no
36 changes: 8 additions & 28 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ jobs:
retention-days: 7

coverage:
name: Coverage (debian:stable / clang / Debug)
name: Coverage (debian:stable / gcc / Debug)

runs-on: ubuntu-latest

Expand All @@ -206,7 +206,7 @@ jobs:
- name: Install dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: bash dependencies.sh --compiler=clang
run: bash dependencies.sh --compiler=gcc --coverage

- name: Cache CMake FetchContent (spdlog, clipp, fmt)
uses: actions/cache@v5
Expand All @@ -222,39 +222,19 @@ jobs:
git config --global user.name "GitHub Actions"
git config --global init.defaultBranch master

- name: Build with coverage
- name: Build, test, and collect coverage
env:
CC: clang
CXX: clang++
CC: gcc
CXX: g++
CI: "1"
COVERAGE: "1"
run: make TYPE=Debug test

- name: Collect coverage data
run: |
gcovr --cobertura coverage.xml \
--gcov-executable 'llvm-cov gcov' \
--gcov-ignore-errors=no_working_dir_found \
--exclude 'build/_deps/' \
--exclude 'test/' \
--root "$GITHUB_WORKSPACE"

- name: Verify coverage file
run: |
ls -la coverage.xml
head -50 coverage.xml

- name: Install codecov dependencies
env:
DEBIAN_FRONTEND: noninteractive
run: apt-get update && apt-get install -y curl gpg
run: make CC=gcc CXX=g++ TYPE=Debug coverage REBUILD=1

- name: Upload to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.xml
files: ./coverage.info
flags: unittests
name: debian-stable-clang-debug
name: debian-stable-gcc-debug
verbose: true
fail_ci_if_error: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ build/

coverage-report/
coverage.xml
coverage.info

### C++
# Prerequisites
Expand Down
14 changes: 9 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
# Enable generation of compile_commands.json
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Code coverage options
option(WIP_COVERAGE "Enable code coverage instrumentation" OFF)
if(WIP_COVERAGE)
add_compile_options(-fprofile-arcs -ftest-coverage)
add_link_options(-fprofile-arcs -ftest-coverage)
endif()

include(FetchContent)
include(CheckCXXSourceCompiles)
Expand All @@ -26,6 +21,15 @@ FetchContent_Declare(

FetchContent_MakeAvailable(spdlog)

# Code coverage options — applied AFTER FetchContent so that third-party
# dependencies (spdlog, fmt, …) are NOT instrumented. Mixing gcov versions
# between the host compiler and a pre-built dep causes "version mismatch"
# errors at runtime that pollute test output.
if(WIP_COVERAGE)
add_compile_options(-fprofile-arcs -ftest-coverage)
add_link_options(-fprofile-arcs -ftest-coverage)
endif()

# Detect whether the compiler's standard library ships <print> (C++23 P2093).
# GCC < 14 and some older clangs lack it even with -std=c++23.
check_cxx_source_compiles("
Expand Down
35 changes: 31 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ NPROC ?= $(shell nproc || echo 1)
CC ?= $(shell which clang gcc cc | head -n1)
CXX ?= $(shell which clang g++ c++ | head -n1)
COVERAGE ?= false
# Locate the right gcov-compatible tool to match the compiler:
# - if CC is clang, use llvm-cov (prefer plain symlink, fall back to versioned)
# - otherwise use plain gcov
# Use = (recursive) not := (immediate) so CC override on the command line is respected.
_IS_CLANG = $(shell $(CC) --version 2>/dev/null | grep -c clang)
GCOV_TOOL = $(if $(filter 1,$(_IS_CLANG)),$(shell which llvm-cov 2>/dev/null || ls /usr/bin/llvm-cov-* 2>/dev/null | sort -V | tail -1) gcov,gcov)
$(info ## TYPE=${TYPE} CC=${CC} CXX=${CXX} COVERAGE=${COVERAGE})

# Coverage flag for CMake
Expand Down Expand Up @@ -61,13 +67,34 @@ test: ## run unit tests (with ctest, uses REBUILD={true,false}, COVERAGE={true,f
${Q}cd "${BUILD}"/ && ctest -C "${TYPE}" $(if ${CI},--output-on-failure -VV)
${Q}echo " ✅ Unit tests complete."

coverage: ## check code coverage (with gcovr, uses REBUILD={true,false})
coverage: ## check code coverage (with lcov, uses REBUILD={true,false})
${Q}$(if $(filter 1 yes true YES TRUE,${REBUILD}),rm -rf "${BUILD}"/)
${Q}${CMAKE} -G ${GENERATOR} -S. -B${BUILD} -DCMAKE_INSTALL_PREFIX="$(PREFIX)" -DCMAKE_BUILD_TYPE="${TYPE}" -DWIP_COVERAGE=ON
${Q}${CMAKE} -G ${GENERATOR} -S. -B${BUILD} -DCMAKE_INSTALL_PREFIX="$(PREFIX)" -DCMAKE_BUILD_TYPE="${TYPE}" -DWIP_COVERAGE=ON -DCMAKE_C_COMPILER="${CC}" -DCMAKE_CXX_COMPILER="${CXX}"
${Q}${CMAKE} --build "${BUILD}" --config "${TYPE}" --parallel "${NPROC}"
${Q}cd "${BUILD}"/ && ctest -C "${TYPE}" -VV
${Q}cd "${BUILD}"/ && ctest -C "${TYPE}" $(if ${CI},--output-on-failure -VV)
${Q}printf '#!/bin/sh\nexec $(GCOV_TOOL) "$$@"\n' > "${BUILD}/gcov-tool.sh" && chmod +x "${BUILD}/gcov-tool.sh"
${Q}lcov --capture --directory "${BUILD}/src" \
--directory "${BUILD}/test" \
--gcov-tool "${BUILD}/gcov-tool.sh" \
--ignore-errors inconsistent \
--ignore-errors inconsistent \
--ignore-errors format \
--ignore-errors unsupported \
--output-file coverage.info
${Q}lcov --remove coverage.info '/usr/*' '*/test/*' \
--ignore-errors inconsistent \
--ignore-errors inconsistent \
--ignore-errors format \
--ignore-errors unsupported \
--ignore-errors corrupt \
--output-file coverage.info
${Q}mkdir -p coverage-report
${Q}gcovr --html coverage-report/index.html --root . "${BUILD}"
${Q}genhtml coverage.info --output-directory coverage-report \
--ignore-errors inconsistent \
--ignore-errors inconsistent \
--ignore-errors corrupt \
--ignore-errors unsupported \
--ignore-errors category
${Q}echo " ✅ Coverage report generated in coverage-report/"

install: ## install the package (to the `PREFIX`, uses REBUILD={true,false})
Expand Down
25 changes: 21 additions & 4 deletions dependencies.sh
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ function want_one_of() {
# ---------------------------------------------------------------------------

compiler="" # empty → auto-select via must_have_one_of
coverage=0 # --coverage → install lcov, curl, gpg

for arg in "$@" ; do
case "$arg" in
Expand All @@ -122,9 +123,11 @@ for arg in "$@" ; do
--compiler=clang) compiler=clang ;;
--compiler=*)
die "unknown --compiler value '${arg#--compiler=}' (expected gcc or clang)" ;;
--coverage)
coverage=1 ;;
-h|--help)
cat <<'EOF'
Usage: dependencies.sh [--compiler=<gcc|clang>] [-h|--help]
Usage: dependencies.sh [--compiler=<gcc|clang>] [--coverage] [-h|--help]

Install build dependencies for git-wip.

Expand All @@ -133,6 +136,8 @@ Options:
--compiler=clang Install clang
(no flag) Install whichever of clang/gcc is available (auto-select)

--coverage Also install coverage tools (lcov, curl, gpg)

-h, --help Show this help and exit
EOF
exit 0
Expand Down Expand Up @@ -205,22 +210,19 @@ case "$pkg_mgr" in
libgmock-dev
libgtest-dev
libgit2-dev
gcovr
)
;;
dnf)
packages+=(
gtest-devel
gmock-devel
libgit2-devel
gcovr
)
;;
pacman)
# Arch uses different package names
packages+=(
libgit2
gcovr
)
# Replace base packages with Arch equivalents
packages=( "${packages[@]/ninja-build/ninja}" )
Expand All @@ -233,6 +235,21 @@ case "$pkg_mgr" in
;;
esac

# Coverage tools (only when --coverage is requested)
if [ "$coverage" = 1 ]; then
case "$pkg_mgr" in
apt)
packages+=( lcov curl gpg )
;;
dnf)
packages+=( lcov curl gnupg2 )
;;
pacman)
packages+=( lcov curl gnupg )
;;
esac
fi

set -e -x

case "$pkg_mgr" in
Expand Down