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
10 changes: 5 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: Build and Test

on:
push:
branches: [ main ]
branches: [ master ]
pull_request:
branches: [ main ]
branches: [ master ]

jobs:
build:
Expand Down Expand Up @@ -68,7 +68,7 @@ jobs:
shell_tests: "ON"

- name: rel-clang-macos
os: macos-11
os: macos-latest
compiler: clang
scanbuild: ""
cflags: "-O3 -Wall -Wextra -Wshadow -Wunused-variable -Wunused-parameter -Wunused-function -Wunused -Wno-system-headers -Wno-deprecated -Wwrite-strings"
Expand All @@ -86,7 +86,7 @@ jobs:
AGENT_BUILDDIRECTORY: ${{ github.workspace }}/NIFTIworkspace
BUILD_SOURCESDIRECTORY: ${{ github.workspace }}
SYSTEM_PULLREQUEST_SOURCEBRANCH: ${{ github.head_ref }}
BUILD_SOURCEBRANCHNAME: ${{ github.head_ref }}
BUILD_SOURCEBRANCHNAME: ${{ github.head_ref || github.ref_name }}
BUILD_BUILDID: ${{ github.run_id }}
SYSTEM_PULLREQUEST_PULLREQUESTNUMBER: ${{ github.event.pull_request.number }}
CTEST_SCRIPT_DIRECTORY: ${{ github.workspace }}/cmake
Expand Down Expand Up @@ -131,5 +131,5 @@ jobs:

- name: Run CTest
run: |
eval $SCANBUILD_EXE ctest -S ${CTEST_SCRIPT_DIRECTORY}/travis_dashboard.cmake -V -j 4
eval $SCANBUILD_EXE ctest -S ${CTEST_SCRIPT_DIRECTORY}/github_dashboard.cmake -V -j 4

178 changes: 147 additions & 31 deletions .github/workflows/cmake-multi-platform.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,30 @@
# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
# Per-PR build and test matrix.
#
# Axes and why each one is here:
#
# os / c_compiler GNU, Clang and AppleClang. macOS has no gcc entry
# because /usr/bin/gcc there is a clang shim that
# reports AppleClang, so a macos+gcc leg duplicates
# the macos+clang leg exactly.
# shared BUILD_SHARED_LIBS also gates TEST_INSTALL, so the
# ON legs are the only ones that run install_linking
# and therefore the only ones covering the install
# and export path.
# fslstyle -DFSLSTYLE is not additive. It rewrites behaviour
# in niftilib and nifti2 through global -DFSLSTYLE,
# -DPIGZ and -DREJECT_COMPLEX definitions, and one of
# them has an #else that changes the pixdim[0] value
# written to disk (nifti1_io.c). Both values are
# real configurations and neither subsumes the other.
# build_type Debug turns assert() from a no-op into an abort,
# and the library has live assert() sites. One
# static Debug leg carries this; Debug is not a
# second pass over the other axes.
#
# The optional libraries (cifti, fsliolib) are built everywhere rather
# than being an axis of their own; they are additive, so ON covers OFF.
# The minimal-configuration job below covers the other direction.

name: CMake on multiple platforms

on:
Expand All @@ -10,73 +35,164 @@ on:

jobs:
build:
name: ${{ matrix.os }} ${{ matrix.c_compiler }} ${{ matrix.build_type }} shared=${{ matrix.shared }} fslstyle=${{ matrix.fslstyle }}
runs-on: ${{ matrix.os }}

strategy:
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
fail-fast: false

# Set up a matrix to run the following 3 configurations:
# 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator>
# 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator>
# 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator>
#
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
matrix:
os: [ubuntu-latest, macos-latest]
build_type: [Release]
c_compiler: [gcc, clang]
# 'default' is what a consumer gets with no options; 'all' turns on
# the optional libraries and the FSL parity defines, which are the
# code paths no workflow compiled before.
options: [default, all]
build_type: [Release]
shared: ["OFF", "ON"]
fslstyle: ["OFF", "ON"]
include:
- os: macos-latest
c_compiler: clang
cpp_compiler: clang++
- os: ubuntu-latest
c_compiler: gcc
cpp_compiler: g++
- os: ubuntu-latest
c_compiler: clang
cpp_compiler: clang++
exclude:
- os: macos-latest
c_compiler: clang
cpp_compiler: clang++
# One Debug leg, static. Debug exists to make assert()
# live, not to re-cover the linkage or platform axes, so a
# single configuration carries it. FSLSTYLE is ON so the
# assert() sites behind those defines are reachable too.
- os: ubuntu-latest
c_compiler: cl
c_compiler: gcc
cpp_compiler: g++
build_type: Debug
shared: "OFF"
fslstyle: "ON"
exclude:
# /usr/bin/gcc on macOS is a clang shim; this leg would be an
# exact duplicate of the macos clang leg.
- os: macos-latest
c_compiler: gcc

steps:
- uses: actions/checkout@v4

- name: Install optional dependencies
# cifti needs expat; only the 'all' configuration builds it.
if: runner.os == 'Linux' && matrix.options == 'all'
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y libexpat1-dev zlib1g-dev

- name: Set reusable strings
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
run: echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"

- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
${{ matrix.options == 'all' && '-DUSE_CIFTI_CODE=ON -DUSE_FSL_CODE=ON -DFSLSTYLE=ON' || '' }}
-DBUILD_SHARED_LIBS=${{ matrix.shared }}
-DUSE_CIFTI_CODE=ON
-DUSE_FSL_CODE=ON
-DFSLSTYLE=${{ matrix.fslstyle }}
-S ${{ github.workspace }}

- name: Build
# Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}

- name: Test
working-directory: ${{ steps.strings.outputs.build-output-dir }}
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest --build-config ${{ matrix.build_type }} --output-on-failure

