From a8ef432e684d2910022719bd14e21a2adaef84f1 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 21 Sep 2026 13:10:46 -0500 Subject: [PATCH 1/3] COMP: Widen CI coverage across platforms, linkage, and configurations Run the Build and Test workflow on this repository's branch. Its trigger named "main" while the branch is "master", so it had never executed on master and did not execute on pull requests; valgrind, AddressSanitizer, UndefinedBehaviorSanitizer, scan-build, gcov coverage, and the only shared-library configuration were all unexercised. Also move its macOS entry off the retired macos-11 image. Restructure the per-PR matrix around the axes that change what is compiled: shared BUILD_SHARED_LIBS gates TEST_INSTALL, so the ON legs are the first to run install_linking and cover the install and export path. fslstyle -DFSLSTYLE is not additive. It rewrites behaviour in niftilib and nifti2 through global -DFSLSTYLE, -DPIGZ and -DREJECT_COMPLEX, and one site has an #else that changes the pixdim[0] value written to disk. Neither value subsumes the other. build_type One static Debug leg, which is what makes assert() live. Drop both macos gcc legs: /usr/bin/gcc there is a clang shim reporting AppleClang, so they duplicated the macos clang legs exactly. The optional libraries are built everywhere rather than forming an axis, since they are additive. Add three jobs. The minimal configuration builds znzlib and niftilib alone, which is what a downstream project vendoring the core reader selects and which nothing else configures. The oldest supported CMake job guards cmake_minimum_required, invisible to runners that all carry a recent CMake. The exported symbol baseline diffs the dynamic symbol set against a committed file, so a change to the ABI has to be updated in the same commit rather than landing unnoticed. Verified on Ubuntu 24.04 with GCC 13.3.0, the compiler the Linux runners use: shared, Release, FSLSTYLE=OFF 345/345, install_linking passed static, Debug, FSLSTYLE=ON 344/344, no assertion aborts minimal configures and builds, no tests CMake 3.28.3 344/344 The baseline holds 448 symbols across six libraries, which is the figure the linkage changes have been asserting without a way to check it. The workflow steps were exercised by running them directly in the runner container image rather than through act, whose image omits cmake. --- .github/workflows/build.yml | 6 +- .github/workflows/cmake-multi-platform.yml | 178 ++++++-- cmake/collect_exported_symbols.sh | 60 +++ cmake/exported_symbols_linux.txt | 448 +++++++++++++++++++++ 4 files changed, 658 insertions(+), 34 deletions(-) create mode 100755 cmake/collect_exported_symbols.sh create mode 100644 cmake/exported_symbols_linux.txt diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4c82448d..2a5a8922 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,9 +2,9 @@ name: Build and Test on: push: - branches: [ main ] + branches: [ master ] pull_request: - branches: [ main ] + branches: [ master ] jobs: build: @@ -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" diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 21d0cad3..68197e71 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -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: @@ -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. - # 2. - # 3. - # - # 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 cmake/exported_symbols_linux.txt" + exit 1 + fi + echo "Exported symbols match the baseline." diff --git a/cmake/collect_exported_symbols.sh b/cmake/collect_exported_symbols.sh new file mode 100755 index 00000000..2cdae6c0 --- /dev/null +++ b/cmake/collect_exported_symbols.sh @@ -0,0 +1,60 @@ +#!/bin/sh +# Collect the dynamic symbols exported by the built shared libraries. +# +# collect_exported_symbols.sh +# +# The output is sorted " " 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 " >&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" diff --git a/cmake/exported_symbols_linux.txt b/cmake/exported_symbols_linux.txt new file mode 100644 index 00000000..14effdcd --- /dev/null +++ b/cmake/exported_symbols_linux.txt @@ -0,0 +1,448 @@ +libcifti.so axio_cifti_from_ext +libcifti.so axio_find_map_name +libcifti.so axio_num_tokens +libcifti.so axio_read_buf +libcifti.so axio_read_cifti_file +libcifti.so axio_read_file +libcifti.so axio_show_attrs +libcifti.so axio_show_cifti_summary +libcifti.so axio_show_mim_summary +libcifti.so axio_text_to_binary +libcifti.so axml_add_attrs +libcifti.so axml_attr_value +libcifti.so axml_disp_xlist +libcifti.so axml_disp_xml_t +libcifti.so axml_free_xlist +libcifti.so axml_free_xml_t +libcifti.so axml_get_buf_size +libcifti.so axml_get_dstore +libcifti.so axml_get_indent +libcifti.so axml_get_verb +libcifti.so axml_get_wstream +libcifti.so axml_read_buf +libcifti.so axml_read_file +libcifti.so axml_recur +libcifti.so axml_recur_find_xml +libcifti.so axml_set_buf_size +libcifti.so axml_set_dstore +libcifti.so axml_set_indent +libcifti.so axml_set_verb +libcifti.so axml_set_wstream +libcifti.so new_afni_xml +libfslio.so AvwSwapHeader +libfslio.so FslBaseFileType +libfslio.so FslCheckForMultipleFileNames +libfslio.so FslCloneHeader +libfslio.so FslClose +libfslio.so FslFileExists +libfslio.so FslFileType +libfslio.so FslFileTypeString +libfslio.so FslGetAnalyzeOrigin +libfslio.so FslGetAuxFile +libfslio.so FslGetBufferAsScaledDouble +libfslio.so FslGetCalMinMax +libfslio.so FslGetDataType +libfslio.so FslGetDim +libfslio.so FslGetDimensionality +libfslio.so FslGetEnvOutputType +libfslio.so FslGetFileType +libfslio.so FslGetFileType2 +libfslio.so FslGetHdrImgNames +libfslio.so FslGetIgnoreMFQ +libfslio.so FslGetIntensityScaling +libfslio.so FslGetIntent +libfslio.so FslGetLeftRightOrder +libfslio.so FslGetMMCoord +libfslio.so FslGetOverrideOutputType +libfslio.so FslGetReadFileType +libfslio.so FslGetRigidXform +libfslio.so FslGetStdXform +libfslio.so FslGetTimeUnits +libfslio.so FslGetVolSize +libfslio.so FslGetVolumeAsScaledDouble +libfslio.so FslGetVoxCoord +libfslio.so FslGetVoxDim +libfslio.so FslGetVoxUnits +libfslio.so FslGetWriteMode +libfslio.so FslInit +libfslio.so FslInit4Write +libfslio.so FslInitHeader +libfslio.so FslIsCompressedFileType +libfslio.so FslIsSingleFileType +libfslio.so FslIsValidFileType +libfslio.so FslMakeBaseName +libfslio.so FslOpen +libfslio.so FslReadAllVolumes +libfslio.so FslReadHeader +libfslio.so FslReadRawHeader +libfslio.so FslReadRowSeries +libfslio.so FslReadSliceSeries +libfslio.so FslReadTimeSeries +libfslio.so FslReadVolumes +libfslio.so FslSeekVolume +libfslio.so FslSetAnalyzeSform +libfslio.so FslSetAuxFile +libfslio.so FslSetCalMinMax +libfslio.so FslSetDataType +libfslio.so FslSetDim +libfslio.so FslSetDimensionality +libfslio.so FslSetFileType +libfslio.so FslSetIgnoreMFQ +libfslio.so FslSetInit +libfslio.so FslSetIntensityScaling +libfslio.so FslSetIntent +libfslio.so FslSetOverrideOutputType +libfslio.so FslSetRigidXform +libfslio.so FslSetStdXform +libfslio.so FslSetTimeUnits +libfslio.so FslSetVoxDim +libfslio.so FslSetVoxUnits +libfslio.so FslSetWriteMode +libfslio.so FslWriteAllVolumes +libfslio.so FslWriteHeader +libfslio.so FslWriteVolumes +libfslio.so FslXOpen +libfslio.so check_for_multiple_filenames +libfslio.so convertBufferToScaledDouble +libfslio.so d3matrix +libfslio.so d4matrix +libfslio.so fsl_fileexists +libfslio.so mat44_to_mat33 +libnifti2.so disp_nifti_1_header +libnifti2.so disp_nifti_2_header +libnifti2.so is_nifti_file +libnifti2.so is_valid_nifti_type +libnifti2.so nifti1_magic +libnifti2.so nifti2_magic +libnifti2.so nifti_add_extension +libnifti2.so nifti_alter_cifti_dims +libnifti2.so nifti_compiled_with_zlib +libnifti2.so nifti_convert_n1hdr2nim +libnifti2.so nifti_convert_n2hdr2nim +libnifti2.so nifti_convert_nim2n1hdr +libnifti2.so nifti_convert_nim2n2hdr +libnifti2.so nifti_copy_extensions +libnifti2.so nifti_copy_nim_info +libnifti2.so nifti_datatype_from_string +libnifti2.so nifti_datatype_is_valid +libnifti2.so nifti_datatype_sizes +libnifti2.so nifti_datatype_string +libnifti2.so nifti_datatype_to_string +libnifti2.so nifti_disp_lib_hist +libnifti2.so nifti_disp_lib_version +libnifti2.so nifti_disp_matrix_orient +libnifti2.so nifti_disp_type_list +libnifti2.so nifti_dmat33_colnorm +libnifti2.so nifti_dmat33_determ +libnifti2.so nifti_dmat33_inverse +libnifti2.so nifti_dmat33_mul +libnifti2.so nifti_dmat33_polar +libnifti2.so nifti_dmat33_rownorm +libnifti2.so nifti_dmat44_inverse +libnifti2.so nifti_dmat44_mul +libnifti2.so nifti_dmat44_to_mat44 +libnifti2.so nifti_dmat44_to_orientation +libnifti2.so nifti_dmat44_to_quatern +libnifti2.so nifti_fileexists +libnifti2.so nifti_find_file_extension +libnifti2.so nifti_findhdrname +libnifti2.so nifti_findimgname +libnifti2.so nifti_free_NBL +libnifti2.so nifti_free_extensions +libnifti2.so nifti_get_alter_cifti +libnifti2.so nifti_get_filesize +libnifti2.so nifti_get_int64list +libnifti2.so nifti_get_intlist +libnifti2.so nifti_get_volsize +libnifti2.so nifti_hdr1_looks_good +libnifti2.so nifti_hdr2_looks_good +libnifti2.so nifti_header_version +libnifti2.so nifti_image_free +libnifti2.so nifti_image_from_ascii +libnifti2.so nifti_image_infodump +libnifti2.so nifti_image_load +libnifti2.so nifti_image_load_bricks +libnifti2.so nifti_image_open +libnifti2.so nifti_image_read +libnifti2.so nifti_image_read_bricks +libnifti2.so nifti_image_to_ascii +libnifti2.so nifti_image_unload +libnifti2.so nifti_image_write +libnifti2.so nifti_image_write_bricks +libnifti2.so nifti_image_write_bricks_status +libnifti2.so nifti_image_write_hdr_img +libnifti2.so nifti_image_write_hdr_img2 +libnifti2.so nifti_image_write_status +libnifti2.so nifti_intent_string +libnifti2.so nifti_is_complete_filename +libnifti2.so nifti_is_gzfile +libnifti2.so nifti_is_inttype +libnifti2.so nifti_is_valid_datatype +libnifti2.so nifti_is_valid_ecode +libnifti2.so nifti_looks_like_cifti +libnifti2.so nifti_make_new_n1_header +libnifti2.so nifti_make_new_n2_header +libnifti2.so nifti_make_new_nim +libnifti2.so nifti_make_orthog_dmat44 +libnifti2.so nifti_make_orthog_mat44 +libnifti2.so nifti_makebasename +libnifti2.so nifti_makehdrname +libnifti2.so nifti_makeimgname +libnifti2.so nifti_mat33_colnorm +libnifti2.so nifti_mat33_determ +libnifti2.so nifti_mat33_inverse +libnifti2.so nifti_mat33_mul +libnifti2.so nifti_mat33_polar +libnifti2.so nifti_mat33_rownorm +libnifti2.so nifti_mat44_inverse +libnifti2.so nifti_mat44_mul +libnifti2.so nifti_mat44_to_dmat44 +libnifti2.so nifti_mat44_to_orientation +libnifti2.so nifti_mat44_to_quatern +libnifti2.so nifti_nim_has_valid_dims +libnifti2.so nifti_nim_is_valid +libnifti2.so nifti_orientation_string +libnifti2.so nifti_quatern_to_dmat44 +libnifti2.so nifti_quatern_to_mat44 +libnifti2.so nifti_read_ascii_image +libnifti2.so nifti_read_buffer +libnifti2.so nifti_read_collapsed_image +libnifti2.so nifti_read_header +libnifti2.so nifti_read_n1_hdr +libnifti2.so nifti_read_n2_hdr +libnifti2.so nifti_read_subregion_image +libnifti2.so nifti_set_allow_upper_fext +libnifti2.so nifti_set_alter_cifti +libnifti2.so nifti_set_debug_level +libnifti2.so nifti_set_filenames +libnifti2.so nifti_set_fix_floats +libnifti2.so nifti_set_iname_offset +libnifti2.so nifti_set_skip_blank_ext +libnifti2.so nifti_set_type_from_names +libnifti2.so nifti_short_order +libnifti2.so nifti_simple_init_nim +libnifti2.so nifti_slice_string +libnifti2.so nifti_strdup +libnifti2.so nifti_swap_16bytes +libnifti2.so nifti_swap_2bytes +libnifti2.so nifti_swap_4bytes +libnifti2.so nifti_swap_8bytes +libnifti2.so nifti_swap_Nbytes +libnifti2.so nifti_swap_as_analyze +libnifti2.so nifti_swap_as_nifti1 +libnifti2.so nifti_swap_as_nifti2 +libnifti2.so nifti_test_datatype_sizes +libnifti2.so nifti_type_and_names_match +libnifti2.so nifti_units_string +libnifti2.so nifti_update_dims_from_array +libnifti2.so nifti_valid_header_size +libnifti2.so nifti_validfilename +libnifti2.so nifti_write_all_data +libnifti2.so nifti_write_ascii_image +libnifti2.so nifti_write_buffer +libnifti2.so nifti_xform_string +libnifti2.so old_swap_nifti_header +libnifti2.so swap_nifti_header +libnifti2.so valid_nifti_brick_list +libnifti2.so valid_nifti_extensions +libnifticdf.so E0000 +libnifticdf.so E0001 +libnifticdf.so Xgamm +libnifticdf.so algdiv +libnifticdf.so alngam +libnifticdf.so alnrel +libnifticdf.so apser +libnifticdf.so basym +libnifticdf.so bcorr +libnifticdf.so betaln +libnifticdf.so bfrac +libnifticdf.so bgrat +libnifticdf.so bpser +libnifticdf.so bratio +libnifticdf.so brcmp1 +libnifticdf.so brcomp +libnifticdf.so bup +libnifticdf.so cdfbet +libnifticdf.so cdfbin +libnifticdf.so cdfchi +libnifticdf.so cdfchn +libnifticdf.so cdff +libnifticdf.so cdffnc +libnifticdf.so cdfgam +libnifticdf.so cdfnbn +libnifticdf.so cdfnor +libnifticdf.so cdfpoi +libnifticdf.so cdft +libnifticdf.so cumbet +libnifticdf.so cumbin +libnifticdf.so cumchi +libnifticdf.so cumchn +libnifticdf.so cumf +libnifticdf.so cumfnc +libnifticdf.so cumgam +libnifticdf.so cumnbn +libnifticdf.so cumnor +libnifticdf.so cumpoi +libnifticdf.so cumt +libnifticdf.so dbetrm +libnifticdf.so devlpl +libnifticdf.so dexpm1 +libnifticdf.so dinvnr +libnifticdf.so dinvr +libnifticdf.so dlanor +libnifticdf.so dln1mx +libnifticdf.so dln1px +libnifticdf.so dlnbet +libnifticdf.so dlngam +libnifticdf.so dstinv +libnifticdf.so dstrem +libnifticdf.so dstzr +libnifticdf.so dt1 +libnifticdf.so dzror +libnifticdf.so erf1 +libnifticdf.so erfc1 +libnifticdf.so esum +libnifticdf.so exparg +libnifticdf.so fifdint +libnifticdf.so fifdmax1 +libnifticdf.so fifdmin1 +libnifticdf.so fifdsign +libnifticdf.so fifidint +libnifticdf.so fifmod +libnifticdf.so fpser +libnifticdf.so ftnstop +libnifticdf.so gam1 +libnifticdf.so gaminv +libnifticdf.so gamln +libnifticdf.so gamln1 +libnifticdf.so grat1 +libnifticdf.so gratio +libnifticdf.so gsumln +libnifticdf.so inam +libnifticdf.so ipmpar +libnifticdf.so nifti_cdf2stat +libnifticdf.so nifti_intent_code +libnifticdf.so nifti_rcdf2stat +libnifticdf.so nifti_stat2cdf +libnifticdf.so nifti_stat2hzscore +libnifticdf.so nifti_stat2rcdf +libnifticdf.so nifti_stat2zscore +libnifticdf.so psi +libnifticdf.so rcomp +libnifticdf.so rexp +libnifticdf.so rlog +libnifticdf.so rlog1 +libnifticdf.so spmpar +libnifticdf.so stvaln +libniftiio.so disp_nifti_1_header +libniftiio.so is_nifti_file +libniftiio.so is_valid_nifti_type +libniftiio.so nifti_add_extension +libniftiio.so nifti_compiled_with_zlib +libniftiio.so nifti_convert_nhdr2nim +libniftiio.so nifti_convert_nim2nhdr +libniftiio.so nifti_copy_extensions +libniftiio.so nifti_copy_nim_info +libniftiio.so nifti_datatype_from_string +libniftiio.so nifti_datatype_is_valid +libniftiio.so nifti_datatype_sizes +libniftiio.so nifti_datatype_string +libniftiio.so nifti_datatype_to_string +libniftiio.so nifti_disp_lib_hist +libniftiio.so nifti_disp_lib_version +libniftiio.so nifti_disp_matrix_orient +libniftiio.so nifti_disp_type_list +libniftiio.so nifti_fileexists +libniftiio.so nifti_find_file_extension +libniftiio.so nifti_findhdrname +libniftiio.so nifti_findimgname +libniftiio.so nifti_free_NBL +libniftiio.so nifti_free_extensions +libniftiio.so nifti_get_filesize +libniftiio.so nifti_get_intlist +libniftiio.so nifti_get_volsize +libniftiio.so nifti_hdr_looks_good +libniftiio.so nifti_image_free +libniftiio.so nifti_image_from_ascii +libniftiio.so nifti_image_infodump +libniftiio.so nifti_image_load +libniftiio.so nifti_image_load_bricks +libniftiio.so nifti_image_open +libniftiio.so nifti_image_read +libniftiio.so nifti_image_read_bricks +libniftiio.so nifti_image_to_ascii +libniftiio.so nifti_image_unload +libniftiio.so nifti_image_write +libniftiio.so nifti_image_write_bricks +libniftiio.so nifti_image_write_bricks_status +libniftiio.so nifti_image_write_hdr_img +libniftiio.so nifti_image_write_hdr_img2 +libniftiio.so nifti_image_write_status +libniftiio.so nifti_intent_string +libniftiio.so nifti_is_complete_filename +libniftiio.so nifti_is_gzfile +libniftiio.so nifti_is_inttype +libniftiio.so nifti_is_valid_datatype +libniftiio.so nifti_is_valid_ecode +libniftiio.so nifti_make_new_header +libniftiio.so nifti_make_new_nim +libniftiio.so nifti_make_orthog_mat44 +libniftiio.so nifti_makebasename +libniftiio.so nifti_makehdrname +libniftiio.so nifti_makeimgname +libniftiio.so nifti_mat33_colnorm +libniftiio.so nifti_mat33_determ +libniftiio.so nifti_mat33_inverse +libniftiio.so nifti_mat33_mul +libniftiio.so nifti_mat33_polar +libniftiio.so nifti_mat33_rownorm +libniftiio.so nifti_mat44_inverse +libniftiio.so nifti_mat44_to_orientation +libniftiio.so nifti_mat44_to_quatern +libniftiio.so nifti_nim_has_valid_dims +libniftiio.so nifti_nim_is_valid +libniftiio.so nifti_orientation_string +libniftiio.so nifti_quatern_to_mat44 +libniftiio.so nifti_read_ascii_image +libniftiio.so nifti_read_buffer +libniftiio.so nifti_read_collapsed_image +libniftiio.so nifti_read_header +libniftiio.so nifti_read_subregion_image +libniftiio.so nifti_set_allow_upper_fext +libniftiio.so nifti_set_debug_level +libniftiio.so nifti_set_filenames +libniftiio.so nifti_set_fix_floats +libniftiio.so nifti_set_iname_offset +libniftiio.so nifti_set_skip_blank_ext +libniftiio.so nifti_set_type_from_names +libniftiio.so nifti_short_order +libniftiio.so nifti_simple_init_nim +libniftiio.so nifti_slice_string +libniftiio.so nifti_strdup +libniftiio.so nifti_swap_16bytes +libniftiio.so nifti_swap_2bytes +libniftiio.so nifti_swap_4bytes +libniftiio.so nifti_swap_8bytes +libniftiio.so nifti_swap_Nbytes +libniftiio.so nifti_swap_as_analyze +libniftiio.so nifti_test_datatype_sizes +libniftiio.so nifti_type_and_names_match +libniftiio.so nifti_units_string +libniftiio.so nifti_update_dims_from_array +libniftiio.so nifti_validfilename +libniftiio.so nifti_write_all_data +libniftiio.so nifti_write_ascii_image +libniftiio.so nifti_write_buffer +libniftiio.so nifti_xform_string +libniftiio.so old_swap_nifti_header +libniftiio.so swap_nifti_header +libniftiio.so valid_nifti_brick_list +libniftiio.so valid_nifti_extensions +libznz.so Xznzclose +libznz.so znzopen +libznz.so znzputs +libznz.so znzread +libznz.so znzrewind +libznz.so znzseek +libznz.so znztell +libznz.so znzwrite From 2c27a784f266e0b3a67c3f8ea8998188448f1367 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 21 Sep 2026 13:27:08 -0500 Subject: [PATCH 2/3] COMP: Submit dashboard results over https, at the documented start time The dashboard script restates the CTestConfig.cmake settings because CTest's delayed initialization does not pick them up, and the restated copy had drifted from the original. Submit over https rather than http. my.cdash.org serves plain http without redirecting, so submissions were going unencrypted. Use the 00:00:00 EST nightly start time that CTestConfig.cmake declares, rather than 01:00:00 UTC. The two differ by four hours, so nightly builds were filed under the wrong day on the dashboard. --- cmake/nifti_common.cmake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/nifti_common.cmake b/cmake/nifti_common.cmake index e766f738..ed8f85b9 100644 --- a/cmake/nifti_common.cmake +++ b/cmake/nifti_common.cmake @@ -267,8 +267,10 @@ endif() set(CTEST_CHECKOUT_COMMAND "\"${CMAKE_COMMAND}\" -P \"${ctest_checkout_script}\"") # CTest delayed initialization is broken, so we put the # CTestConfig.cmake info here. - set(CTEST_NIGHTLY_START_TIME "01:00:00 UTC") - set(CTEST_DROP_METHOD "http") + # Keep these in agreement with CTestConfig.cmake; a nightly start time + # that disagrees files builds under the wrong day on the dashboard. + set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") + set(CTEST_DROP_METHOD "https") set(CTEST_DROP_SITE "my.cdash.org") set(CTEST_DROP_LOCATION "/submit.php?project=nifti_clib") set(CTEST_DROP_SITE_CDASH TRUE) From 71e2b364981fa1475a291c9e240de1f3abadc79d Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 21 Sep 2026 13:43:13 -0500 Subject: [PATCH 3/3] COMP: Finish the migration from Travis to GitHub Actions The 2025 conversion to GitHub Actions replaced .travis.yml with two workflows but left the dashboard script untouched, so it still required a Travis environment. The workflow that drives it named the wrong branch and never ran, which is why nothing surfaced the mismatch. Rename travis_dashboard.cmake to github_dashboard.cmake and take its inputs from the runner that actually exists. CTEST_SITE now comes from RUNNER_OS rather than the required TRAVIS_APP_HOST, whose absence aborted the script before it configured anything, and the build name carries RUNNER_OS in place of TRAVIS_OS_NAME. Compare the branch name against its value rather than against the literal string "ENV{BUILD_SOURCEBRANCHNAME}", so the Continuous and Nightly models can be selected at all, and give the workflow a branch name on push events as well as on pull requests. Apply the same corrections to local_dashboard.cmake. --- .github/workflows/build.yml | 4 ++-- ...travis_dashboard.cmake => github_dashboard.cmake} | 12 +++++++----- cmake/local_dashboard.cmake | 9 ++++----- 3 files changed, 13 insertions(+), 12 deletions(-) rename cmake/{travis_dashboard.cmake => github_dashboard.cmake} (90%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2a5a8922..e2bd685b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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 @@ -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 diff --git a/cmake/travis_dashboard.cmake b/cmake/github_dashboard.cmake similarity index 90% rename from cmake/travis_dashboard.cmake rename to cmake/github_dashboard.cmake index 680e0031..8d358a70 100644 --- a/cmake/travis_dashboard.cmake +++ b/cmake/github_dashboard.cmake @@ -21,8 +21,10 @@ function(set_from_env var env_var) endif() endfunction() -set_from_env(CTEST_SITE "TRAVIS_APP_HOST" REQUIRED) -set(CTEST_SITE "travis.${CTEST_SITE}") +# RUNNER_OS is set by GitHub Actions ("Linux", "macOS", "Windows"). The +# default keeps the script usable from a developer machine. +set_from_env(CTEST_SITE "RUNNER_OS" DEFAULT "unknown") +set(CTEST_SITE "github.${CTEST_SITE}") set(CTEST_UPDATE_VERSION_ONLY 1) # https://gitlab.kitware.com/cmake/community/wikis/doc/ctest/Scripting-Of-CTest @@ -55,11 +57,11 @@ if(NOT CTEST_BUILD_NAME) set(branch "-$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_git_branch "$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_model "Experimental") - elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "master") + elseif("$ENV{BUILD_SOURCEBRANCHNAME}" STREQUAL "master") set(branch "-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Continuous") - elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "nightly-master") + elseif("$ENV{BUILD_SOURCEBRANCHNAME}" STREQUAL "nightly-master") set(branch "-nightly-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Nightly") @@ -76,7 +78,7 @@ if(NOT CTEST_BUILD_NAME) endif() set(CTEST_BUILD_NAME - "$ENV{BLDPREFIX}_$ENV{TRAVIS_OS_NAME}-$ENV{BUILD_BUILDID}_${pr}_${branch}") + "$ENV{BLDPREFIX}_$ENV{RUNNER_OS}-$ENV{BUILD_BUILDID}_${pr}_${branch}") endif() set(dashboard_cache " diff --git a/cmake/local_dashboard.cmake b/cmake/local_dashboard.cmake index a69588c1..c85a9dbd 100644 --- a/cmake/local_dashboard.cmake +++ b/cmake/local_dashboard.cmake @@ -32,9 +32,8 @@ function(set_from_env var env_var) endif() endfunction() -#set_from_env(CTEST_SITE "TRAVIS_APP_HOST" REQUIRED) cmake_host_system_information(RESULT CTEST_SITE QUERY HOSTNAME) -set(CTEST_SITE "travis.${CTEST_SITE}") +set(CTEST_SITE "local.${CTEST_SITE}") set(CTEST_UPDATE_VERSION_ONLY 1) set_from_env(PARALLEL_LEVEL "PARALLEL_LEVEL" DEFAULT 8) @@ -59,11 +58,11 @@ if(NOT CTEST_BUILD_NAME) set(branch "-$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_git_branch "$ENV{SYSTEM_PULLREQUEST_SOURCEBRANCH}") set(dashboard_model "Experimental") - elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "master") + elseif("$ENV{BUILD_SOURCEBRANCHNAME}" STREQUAL "master") set(branch "-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Continuous") - elseif(ENV{BUILD_SOURCEBRANCHNAME} STREQUAL "nightly-master") + elseif("$ENV{BUILD_SOURCEBRANCHNAME}" STREQUAL "nightly-master") set(branch "-nightly-master") set(dashboard_git_branch "$ENV{BUILD_SOURCEBRANCHNAME}") set(dashboard_model "Nightly") @@ -80,7 +79,7 @@ if(NOT CTEST_BUILD_NAME) endif() set(CTEST_BUILD_NAME - "$ENV{TRAVIS_OS_NAME}-$ENV{BUILD_BUILDID}${pr}${branch}") + "$ENV{RUNNER_OS}-$ENV{BUILD_BUILDID}${pr}${branch}") endif() set(dashboard_cache "