From ae2fc53813ef5942c47970aca943f81ab8a0e568 Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 09:59:38 +0200 Subject: [PATCH 01/11] package_source configures again after a change of VERSION.txt, with the Makefile generators too --- CMakeLists.txt | 9 +++++++- cmake/gaol_package_source.cmake | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 cmake/gaol_package_source.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index b3ceb2e5..581c3b3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -958,7 +958,14 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) # warn while it configures only, so it does here, whether or not the archive # is made. A tree without configure, or with a configure that has no such # line, has nothing to compare (tests/cpack_stale_configure.cmake checks it, - # GAOL v5). + # GAOL v5). As the archive takes its name from the version CMake read when it + # configured, CPack includes cmake/gaol_package_source.cmake, which configures + # the build directory again first when VERSION.txt holds another version: + # Ninja does before package_source, the Makefile generators did not. + set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/gaol_package_source.cmake") + set(CPACK_GAOL_CMAKE_COMMAND "${CMAKE_COMMAND}") + set(CPACK_GAOL_SOURCE_DIR "${PROJECT_SOURCE_DIR}") + set(CPACK_GAOL_BINARY_DIR "${PROJECT_BINARY_DIR}") if(EXISTS "${PROJECT_SOURCE_DIR}/configure") file(STRINGS "${PROJECT_SOURCE_DIR}/configure" _gaol_configure_version REGEX "^PACKAGE_VERSION='" LIMIT_COUNT 1) if(_gaol_configure_version MATCHES "^PACKAGE_VERSION='([^']*)'") diff --git a/cmake/gaol_package_source.cmake b/cmake/gaol_package_source.cmake new file mode 100644 index 00000000..ec27eb58 --- /dev/null +++ b/cmake/gaol_package_source.cmake @@ -0,0 +1,40 @@ +# ================================================================== +# The archive of the sources after a change of VERSION.txt (GAOL v5) +# ================================================================== +# +# CPack includes this file when it makes a package, once per generator +# (CPACK_PROJECT_CONFIG_FILE, set by CMakeLists.txt). The archive of the +# sources (package_source) takes its name and its version from +# CPackSourceConfig.cmake, which CMake writes in the build directory when it +# configures. Before package_source, Ninja configures again after a change of +# VERSION.txt (CMAKE_CONFIGURE_DEPENDS), but the Makefile generators run CPack +# at once: the archive was named after the old version, held the new +# VERSION.txt, and CMake did not say whether configure had been generated for +# it. So when VERSION.txt holds another version than the build directory was +# configured for, CMake configures it again here, which warns of a configure +# generated for another version, and the configuration it writes again is read +# in place of the old one. Only for the archive of the sources: the target +# package builds first, which configures again with every generator. +# +# Copyright (c) 2026 ENSTA, France +# +# Created 2026-10-06 by Jordan NININ + +# CPack sets CPACK_INSTALLED_DIRECTORIES for the archive of the sources only: +# the packages of the library install the build instead +if(CPACK_INSTALLED_DIRECTORIES) + include("${CPACK_GAOL_SOURCE_DIR}/cmake/gaol_version.cmake") + gaol_read_version("${CPACK_GAOL_SOURCE_DIR}/VERSION.txt" _gaol_version _gaol_version_error) + # A VERSION.txt refused configures again too, which fails with its message + if(NOT _gaol_version STREQUAL CPACK_PACKAGE_VERSION) + message(STATUS "VERSION.txt no longer holds ${CPACK_PACKAGE_VERSION}, the version " + "${CPACK_GAOL_BINARY_DIR} was configured for: CMake configures it again") + execute_process( + COMMAND "${CPACK_GAOL_CMAKE_COMMAND}" -S "${CPACK_GAOL_SOURCE_DIR}" -B "${CPACK_GAOL_BINARY_DIR}" + RESULT_VARIABLE _gaol_status) + if(NOT _gaol_status EQUAL 0) + message(FATAL_ERROR "CMake did not configure ${CPACK_GAOL_BINARY_DIR} again (status ${_gaol_status})") + endif() + include("${CPACK_SOURCE_OUTPUT_CONFIG_FILE}") + endif() +endif() From 3f9ba96a44dc6724518e642f0102e37668e20eab Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 09:59:38 +0200 Subject: [PATCH 02/11] cpack_stale_configure: ccache in CC, Ninja outside PATH, skipped without sh or links, package_source --- tests/CMakeLists.txt | 27 +++++-- tests/cpack_stale_configure.cmake | 118 ++++++++++++++++++++++++------ 2 files changed, 113 insertions(+), 32 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 626466c5..464a9430 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -161,21 +161,32 @@ endif() # The warning of the CPack block of CMakeLists.txt, when the configure that the # archive of the sources holds was generated for another version than VERSION.txt # holds (GAOL v5): not a program, a script that configures copies of the tree -# with the compiler that built GAOL (cpack_stale_configure.cmake). Only the CMake -# build makes the archive; the copies are made of symbolic links, so the script -# runs on the machine that builds, where the system has them, and it asks the -# configure of the tree its version, so there has to be one. The time limit is -# that of a few configurations, on a slow machine. +# with the compilers that built GAOL, and makes the archive after a change of +# VERSION.txt (cpack_stale_configure.cmake). Only the CMake build makes the +# archive; the copies are made of symbolic links, so the script runs on the +# machine that builds, and it asks the configure of the tree its version, so +# there has to be one. The compilers are passed with their arguments, which +# CMake keeps apart: with CC="ccache gcc", CMAKE_C_COMPILER is ccache and +# CMAKE_C_COMPILER_ARG1 gcc. Without sh, or on a system that makes no symbolic +# link, the script says it is skipped, which CTest reads from CMake 3.16 (the +# test passes before). The time limit is that of a few configurations, on a +# slow machine. if(CMAKE_HOST_UNIX AND NOT CMAKE_CROSSCOMPILING AND EXISTS "${PROJECT_SOURCE_DIR}/configure") + foreach(_lang C CXX) + string(STRIP "${CMAKE_${_lang}_COMPILER_ARG1}" _gaol_arguments) + string(STRIP "${CMAKE_${_lang}_COMPILER} ${_gaol_arguments}" _gaol_${_lang}_compiler) + endforeach() add_test(NAME cpack_stale_configure COMMAND "${CMAKE_COMMAND}" "-DGAOL_SOURCE_DIR=${PROJECT_SOURCE_DIR}" "-DGAOL_WORK_DIR=${CMAKE_CURRENT_BINARY_DIR}/cpack_stale_configure" "-DGAOL_GENERATOR=${CMAKE_GENERATOR}" - "-DGAOL_C_COMPILER=${CMAKE_C_COMPILER}" - "-DGAOL_CXX_COMPILER=${CMAKE_CXX_COMPILER}" + "-DGAOL_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}" + "-DGAOL_C_COMPILER=${_gaol_C_compiler}" + "-DGAOL_CXX_COMPILER=${_gaol_CXX_compiler}" -P "${CMAKE_CURRENT_SOURCE_DIR}/cpack_stale_configure.cmake") - set_tests_properties(cpack_stale_configure PROPERTIES LABELS unit TIMEOUT 600) + set_tests_properties(cpack_stale_configure PROPERTIES LABELS unit TIMEOUT 600 + SKIP_REGULAR_EXPRESSION "cpack_stale_configure: skipped") endif() # Commented out: the tests run no thread (GAOL v5) diff --git a/tests/cpack_stale_configure.cmake b/tests/cpack_stale_configure.cmake index 8a3634eb..f3a86ce7 100644 --- a/tests/cpack_stale_configure.cmake +++ b/tests/cpack_stale_configure.cmake @@ -19,17 +19,32 @@ # - a configure without a line PACKAGE_VERSION=, and a tree without configure # (an archive of another kind): no warning, and CMake configures. # +# The archive takes its name from the version CMake read when it configured: +# the copy configured for the version configure was generated for, VERSION.txt +# then holds the next one, and CPack has to configure the build directory +# again before it makes the archive (cmake/gaol_package_source.cmake), warn, +# and name the archive after the new version. CPack runs as the target +# package_source runs it, in the build directory, whatever the generator: +# Ninja configured again before package_source, the Makefile generators did +# not. +# # A copy is made of symbolic links to the files and directories of the tree, # but for CMakeLists.txt, VERSION.txt and configure, which are copies: CMake # reads them from the copy, and the script never writes through a link, into # the tree. The version the committed configure was generated for is asked of # configure itself (configure --version, as a user of the archive sees it), not -# read as CMakeLists.txt reads it, so that the two do not share a mistake. +# read as CMakeLists.txt reads it, so that the two do not share a mistake. The +# copy is configured with the generator, its program and the compilers that +# built GAOL, the compilers given to CMake as CC and CXX, the way CMake reads +# them with their arguments (CC="ccache gcc"). Where sh cannot run configure, +# or the system makes no symbolic link, the script says that it is skipped +# (SKIP_REGULAR_EXPRESSION of tests/CMakeLists.txt) rather than failing. # # ctest runs it (tests/CMakeLists.txt), and by hand: # # cmake -DGAOL_SOURCE_DIR= -DGAOL_WORK_DIR=/cpack_stale_configure \ -# -DGAOL_GENERATOR= -DGAOL_C_COMPILER= -DGAOL_CXX_COMPILER= \ +# -DGAOL_GENERATOR= [-DGAOL_MAKE_PROGRAM=] \ +# "-DGAOL_C_COMPILER=" "-DGAOL_CXX_COMPILER=" \ # -P tests/cpack_stale_configure.cmake # # Copyright (c) 2026 ENSTA, France @@ -43,14 +58,40 @@ foreach(_name GAOL_SOURCE_DIR GAOL_WORK_DIR GAOL_GENERATOR GAOL_C_COMPILER GAOL_ message(FATAL_ERROR "${_name} is not given (see the head of this file)") endif() endforeach() -# The script removes what it made in this directory, and nothing else +# The script removes the whole of this directory, when it starts and when it +# ends: it has to be the directory of this test if(NOT GAOL_WORK_DIR MATCHES "/cpack_stale_configure$") message(FATAL_ERROR "GAOL_WORK_DIR, ${GAOL_WORK_DIR}, is not a directory of this test (cpack_stale_configure)") endif() -# The version configure was generated for, and the next one +set(_tree "${GAOL_WORK_DIR}/tree") +set(_build "${GAOL_WORK_DIR}/build") + +# Removes the directory, the links of the copy one by one first, so that +# nothing is ever removed through them +macro(remove_work_dir) + file(GLOB _links "${_tree}/*") + foreach(_path ${_links}) + file(REMOVE "${_path}") + endforeach() + file(REMOVE_RECURSE "${GAOL_WORK_DIR}") +endmacro() + +# Ends the script, which passes, saying why it is skipped: ctest reads the +# message (SKIP_REGULAR_EXPRESSION) +macro(skip why) + remove_work_dir() + message(STATUS "cpack_stale_configure: skipped, ${why}") + return() +endmacro() + +# The version configure was generated for, and the next one. A status that is +# no number is a command that did not run execute_process(COMMAND sh "${GAOL_SOURCE_DIR}/configure" --version OUTPUT_VARIABLE _output RESULT_VARIABLE _status) +if(NOT _status MATCHES "^[0-9]+$") + skip("sh did not run configure --version (${_status})") +endif() if(NOT _status EQUAL 0 OR NOT _output MATCHES "^gaol configure ([0-9]+)\\.([0-9]+)\\.([0-9]+)\n") message(FATAL_ERROR "configure --version, which tells the version configure was generated for, gave (status ${_status}):\n${_output}") endif() @@ -61,18 +102,16 @@ math(EXPR _next_micro "${_micro} + 1") set(_old "${_major}.${_minor}.${_micro}") set(_new "${_major}.${_minor}.${_next_micro}") -set(_tree "${GAOL_WORK_DIR}/tree") -set(_build "${GAOL_WORK_DIR}/build") - -# What a run left is removed with its links one by one, so that nothing is -# ever removed through them -file(GLOB _left "${_tree}/*") -foreach(_path ${_left}) - file(REMOVE "${_path}") -endforeach() -file(REMOVE_RECURSE "${GAOL_WORK_DIR}") +# What a run left +remove_work_dir() file(MAKE_DIRECTORY "${_tree}") +# Whether the system makes symbolic links here, which a file system may not +file(CREATE_LINK "${GAOL_SOURCE_DIR}/VERSION.txt" "${GAOL_WORK_DIR}/probe" RESULT _result SYMBOLIC) +if(NOT _result STREQUAL "0") + skip("the system made no symbolic link in ${GAOL_WORK_DIR}: ${_result}") +endif() +file(REMOVE "${GAOL_WORK_DIR}/probe") file(GLOB _entries RELATIVE "${GAOL_SOURCE_DIR}" "${GAOL_SOURCE_DIR}/*") foreach(_entry ${_entries}) # The three files to copy, and the hidden ones (.git...), which no @@ -93,15 +132,27 @@ foreach(_entry ${_entries}) endforeach() file(COPY "${GAOL_SOURCE_DIR}/CMakeLists.txt" DESTINATION "${_tree}") +# The program of the generator, which CMake looks for in PATH otherwise: Ninja +# can be elsewhere +set(_make_program) +if(NOT "${GAOL_MAKE_PROGRAM}" STREQUAL "") + set(_make_program "-DCMAKE_MAKE_PROGRAM=${GAOL_MAKE_PROGRAM}") +endif() + +# Writes in the VERSION.txt of the copy +function(write_version version) + file(REMOVE "${_tree}/VERSION.txt") + file(WRITE "${_tree}/VERSION.txt" "${version}\n") +endfunction() + # Configures the copy as it is, in the same directory of build each time (the -# checks of the compiler are cached), with the compiler that built GAOL, and +# checks of the compiler are cached), with the compilers that built GAOL, and # checks its warning: is WARNS, with the versions it names, or SILENT function(check_configure title version expected) - file(REMOVE "${_tree}/VERSION.txt") - file(WRITE "${_tree}/VERSION.txt" "${version}\n") + write_version("${version}") execute_process( - COMMAND "${CMAKE_COMMAND}" -S "${_tree}" -B "${_build}" -G "${GAOL_GENERATOR}" - "-DCMAKE_C_COMPILER=${GAOL_C_COMPILER}" "-DCMAKE_CXX_COMPILER=${GAOL_CXX_COMPILER}" + COMMAND "${CMAKE_COMMAND}" -E env "CC=${GAOL_C_COMPILER}" "CXX=${GAOL_CXX_COMPILER}" + "${CMAKE_COMMAND}" -S "${_tree}" -B "${_build}" -G "${GAOL_GENERATOR}" ${_make_program} RESULT_VARIABLE _status OUTPUT_VARIABLE _output ERROR_VARIABLE _error) if(NOT _status EQUAL 0) message(FATAL_ERROR "${title}: CMake did not configure the copy (status ${_status}):\n${_output}\n${_error}") @@ -129,6 +180,29 @@ file(COPY "${GAOL_SOURCE_DIR}/configure" DESTINATION "${_tree}") check_configure("VERSION.txt ${_new}, configure generated for ${_old}" "${_new}" WARNS) check_configure("VERSION.txt ${_old}, configure generated for ${_old}" "${_old}" SILENT) +# The archive of the sources after a change of VERSION.txt, the build directory +# being configured for the version configure was generated for +write_version("${_new}") +execute_process(COMMAND "${CMAKE_CPACK_COMMAND}" --config CPackSourceConfig.cmake + WORKING_DIRECTORY "${_build}" RESULT_VARIABLE _status OUTPUT_VARIABLE _output ERROR_VARIABLE _error) +set(_title "VERSION.txt ${_new} after a configuration for ${_old}, package_source") +if(NOT _status EQUAL 0) + message(FATAL_ERROR "${_title}: CPack did not make the archive (status ${_status}):\n${_output}\n${_error}") +endif() +string(REGEX REPLACE "[ \t\r\n]+" " " _text "${_output} ${_error}") +string(FIND "${_text}" "configure was generated for GAOL ${_old}, and VERSION.txt holds ${_new}:" _found) +if(_found EQUAL -1 OR NOT EXISTS "${_build}/gaol-${_new}.tar.gz" OR EXISTS "${_build}/gaol-${_old}.tar.gz") + file(GLOB _archives RELATIVE "${_build}" "${_build}/*.tar.gz") + message(FATAL_ERROR "${_title}: CPack did not configure again, warn and make gaol-${_new}.tar.gz " + "(archives made: ${_archives}):\n${_output}\n${_error}") +endif() +execute_process(COMMAND "${CMAKE_COMMAND}" -E tar tzf "gaol-${_new}.tar.gz" + WORKING_DIRECTORY "${_build}" OUTPUT_VARIABLE _list) +if(NOT _list MATCHES "(^|\n)gaol-${_new}/VERSION\\.txt\n") + message(FATAL_ERROR "${_title}: gaol-${_new}.tar.gz holds no gaol-${_new}/VERSION.txt") +endif() +message(STATUS "${_title}: WARNS and gaol-${_new}.tar.gz, as expected") + # The same, with the line ends of Windows file(READ "${GAOL_SOURCE_DIR}/configure" _script) string(REPLACE "\n" "\r\n" _script "${_script}") @@ -143,8 +217,4 @@ check_configure("VERSION.txt ${_new}, configure without PACKAGE_VERSION=" "${_ne file(REMOVE "${_tree}/configure") check_configure("VERSION.txt ${_new}, no configure" "${_new}" SILENT) -file(GLOB _made "${_tree}/*") -foreach(_path ${_made}) - file(REMOVE "${_path}") -endforeach() -file(REMOVE_RECURSE "${GAOL_WORK_DIR}") +remove_work_dir() From 28d5f45ca4b87944ee6f5282ff509ef21ee21ddc Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 09:59:38 +0200 Subject: [PATCH 03/11] linux.yml: cpack_stale_configure with ccache in CC and Ninja outside PATH --- .github/workflows/linux.yml | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 5a6c564b..2abb825f 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -3,7 +3,8 @@ # (BUILD_SHARED_LIBS). Also with the sanitizers, with -Wall -Wextra -Werror, # checking the headers it installs too (GAOL v5), with the minimum version of # CMake GAOL declares, and as a part of another project, brought in by -# FetchContent (tests/fetch_content). +# FetchContent (tests/fetch_content). The test cpack_stale_configure also runs +# with ccache in CC and Ninja outside PATH. # # The runners have no locale writing a decimal comma, which tests/numbers.cpp # reads and writes numbers under where there is one, and where there is none it @@ -258,6 +259,31 @@ jobs: - name: The test numbers ran under a locale writing a decimal comma run: sh .github/scripts/comma-locale.sh check build + # The test cpack_stale_configure configures copies of the tree with the + # compilers and the generator that configured GAOL: with a compiler given + # with an argument, which CMake keeps in CMAKE_C_COMPILER_ARG1, and Ninja + # outside PATH, where CMake finds it by CMAKE_MAKE_PROGRAM only. The test + # needs no build (GAOL v5) + launcher-ninja: + name: Ubuntu 24.04 x86_64 GCC, cpack_stale_configure with ccache in CC and Ninja outside PATH + runs-on: ubuntu-24.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@v7 + - name: ccache, and Ninja outside PATH + run: | + sudo apt-get update -q + sudo apt-get install -y -q ccache + curl -sSL -o "$RUNNER_TEMP/ninja-linux.zip" https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-linux.zip + unzip -q "$RUNNER_TEMP/ninja-linux.zip" -d "$RUNNER_TEMP/ninja" + # A Ninja of the image, which CMake would find in PATH + for ninja in $(which -a ninja); do sudo rm -f "$ninja"; done + if command -v ninja; then exit 1; fi + - name: Configure + run: CC="ccache gcc" CXX="ccache g++" cmake -S . -B build -G Ninja -DCMAKE_MAKE_PROGRAM="$RUNNER_TEMP/ninja/ninja" -DWITH_TESTS=ON + - name: The test cpack_stale_configure + run: cd build && ctest -R cpack_stale_configure --no-tests=error + fetch-content: name: Ubuntu 24.04 x86_64 GCC, GAOL built by FetchContent runs-on: ubuntu-24.04 From 501c73430bbcf6e752d4c8aebe362150b27bebad Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 09:59:38 +0200 Subject: [PATCH 04/11] doc, manual: package_source configures again, what cpack_stale_configure checks and why CMake only --- doc/building.md | 8 +++++--- doc/continuous-integration.md | 4 +++- doc/tests.md | 38 +++++++++++++++++++++++------------ manual/v5/gaol.tex | 3 ++- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/doc/building.md b/doc/building.md index d371a8a4..65289550 100644 --- a/doc/building.md +++ b/doc/building.md @@ -150,9 +150,11 @@ cmake --build build --target package The archive takes its name from the version CMake read when it configured, and CMake warns of a `configure` generated for another version at that moment. -After a change of `VERSION.txt`, configure the build directory again -(`cmake -S . -B build`) before `package_source`: Ninja does it by itself, the -Makefile generators do not. +After a change of `VERSION.txt`, `package_source` configures the build +directory again first, whatever the generator: Ninja does before it runs CPack, +and CPack does when `VERSION.txt` holds another version than the build +directory was configured for (`cmake/gaol_package_source.cmake`, GAOL v5), +where the Makefile generators ran CPack at once. The packages hold `libgaol` as the build compiled it: with `GAOL_FMA` `ON`, the default, only the processors that have the fused multiply-add diff --git a/doc/continuous-integration.md b/doc/continuous-integration.md index 2f955a5d..f622cacb 100644 --- a/doc/continuous-integration.md +++ b/doc/continuous-integration.md @@ -18,7 +18,9 @@ request (GAOL v5); `workflow_dispatch` runs them on any branch. The badges of with the compilers of Ubuntu 22.04 (GCC 11 and Clang 14 on x86_64, GCC 11 on arm64), whose images GitHub retires by April 2027, with GCC 9, which has no `__builtin_roundeven()` (see [3rd/README.md](../3rd/README.md)), and as a - shared library (`BUILD_SHARED_LIBS`). + shared library (`BUILD_SHARED_LIBS`); the test `cpack_stale_configure` also + runs with `CC="ccache gcc"` and a Ninja outside `PATH`, which it has to pass + on to the copies of the tree it configures. - **Linux containers:** - Debian 12 and 13 on amd64, arm64 and armhf, and Debian 12 on i386; - manylinux_2_28 on x86_64 and aarch64; diff --git a/doc/tests.md b/doc/tests.md index b30935a5..fac08c8a 100644 --- a/doc/tests.md +++ b/doc/tests.md @@ -700,19 +700,31 @@ mode there. itself, where the tree has a `configure`): a script, not a program (`tests/cpack_stale_configure.cmake`). CPack puts `configure` in the archive of the sources as it is committed, and `configure --version` gives the version - it was generated for: after a change of `VERSION.txt` without a new - generation of `configure`, the archive of the new version holds a - `configure` that says the old one. The script configures copies of the tree - with the compiler that built GAOL, and CMake has to warn of it, naming the - two versions, whether `configure` has the line ends of Unix or of Windows, - and not otherwise: not when `configure` was generated for the version - `VERSION.txt` holds, not when it has no line `PACKAGE_VERSION=`, and not - when there is no `configure`, which CMake has to configure all the same. The - version `configure` was generated for is asked of `configure --version`, not - read as `CMakeLists.txt` reads it. The copies are made of symbolic links to - the files of the tree, but for `CMakeLists.txt`, `VERSION.txt` and - `configure`, which are copied; the test takes a few seconds on an ordinary - machine, a configuration and four that reuse its checks (GAOL v5). + it was generated for: after a change of `VERSION.txt` without a new generation + of `configure`, the archive of the new version holds a `configure` that says + the old one. The script configures copies of the tree with the generator and + the compilers that built GAOL, and CMake has to warn of it, naming the two + versions, whether `configure` has the line ends of Unix or of Windows, and not + otherwise: not when `configure` was generated for the version `VERSION.txt` + holds, not when it has no line `PACKAGE_VERSION=`, and not when there is no + `configure`, which CMake has to configure all the same. Then a copy configured + for the version `configure` was generated for has its `VERSION.txt` changed, + and CPack, run as `package_source` runs it, has to configure it again, warn, + and name the archive after the new version + (`cmake/gaol_package_source.cmake`), which the Makefile generators did not do. + The version `configure` was generated for is asked of `configure --version`, + not read as `CMakeLists.txt` reads it. The copies are made of symbolic links + to the files of the tree, but for `CMakeLists.txt`, `VERSION.txt` and + `configure`, which are copied. The compilers are given to CMake as `CC` and + `CXX` with their arguments (`CC="ccache gcc"` leaves `ccache` in + `CMAKE_C_COMPILER` and `gcc` in `CMAKE_C_COMPILER_ARG1`), and the generator + with its program (`CMAKE_MAKE_PROGRAM`, for a Ninja outside `PATH`), which a + job of `.github/workflows/linux.yml` checks; without `sh`, or where the system + makes no symbolic link, the test says it is skipped. It takes a few seconds on + an ordinary machine, a configuration and five that reuse its checks, and an + archive of links. Only the CMake build has it: CPack makes the archive, and + the autotools jobs of the continuous integration compare `configure --version` + with `VERSION.txt` already (GAOL v5). - **The unit tests of GAOL 4:** `arithmetic_operators` (`check/arithmetic.cpp`), `assignment`, `constants`, `constructor`, `float_functions`, `generic_functions`, `input_output`, `interval_functions`, `misc`, diff --git a/manual/v5/gaol.tex b/manual/v5/gaol.tex index 7e00feb0..0a2530fa 100644 --- a/manual/v5/gaol.tex +++ b/manual/v5/gaol.tex @@ -532,7 +532,8 @@ \subsection{The archive of the sources and the packages}\label{sec:packages} from a clean checkout, and holds \file{configure} as it was generated. CMake warns, when it configures, if that was for another version than \file{VERSION.txt} holds: \cmd{configure --version} would give the old one - in the archive; + in the archive. After a change of \file{VERSION.txt}, \code{package\_source} + configures the build directory again first, whatever the generator; \item \code{package} gives \file{gaol-\var{version}-\var{system}.tar.gz}, what \cmd{cmake --install} installs, to extract anywhere, and on Linux \file{libgaol-dev\_\var{version}\_\var{arch}.deb}, the same files in From dce0bab0fc47cfa7a18a0458b3597435b9ca1a9e Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 10:29:40 +0200 Subject: [PATCH 05/11] gaol_package_source.cmake: the policies of CMakeLists.txt (CMP0007 with CMake 3), GAOL's own version --- CMakeLists.txt | 1 + cmake/gaol_package_source.cmake | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 581c3b3b..4c8d684e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -963,6 +963,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) # the build directory again first when VERSION.txt holds another version: # Ninja does before package_source, the Makefile generators did not. set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_SOURCE_DIR}/cmake/gaol_package_source.cmake") + set(CPACK_GAOL_VERSION "${PROJECT_VERSION}") set(CPACK_GAOL_CMAKE_COMMAND "${CMAKE_COMMAND}") set(CPACK_GAOL_SOURCE_DIR "${PROJECT_SOURCE_DIR}") set(CPACK_GAOL_BINARY_DIR "${PROJECT_BINARY_DIR}") diff --git a/cmake/gaol_package_source.cmake b/cmake/gaol_package_source.cmake index ec27eb58..b1ee41a0 100644 --- a/cmake/gaol_package_source.cmake +++ b/cmake/gaol_package_source.cmake @@ -20,14 +20,20 @@ # # Created 2026-10-06 by Jordan NININ +# CPack reads this file without the policies of CMakeLists.txt: CMake 3 would +# warn of CMP0007 at the list() of gaol_read_version() otherwise +cmake_policy(PUSH) +cmake_policy(VERSION 3.14...3.25) + # CPack sets CPACK_INSTALLED_DIRECTORIES for the archive of the sources only: -# the packages of the library install the build instead +# the packages of the library install the build instead. The version compared +# is GAOL's own, CPACK_PACKAGE_VERSION being that of cpack -R when it is given if(CPACK_INSTALLED_DIRECTORIES) include("${CPACK_GAOL_SOURCE_DIR}/cmake/gaol_version.cmake") gaol_read_version("${CPACK_GAOL_SOURCE_DIR}/VERSION.txt" _gaol_version _gaol_version_error) # A VERSION.txt refused configures again too, which fails with its message - if(NOT _gaol_version STREQUAL CPACK_PACKAGE_VERSION) - message(STATUS "VERSION.txt no longer holds ${CPACK_PACKAGE_VERSION}, the version " + if(NOT _gaol_version STREQUAL CPACK_GAOL_VERSION) + message(STATUS "VERSION.txt no longer holds ${CPACK_GAOL_VERSION}, the version " "${CPACK_GAOL_BINARY_DIR} was configured for: CMake configures it again") execute_process( COMMAND "${CPACK_GAOL_CMAKE_COMMAND}" -S "${CPACK_GAOL_SOURCE_DIR}" -B "${CPACK_GAOL_BINARY_DIR}" @@ -38,3 +44,5 @@ if(CPACK_INSTALLED_DIRECTORIES) include("${CPACK_SOURCE_OUTPUT_CONFIG_FILE}") endif() endif() + +cmake_policy(POP) From 75db9968594c5231bad00f6fd57a0903308e9750 Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 10:29:40 +0200 Subject: [PATCH 06/11] cpack_stale_configure: no warning of CMake in GAOL's files CPack reads, skipped only without sh --- tests/cpack_stale_configure.cmake | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tests/cpack_stale_configure.cmake b/tests/cpack_stale_configure.cmake index f3a86ce7..57599a54 100644 --- a/tests/cpack_stale_configure.cmake +++ b/tests/cpack_stale_configure.cmake @@ -23,7 +23,8 @@ # the copy configured for the version configure was generated for, VERSION.txt # then holds the next one, and CPack has to configure the build directory # again before it makes the archive (cmake/gaol_package_source.cmake), warn, -# and name the archive after the new version. CPack runs as the target +# and name the archive after the new version, CMake giving no warning of its +# own in the files of GAOL that CPack reads. CPack runs as the target # package_source runs it, in the build directory, whatever the generator: # Ninja configured again before package_source, the Makefile generators did # not. @@ -36,8 +37,8 @@ # read as CMakeLists.txt reads it, so that the two do not share a mistake. The # copy is configured with the generator, its program and the compilers that # built GAOL, the compilers given to CMake as CC and CXX, the way CMake reads -# them with their arguments (CC="ccache gcc"). Where sh cannot run configure, -# or the system makes no symbolic link, the script says that it is skipped +# them with their arguments (CC="ccache gcc"). Without sh, or where the system +# makes no symbolic link, the script says that it is skipped # (SKIP_REGULAR_EXPRESSION of tests/CMakeLists.txt) rather than failing. # # ctest runs it (tests/CMakeLists.txt), and by hand: @@ -58,8 +59,9 @@ foreach(_name GAOL_SOURCE_DIR GAOL_WORK_DIR GAOL_GENERATOR GAOL_C_COMPILER GAOL_ message(FATAL_ERROR "${_name} is not given (see the head of this file)") endif() endforeach() -# The script removes the whole of this directory, when it starts and when it -# ends: it has to be the directory of this test +# The script removes the whole of this directory, when it starts, and when it +# passes or is skipped (a failure leaves it to be looked at): it has to be the +# directory of this test if(NOT GAOL_WORK_DIR MATCHES "/cpack_stale_configure$") message(FATAL_ERROR "GAOL_WORK_DIR, ${GAOL_WORK_DIR}, is not a directory of this test (cpack_stale_configure)") endif() @@ -67,8 +69,10 @@ endif() set(_tree "${GAOL_WORK_DIR}/tree") set(_build "${GAOL_WORK_DIR}/build") -# Removes the directory, the links of the copy one by one first, so that -# nothing is ever removed through them +# Removes the directory, the links of the copy one by one first. file(REMOVE) +# and file(REMOVE_RECURSE) remove a symbolic link, not what it points to, +# which holds also for the links CPack copies into the build directory: nothing +# is ever removed through them macro(remove_work_dir) file(GLOB _links "${_tree}/*") foreach(_path ${_links}) @@ -85,11 +89,12 @@ macro(skip why) return() endmacro() -# The version configure was generated for, and the next one. A status that is -# no number is a command that did not run +# The version configure was generated for, and the next one. Without sh, the +# status is the message of a command that could not start execute_process(COMMAND sh "${GAOL_SOURCE_DIR}/configure" --version OUTPUT_VARIABLE _output RESULT_VARIABLE _status) -if(NOT _status MATCHES "^[0-9]+$") +string(TOLOWER "${_status}" _lower) +if(_lower MATCHES "no such file") skip("sh did not run configure --version (${_status})") endif() if(NOT _status EQUAL 0 OR NOT _output MATCHES "^gaol configure ([0-9]+)\\.([0-9]+)\\.([0-9]+)\n") @@ -189,6 +194,11 @@ set(_title "VERSION.txt ${_new} after a configuration for ${_old}, package_sourc if(NOT _status EQUAL 0) message(FATAL_ERROR "${_title}: CPack did not make the archive (status ${_status}):\n${_output}\n${_error}") endif() +# Without a warning of CMake for the files of GAOL CPack reads, which it reads +# without the policies of CMakeLists.txt +if("${_output}\n${_error}" MATCHES "CMake Warning \\(dev\\) at [^\n]*cmake/gaol_[a-z_]+\\.cmake") + message(FATAL_ERROR "${_title}: CMake warned in a file of GAOL that CPack reads:\n${_output}\n${_error}") +endif() string(REGEX REPLACE "[ \t\r\n]+" " " _text "${_output} ${_error}") string(FIND "${_text}" "configure was generated for GAOL ${_old}, and VERSION.txt holds ${_new}:" _found) if(_found EQUAL -1 OR NOT EXISTS "${_build}/gaol-${_new}.tar.gz" OR EXISTS "${_build}/gaol-${_old}.tar.gz") From 9823d5b561cce148095d6f295a19a64b4dd04080 Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 10:29:40 +0200 Subject: [PATCH 07/11] linux.yml: the cpack_stale_configure job fails if the test is skipped or another Ninja is in PATH --- .github/workflows/linux.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 2abb825f..5d51a055 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -276,13 +276,19 @@ jobs: sudo apt-get install -y -q ccache curl -sSL -o "$RUNNER_TEMP/ninja-linux.zip" https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-linux.zip unzip -q "$RUNNER_TEMP/ninja-linux.zip" -d "$RUNNER_TEMP/ninja" - # A Ninja of the image, which CMake would find in PATH - for ninja in $(which -a ninja); do sudo rm -f "$ninja"; done - if command -v ninja; then exit 1; fi + # A Ninja of the image, under the names CMake looks for in PATH + for name in ninja-build ninja samu; do + for program in $(which -a "$name"); do sudo rm -f "$program"; done + if command -v "$name"; then exit 1; fi + done - name: Configure run: CC="ccache gcc" CXX="ccache g++" cmake -S . -B build -G Ninja -DCMAKE_MAKE_PROGRAM="$RUNNER_TEMP/ninja/ninja" -DWITH_TESTS=ON - - name: The test cpack_stale_configure - run: cd build && ctest -R cpack_stale_configure --no-tests=error + - name: The test cpack_stale_configure, which has to run, not be skipped + run: | + cd build + ctest -R cpack_stale_configure --no-tests=error > ctest.log 2>&1 || { cat ctest.log; exit 1; } + cat ctest.log + if grep -q Skipped ctest.log; then exit 1; fi fetch-content: name: Ubuntu 24.04 x86_64 GCC, GAOL built by FetchContent From 2b4d58a3f172dfac45eb7d80de37c857f926428c Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 10:29:40 +0200 Subject: [PATCH 08/11] doc/tests.md: the archive cpack_stale_configure makes, with CMake 3.14 and with 3.28 --- doc/tests.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/tests.md b/doc/tests.md index fac08c8a..6526d876 100644 --- a/doc/tests.md +++ b/doc/tests.md @@ -722,9 +722,11 @@ mode there. job of `.github/workflows/linux.yml` checks; without `sh`, or where the system makes no symbolic link, the test says it is skipped. It takes a few seconds on an ordinary machine, a configuration and five that reuse its checks, and an - archive of links. Only the CMake build has it: CPack makes the archive, and - the autotools jobs of the continuous integration compare `configure --version` - with `VERSION.txt` already (GAOL v5). + archive: of the links themselves with CMake 3.28 and after (170 KB), of the + files of the directories they point to with CMake 3.14 and 3.16 (5.6 MB). Only + the CMake build has it: CPack makes the archive, and the autotools jobs of the + continuous integration compare `configure --version` with `VERSION.txt` + already (GAOL v5). - **The unit tests of GAOL 4:** `arithmetic_operators` (`check/arithmetic.cpp`), `assignment`, `constants`, `constructor`, `float_functions`, `generic_functions`, `input_output`, `interval_functions`, `misc`, From 60720242822d938bf3fa80f76724f8d77162ff8d Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 11:17:05 +0200 Subject: [PATCH 09/11] CPACK_VERBATIM_VARIABLES: CPack reads CPACK_SOURCE_IGNORE_FILES with its backslashes (CMP0010) --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c8d684e..483937c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -934,7 +934,12 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) # The archive of the sources: the files of the repository, without what git # ignores (.gitignore), the builds within the sources, the packages, and the # notes of the work on GAOL v5 (TODO.md, process.md, todo-notes/), which - # serve its maintainers, not the users of a version + # serve its maintainers, not the users of a version. CPack writes the CPACK_* + # variables into CPackConfig.cmake and CPackSourceConfig.cmake, which it reads + # when it runs: CPACK_VERBATIM_VARIABLES has it escape them, so that the + # backslashes of these regular expressions reach it as they are, where CMake + # 3 warned of an invalid escape sequence, \. (CMP0010, GAOL v5) + set(CPACK_VERBATIM_VARIABLES ON) set(CPACK_SOURCE_GENERATOR "TGZ") set(CPACK_SOURCE_PACKAGE_FILE_NAME "gaol-${PROJECT_VERSION}") string(REGEX REPLACE "([][+.*()^$?|\\])" "\\\\\\1" _gaol_source_regex "${PROJECT_SOURCE_DIR}") From 3d7059aab93468341d77e43e7c287692701f7408 Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 11:17:05 +0200 Subject: [PATCH 10/11] cpack_stale_configure: no dev warning while CPack runs, keep.halo archived (no pattern ignores it) --- tests/cpack_stale_configure.cmake | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/cpack_stale_configure.cmake b/tests/cpack_stale_configure.cmake index 57599a54..0b19f143 100644 --- a/tests/cpack_stale_configure.cmake +++ b/tests/cpack_stale_configure.cmake @@ -24,7 +24,7 @@ # then holds the next one, and CPack has to configure the build directory # again before it makes the archive (cmake/gaol_package_source.cmake), warn, # and name the archive after the new version, CMake giving no warning of its -# own in the files of GAOL that CPack reads. CPack runs as the target +# own in the files CPack reads. CPack runs as the target # package_source runs it, in the build directory, whatever the generator: # Ninja configured again before package_source, the Makefile generators did # not. @@ -136,6 +136,10 @@ foreach(_entry ${_entries}) endif() endforeach() file(COPY "${GAOL_SOURCE_DIR}/CMakeLists.txt" DESTINATION "${_tree}") +# A file the regular expressions of CPACK_SOURCE_IGNORE_FILES do not match, +# which the archive has to hold: \.lo$ read without its backslash, as CMake 4 +# read it without CPACK_VERBATIM_VARIABLES, matches it +file(WRITE "${_tree}/keep.halo" "Not ignored by CPack\n") # The program of the generator, which CMake looks for in PATH otherwise: Ninja # can be elsewhere @@ -194,10 +198,11 @@ set(_title "VERSION.txt ${_new} after a configuration for ${_old}, package_sourc if(NOT _status EQUAL 0) message(FATAL_ERROR "${_title}: CPack did not make the archive (status ${_status}):\n${_output}\n${_error}") endif() -# Without a warning of CMake for the files of GAOL CPack reads, which it reads -# without the policies of CMakeLists.txt -if("${_output}\n${_error}" MATCHES "CMake Warning \\(dev\\) at [^\n]*cmake/gaol_[a-z_]+\\.cmake") - message(FATAL_ERROR "${_title}: CMake warned in a file of GAOL that CPack reads:\n${_output}\n${_error}") +# Without a warning of CMake for the files CPack reads: those of GAOL, which it +# reads without the policies of CMakeLists.txt, and the configuration CMake +# writes for it (an invalid escape sequence with CMake 3, CMP0010) +if("${_output}\n${_error}" MATCHES "CMake Warning \\(dev\\)") + message(FATAL_ERROR "${_title}: CMake warned in a file CPack reads:\n${_output}\n${_error}") endif() string(REGEX REPLACE "[ \t\r\n]+" " " _text "${_output} ${_error}") string(FIND "${_text}" "configure was generated for GAOL ${_old}, and VERSION.txt holds ${_new}:" _found) @@ -211,6 +216,10 @@ execute_process(COMMAND "${CMAKE_COMMAND}" -E tar tzf "gaol-${_new}.tar.gz" if(NOT _list MATCHES "(^|\n)gaol-${_new}/VERSION\\.txt\n") message(FATAL_ERROR "${_title}: gaol-${_new}.tar.gz holds no gaol-${_new}/VERSION.txt") endif() +if(NOT _list MATCHES "(^|\n)gaol-${_new}/keep\\.halo\n") + message(FATAL_ERROR "${_title}: gaol-${_new}.tar.gz holds no gaol-${_new}/keep.halo, which " + "CPACK_SOURCE_IGNORE_FILES does not match (were its backslashes lost?)") +endif() message(STATUS "${_title}: WARNS and gaol-${_new}.tar.gz, as expected") # The same, with the line ends of Windows From 692d7139753b81f1001b3bb0fd78adf59a5be51c Mon Sep 17 00:00:00 2001 From: Jordan08 Date: Tue, 6 Oct 2026 11:17:05 +0200 Subject: [PATCH 11/11] doc/tests.md: the warnings and the ignored files cpack_stale_configure checks in the archive --- doc/tests.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/doc/tests.md b/doc/tests.md index 6526d876..392c1ba6 100644 --- a/doc/tests.md +++ b/doc/tests.md @@ -711,17 +711,22 @@ mode there. for the version `configure` was generated for has its `VERSION.txt` changed, and CPack, run as `package_source` runs it, has to configure it again, warn, and name the archive after the new version - (`cmake/gaol_package_source.cmake`), which the Makefile generators did not do. - The version `configure` was generated for is asked of `configure --version`, - not read as `CMakeLists.txt` reads it. The copies are made of symbolic links - to the files of the tree, but for `CMakeLists.txt`, `VERSION.txt` and - `configure`, which are copied. The compilers are given to CMake as `CC` and - `CXX` with their arguments (`CC="ccache gcc"` leaves `ccache` in - `CMAKE_C_COMPILER` and `gcc` in `CMAKE_C_COMPILER_ARG1`), and the generator - with its program (`CMAKE_MAKE_PROGRAM`, for a Ninja outside `PATH`), which a - job of `.github/workflows/linux.yml` checks; without `sh`, or where the system - makes no symbolic link, the test says it is skipped. It takes a few seconds on - an ordinary machine, a configuration and five that reuse its checks, and an + (`cmake/gaol_package_source.cmake`), which the Makefile generators did not do, + CMake giving no warning of its own meanwhile (CMake 3 warned of the + backslashes of `CPACK_SOURCE_IGNORE_FILES` in the configuration it writes for + CPack); the archive has to hold `keep.halo`, a file of the copy that these + regular expressions do not match, but would without their backslashes, as + CMake 4 read them without `CPACK_VERBATIM_VARIABLES`. The version `configure` + was generated for is asked of `configure --version`, not read as + `CMakeLists.txt` reads it. The copies are made of symbolic links to the files + of the tree, but for `CMakeLists.txt`, `VERSION.txt` and `configure`, which + are copied. The compilers are given to CMake as `CC` and `CXX` with their + arguments (`CC="ccache gcc"` leaves `ccache` in `CMAKE_C_COMPILER` and `gcc` + in `CMAKE_C_COMPILER_ARG1`), and the generator with its program + (`CMAKE_MAKE_PROGRAM`, for a Ninja outside `PATH`), which a job of + `.github/workflows/linux.yml` checks; without `sh`, or where the system makes + no symbolic link, the test says it is skipped. It takes a few seconds on an + ordinary machine, a configuration and five that reuse its checks, and an archive: of the links themselves with CMake 3.28 and after (170 KB), of the files of the directories they point to with CMake 3.14 and 3.16 (5.6 MB). Only the CMake build has it: CPack makes the archive, and the autotools jobs of the