minimal:
# The configuration a downstream project vendoring only the core
# reader selects. Nothing else in the matrix proves the tree still
# configures with the optional subdirectories switched off.
name: minimal configuration (znzlib + niftilib only)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure CMake
run: >
cmake -B ${{ github.workspace }}/build
-DCMAKE_BUILD_TYPE=Release
-DUSE_NIFTI2_CODE=OFF
-DUSE_NIFTICDF_CODE=OFF
-DUSE_CIFTI_CODE=OFF
-DUSE_FSL_CODE=OFF
-DNIFTI_BUILD_APPLICATIONS=OFF
-S ${{ github.workspace }}
- name: Build
run: cmake --build ${{ github.workspace }}/build
- name: Test
working-directory: ${{ github.workspace }}/build
# This configuration registers no tests at all, because the test
# programs live with the applications that are switched off here.
# --no-tests=ignore keeps that from being an error; the value of
# this job is that the tree still configures and builds.
run: ctest --output-on-failure --no-tests=ignore

oldest-cmake:
# Guards cmake_minimum_required. Every other runner carries a
# recent CMake, so a policy or command that needs a newer release
# than the project claims to support is invisible to them.
# PR #30 was exactly that: CMP0169 does not exist before 3.30 and
# setting it unconditionally was fatal on Ubuntu 24.04's 3.28.
name: oldest supported CMake
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y cmake ninja-build libexpat1-dev zlib1g-dev
- name: Show CMake version
run: cmake --version
- name: Configure CMake
run: >
cmake -G Ninja -B ${{ github.workspace }}/build
-DCMAKE_BUILD_TYPE=Release
-DUSE_CIFTI_CODE=ON
-DUSE_FSL_CODE=ON
-S ${{ github.workspace }}
- name: Build
run: cmake --build ${{ github.workspace }}/build
- name: Test
working-directory: ${{ github.workspace }}/build
run: ctest --output-on-failure

exported-symbols:
# The exported symbol set is the ABI. Several open changes assert
# that they leave it untouched and nothing verified that claim, so
# this job diffs it against a committed baseline. An intentional
# change to the ABI updates the baseline in the same commit, which
# makes the change visible in review rather than implicit.
name: exported symbol baseline
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: sudo apt-get update && sudo apt-get install -y libexpat1-dev zlib1g-dev ninja-build
- name: Configure CMake
run: >
cmake -G Ninja -B ${{ github.workspace }}/build
-DCMAKE_BUILD_TYPE=Release
-DBUILD_SHARED_LIBS=ON
-DUSE_CIFTI_CODE=ON
-DUSE_FSL_CODE=ON
-S ${{ github.workspace }}
- name: Build
run: cmake --build ${{ github.workspace }}/build
- name: Collect exported symbols
run: |
bash cmake/collect_exported_symbols.sh \
"${{ github.workspace }}/build" \
/tmp/exported_symbols.txt
- name: Compare against the committed baseline
run: |
if ! diff -u cmake/exported_symbols_linux.txt /tmp/exported_symbols.txt; then
echo ""
echo "The exported symbol set changed."
echo "If that is intended, update cmake/exported_symbols_linux.txt"
echo "in this commit so the ABI change is visible in review:"
echo " bash cmake/collect_exported_symbols.sh <build-dir> cmake/exported_symbols_linux.txt"
exit 1
fi
echo "Exported symbols match the baseline."
60 changes: 60 additions & 0 deletions cmake/collect_exported_symbols.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/bin/sh
# Collect the dynamic symbols exported by the built shared libraries.
#
# collect_exported_symbols.sh <build-dir> <output-file>
#
# The output is sorted "<library> <symbol>" lines, so a diff against the
# committed baseline names both the library and the symbol that moved.
#
# The library name is reported with any version suffix stripped, so a
# SOVERSION bump does not rewrite every line of the baseline:
# libniftiio.so.3.0.0 is reported as libniftiio.so.
#
# Regenerate the baseline after an intended ABI change:
# cmake -B build -DBUILD_SHARED_LIBS=ON -DUSE_CIFTI_CODE=ON -DUSE_FSL_CODE=ON
# cmake --build build
# sh cmake/collect_exported_symbols.sh build cmake/exported_symbols_linux.txt

set -eu

if [ $# -ne 2 ]; then
echo "usage: $0 <build-dir> <output-file>" >&2
exit 2
fi

build_dir=$1
output=$2

if [ ! -d "$build_dir" ]; then
echo "$0: no such build directory: $build_dir" >&2
exit 1
fi

# Match versioned sonames too (libfoo.so.3.0.0), and resolve symlinks so
# libfoo.so -> libfoo.so.3.0.0 is not counted twice.
libs=$(find "$build_dir" -name 'lib*.so*' -exec readlink -f {} \; \
| LC_ALL=C sort -u)

if [ -z "$libs" ]; then
echo "$0: no shared libraries under $build_dir;" \
"configure with -DBUILD_SHARED_LIBS=ON" >&2
exit 1
fi

: > "$output.tmp"

for lib in $libs; do
# libniftiio.so.3.0.0 -> libniftiio.so
name=$(basename "$lib" | sed -E 's/\.so(\.[0-9]+)*$/.so/')
# -D dynamic symbols, --defined-only drops imports; field 3 is the name.
nm -D --defined-only "$lib" \
| awk 'NF >= 3 { print $3 }' \
| grep -v '^$' \
| sed "s|^|$name |" >> "$output.tmp"
done

LC_ALL=C sort -u "$output.tmp" > "$output"
rm -f "$output.tmp"

echo "$0: wrote $(wc -l < "$output") symbols from" \
"$(awk '{print $1}' "$output" | LC_ALL=C sort -u | wc -l) libraries to $output"
Loading
Loading