diff --git a/.github/scripts/version-file.sh b/.github/scripts/version-file.sh index e2c9e0bc..ac26efc8 100644 --- a/.github/scripts/version-file.sh +++ b/.github/scripts/version-file.sh @@ -40,8 +40,10 @@ work=$(mktemp -d "${TMPDIR:-/tmp}/gaol-version.XXXXXX") trap 'rm -rf "$work"' EXIT INT TERM mkdir "$work/src" # -h: README is a symbolic link to README.md, which tar of MSYS2 cannot create when it -# extracts it ("Cannot create symlink"): the copy holds the file itself -tar -c -h -f - --exclude=.git --exclude=autom4te.cache . | tar -x -f - -C "$work/src" +# extracts it ("Cannot create symlink"): the copy holds the file itself. Not +# the link that tests/meson_subproject takes as its subproject, which leads +# back to the root of the sources, and which -h would follow without end +tar -c -h -f - --exclude=.git --exclude=autom4te.cache --exclude=./tests/meson_subproject/subprojects . | tar -x -f - -C "$work/src" cd "$work" # The version is not the one of GAOL: it is the file the build reads, not a diff --git a/.github/workflows/build-systems.yml b/.github/workflows/build-systems.yml index c9f2d5b6..56164c86 100644 --- a/.github/workflows/build-systems.yml +++ b/.github/workflows/build-systems.yml @@ -9,7 +9,8 @@ # locale writing a decimal comma, which the Linux jobs and the containers # generate first, macOS and Windows having one (.github/scripts/comma-locale.sh, # GAOL v5). The autotools jobs check that make distclean gives the sources back -# as git has them. +# as git has them. One job builds GAOL as a subproject of a meson project +# (tests/meson_subproject, GAOL v5). # # Copyright (c) 2026 ENSTA, France # @@ -87,6 +88,7 @@ jobs: sh .github/scripts/version-file.sh autoconf - name: Configure, build and install run: | + set -o pipefail # The same date on every file, as in a release archive: make then # does not regenerate configure, the Makefile.in or the lexer find . -path ./.git -prune -o -exec touch -h -d '2020-01-01 00:00:00' {} + @@ -131,7 +133,9 @@ jobs: run: | sh .github/scripts/tests.sh "$RUNNER_TEMP/gaol" static - name: Performance - run: ./performance | tee -a "$GITHUB_STEP_SUMMARY" + run: | + set -o pipefail + ./performance | tee -a "$GITHUB_STEP_SUMMARY" meson: name: ${{ matrix.cfg.desc }} @@ -189,6 +193,7 @@ jobs: PATH="$nopython" meson setup "$RUNNER_TEMP/build-no-python" - name: Configure, build and install run: | + set -o pipefail meson --version meson setup build-meson --prefix="$RUNNER_TEMP/gaol" --libdir=lib -Dwith-tests=true ${{ matrix.cfg.options }} | tee configure.log meson compile -C build-meson @@ -207,7 +212,67 @@ jobs: - name: Tests built with the installed GAOL run: sh .github/scripts/tests.sh "$RUNNER_TEMP/gaol" shared - name: Performance - run: ./performance | tee -a "$GITHUB_STEP_SUMMARY" + run: | + set -o pipefail + ./performance | tee -a "$GITHUB_STEP_SUMMARY" + + # GAOL as a subproject of a meson project, tests/meson_subproject, which + # builds tests of tests/ with gaol_dep and checks that their code gets the + # flags of interval arithmetic, and that GAOL is built in release in the + # default build type of meson: meson refused the add_global_arguments() of + # meson.build in a subproject, and before 1.8.4 gives a subproject the build + # type of the project, which the meson of Ubuntu 24.04 (1.3.2) checks (GAOL + # v5) + meson-subproject: + name: ${{ matrix.cfg.desc }} + runs-on: ubuntu-24.04 + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + cfg: + - { meson: pipx, desc: 'Meson, Ubuntu 24.04 x86_64, GAOL as a subproject' } + - { meson: apt, desc: 'Meson of Ubuntu 24.04, x86_64, GAOL as a subproject' } + steps: + - uses: actions/checkout@v7 + - name: Tools + run: | + sudo apt-get update -q + if [ "${{ matrix.cfg.meson }}" = pipx ]; then + sudo apt-get install -y -q g++ pipx + pipx install meson + pipx install ninja + echo "$HOME/.local/bin" >> "$GITHUB_PATH" + else + sudo apt-get install -y -q g++ meson ninja-build + fi + - name: Configure tests/meson_subproject, a project bringing GAOL in as a subproject, from this checkout + run: | + set -o pipefail + meson --version + # The meson of Ubuntu has to be older than 1.8.4, which builds a + # subproject in its own default build type itself + if [ "${{ matrix.cfg.meson }}" = apt ]; then + python3 -c 'import sys; sys.exit(tuple(map(int, sys.argv[1].split(".")[:3])) >= (1, 8, 4))' "$(meson --version)" + fi + mkdir tests/meson_subproject/subprojects + ln -s "$PWD" tests/meson_subproject/subprojects/gaol + meson setup build-meson-subproject tests/meson_subproject | tee configure.log + grep -q "Elementary functions: CORE-MATH" configure.log + - name: Build + run: meson compile -C build-meson-subproject + - name: Locale writing a decimal comma + run: sh .github/scripts/comma-locale.sh generate + - name: Tests (ninja test, make test of meson), the flags of their code among them + run: ninja -C build-meson-subproject test + - name: The test numbers ran under a locale writing a decimal comma + run: sh .github/scripts/comma-locale.sh check build-meson-subproject/meson-logs/testlog.txt + - name: enable-debug builds GAOL for debugging, as a subproject and alone + run: | + meson setup build-meson-subproject-debug tests/meson_subproject -Dgaol:enable-debug=true + python3 tests/release_flags.py --debug build-meson-subproject-debug "$PWD/tests/meson_subproject/subprojects/gaol" + meson setup build-meson-debug -Denable-debug=true + python3 tests/release_flags.py --debug build-meson-debug "$PWD" # meson with Visual C++: the static libgaol, as CMake builds it, its tests, # and the installed GAOL, with which a test is compiled again (GAOL v5). In @@ -308,7 +373,8 @@ jobs: sh .github/scripts/comma-locale.sh check build-meson/meson-logs/testlog.txt sh .github/scripts/tests.sh /tmp/gaol shared fi - ./performance | tee /gaol/performance.md" + ./performance > /gaol/performance.md + cat /gaol/performance.md" cat performance.md >> "$GITHUB_STEP_SUMMARY" msys2: @@ -355,7 +421,9 @@ jobs: - name: Tests built with the installed GAOL run: sh .github/scripts/tests.sh "$(cygpath -m "$RUNNER_TEMP")/gaol" static - name: Performance - run: ./performance | tee -a "$GITHUB_STEP_SUMMARY" + run: | + set -o pipefail + ./performance | tee -a "$GITHUB_STEP_SUMMARY" # The three builds give GAOL the same configuration (.github/audit) agree: diff --git a/.github/workflows/containers.yml b/.github/workflows/containers.yml index 5c176c14..b3dadb1d 100644 --- a/.github/workflows/containers.yml +++ b/.github/workflows/containers.yml @@ -101,7 +101,8 @@ jobs: cmake --build /tmp/build --target test $comma_check cd /tmp/build - ./tests/gaol_performance | tee /gaol/performance.md" + ./tests/gaol_performance > /gaol/performance.md + cat /gaol/performance.md" cat performance.md >> "$GITHUB_STEP_SUMMARY" clang-arm32: diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 5d51a055..99750387 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -3,8 +3,9 @@ # (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). The test cpack_stale_configure also runs -# with ccache in CC and Ninja outside PATH. +# FetchContent (tests/fetch_content), which builds GAOL as in Release where it +# gives no build type (tests/release_flags.py, GAOL v5). 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 @@ -96,7 +97,9 @@ jobs: - name: The test numbers ran under a locale writing a decimal comma run: sh .github/scripts/comma-locale.sh check build - name: Performance - run: build/tests/gaol_performance | tee -a "$GITHUB_STEP_SUMMARY" + run: | + set -o pipefail + build/tests/gaol_performance | tee -a "$GITHUB_STEP_SUMMARY" - name: Install run: cmake --install build - name: Tests built with the installed GAOL @@ -300,8 +303,15 @@ jobs: run: sh .github/scripts/comma-locale.sh generate - name: Configure tests/fetch_content, a project building GAOL for itself with FetchContent, from this checkout run: | + set -o pipefail cmake -S tests/fetch_content -B build-fetch-content -DCMAKE_BUILD_TYPE=Release -DFETCHCONTENT_SOURCE_DIR_GAOL="$PWD" -DCMAKE_INSTALL_PREFIX="$PWD/gaol-install" | tee configure.log grep -q "Elementary functions: CORE-MATH" configure.log + - name: Without a build type, GAOL and CORE-MATH compiled as in Release all the same + run: | + # configure only: tests/release_flags.py reads compile_commands.json + # (GAOL v5: CORE-MATH was compiled without optimization) + cmake -S tests/fetch_content -B build-fetch-content-default -DFETCHCONTENT_SOURCE_DIR_GAOL="$PWD" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + python3 tests/release_flags.py build-fetch-content-default "$PWD" - name: Build run: cmake --build build-fetch-content -j 4 - name: Tests (make test) @@ -324,6 +334,66 @@ jobs: cmake --build build-find-package -j 4 cmake --build build-find-package --target test + # The build types, configured only: GAOL_DEBUG builds the libraries of GAOL + # and CORE-MATH for debugging whatever the build type, a project bringing + # GAOL in included, and a generator of several configurations builds Release + # by default (tests/release_flags.py, GAOL v5) + build-types: + name: Ubuntu 24.04 x86_64 GCC, GAOL_DEBUG and Ninja Multi-Config + runs-on: ubuntu-24.04 + timeout-minutes: 30 + steps: + - uses: actions/checkout@v7 + - name: Tools + run: | + sudo apt-get update -q + sudo apt-get install -y -q ninja-build + - name: GAOL_DEBUG, GAOL built alone in Release + run: | + cmake -S . -B build-debug -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON -DGAOL_DEBUG=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + python3 tests/release_flags.py --debug build-debug "$PWD" + - name: GAOL_DEBUG, GAOL brought in by FetchContent without a build type, and in Release + run: | + cmake -S tests/fetch_content -B build-fetch-content-debug -DFETCHCONTENT_SOURCE_DIR_GAOL="$PWD" -DGAOL_DEBUG=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + python3 tests/release_flags.py --debug build-fetch-content-debug "$PWD" + cmake -S tests/fetch_content -B build-fetch-content-release-debug -DFETCHCONTENT_SOURCE_DIR_GAOL="$PWD" -DGAOL_DEBUG=ON \ + -DCMAKE_BUILD_TYPE=Release "-DCMAKE_CXX_FLAGS_RELEASE=-O3 -DNDEBUG -DPROJECT_RELEASE" "-DCMAKE_CXX_FLAGS_DEBUG=-g -DPROJECT_DEBUG" \ + -DCMAKE_EXPORT_COMPILE_COMMANDS=ON + python3 tests/release_flags.py --debug build-fetch-content-release-debug "$PWD" + - name: GAOL_DEBUG reaches the libraries of GAOL alone, and keeps the other flags of the configuration + run: | + # GAOL takes the flags of the configuration less the optimization and + # NDEBUG, never those of Debug, which may hold what the code of the + # project does not get (a sanitizer, a C runtime); the tests of GAOL + # and of the project keep theirs + python3 - "$PWD" <<'EOF' + import json, os, sys + src = os.path.normpath(sys.argv[1]) + def commands(build): + for e in json.load(open(os.path.join(build, 'compile_commands.json'))): + if e['file'].endswith('.cpp'): + yield os.path.normpath(os.path.join(e['directory'], e['file'])), e['command'].split() + gaol, tests = os.path.join(src, 'gaol') + os.sep, os.path.join(src, 'tests') + os.sep + seen = 0 + for path, flags in commands('build-debug'): + if path.startswith(tests): + assert '-O3' in flags and '-DNDEBUG' in flags, (path, flags); seen += 1 + for path, flags in commands('build-fetch-content-release-debug'): + if path.startswith(gaol): + assert '-DPROJECT_RELEASE' in flags and '-DPROJECT_DEBUG' not in flags, (path, flags); seen += 1 + elif path.startswith(tests): + assert '-O3' in flags and '-DNDEBUG' in flags and '-DPROJECT_RELEASE' in flags, (path, flags); seen += 1 + assert seen, 'no command checked' + print(seen, 'commands checked') + EOF + - name: Ninja Multi-Config builds Release by default + run: | + cmake -G "Ninja Multi-Config" -S . -B build-multi + grep '^CMAKE_CONFIGURATION_TYPES:' build-multi/CMakeCache.txt + ninja -C build-multi -n > plan.txt + grep -q 'CMakeFiles/gaol.dir/Release/' plan.txt + if grep -q 'CMakeFiles/gaol.dir/Debug/' plan.txt; then echo "Debug built by default"; exit 1; fi + # The 128-bit integer computed with two 64-bit halves, which is the code # Visual C++ and the 32-bit targets of GCC take: built and tested on an # ordinary machine, where the native type is there to compare with @@ -345,6 +415,7 @@ jobs: run: sh .github/scripts/comma-locale.sh generate - name: Configure run: | + set -o pipefail cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DWITH_TESTS=ON \ -DGAOL_U128_EMULATION=ON -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \ -DCMAKE_C_COMPILER=${{ matrix.cc }} -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} | tee configure.log diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 43794bc9..327934f9 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -65,7 +65,9 @@ jobs: - name: The test numbers ran under a locale writing a decimal comma run: sh .github/scripts/comma-locale.sh check build - name: Performance - run: build/tests/gaol_performance | tee -a "$GITHUB_STEP_SUMMARY" + run: | + set -o pipefail + build/tests/gaol_performance | tee -a "$GITHUB_STEP_SUMMARY" - name: Install run: cmake --install build - name: Tests built with the installed GAOL diff --git a/.gitignore b/.gitignore index dadb3d90..1c0d91ce 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,10 @@ coverage/coverage.json 3rd/math-core/**/.deps/ 3rd/math-core/**/.dirstamp +# The link to the sources of GAOL that tests/meson_subproject takes as its +# subproject (see its meson.build) +tests/meson_subproject/subprojects/ + # Written by the performance target of check/Makefile.am check/performances_result.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 483937c7..a566049e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,6 +50,14 @@ if(_gaol_version_error) message(FATAL_ERROR "${_gaol_version_error}") endif() +# Whether the configurations of a generator of several were given, on the +# command line or in the environment, before project() sets their default +if(DEFINED CMAKE_CONFIGURATION_TYPES OR DEFINED ENV{CMAKE_CONFIGURATION_TYPES}) + set(_gaol_configuration_types_given ON) +else() + set(_gaol_configuration_types_given OFF) +endif() + project(gaol VERSION ${_gaol_version} LANGUAGES C CXX) # A change of VERSION.txt configures again @@ -69,6 +77,17 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE) endif() + # With a generator of several configurations (Visual Studio, Xcode, Ninja + # Multi-Config), Release first among them, unless they were given: Ninja + # Multi-Config builds the first by default. cmake --build with Visual Studio + # builds Debug all the same without --config (GAOL v5) + get_property(_gaol_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(_gaol_multi_config AND NOT _gaol_configuration_types_given AND "Release" IN_LIST CMAKE_CONFIGURATION_TYPES) + set(_gaol_types ${CMAKE_CONFIGURATION_TYPES}) + list(REMOVE_ITEM _gaol_types Release) + list(INSERT _gaol_types 0 Release) + set(CMAKE_CONFIGURATION_TYPES "${_gaol_types}" CACHE STRING "The configurations of the generator" FORCE) + endif() endif() # libgaol, a static library, is compiled as position-independent @@ -103,6 +122,10 @@ option(WITH_EXAMPLES "Build the examples of examples/, which make check runs" OF option(GAOL_SIMD "Compute the intervals with SSE2 instructions on x86 processors" ON) option(GAOL_ASM "Use assembler code (GAOL_USING_ASM)" ON) option(GAOL_VERBOSE_MODE "Write a line on the standard error when GAOL initializes and cleans up" OFF) +# GAOL and CORE-MATH built for debugging whatever the build type or the +# configuration, a project bringing GAOL in included, as enable-debug of meson +# and --enable-debug of configure (GAOL v5; see the end of this file) +option(GAOL_DEBUG "Build GAOL and CORE-MATH for debugging, without optimization and with GAOL_DEBUGGING, whatever the build type or the configuration" OFF) # No option for the intervals of floats, gaol::intervalf and gaol::interval2f, # unfinished, which only a developer of GAOL compiles (see gaol/gaol_config.h) # Coverage: the library and the tests compiled with the counters of gcov @@ -562,7 +585,7 @@ set(GAOL_EXCEPTIONS_ENABLED ON) # generator of several configurations (Visual Studio, Xcode), whose # configurations share gaol/gaol_configuration.h, GAOL_DEBUGGING is given to # the sources of GAOL in the Debug configuration below. -if(CMAKE_BUILD_TYPE STREQUAL "Debug") +if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR GAOL_DEBUG) set(GAOL_DEBUGGING ON) endif() @@ -676,12 +699,15 @@ if(NOT MSVC) endif() endforeach() # The optimizations configure adds to -O3, in the Release configuration + # (not with GAOL_DEBUG) + set(GAOL_RELEASE_FLAGS "") foreach(flag -funroll-loops -fomit-frame-pointer -fexpensive-optimizations) string(MAKE_C_IDENTIFIER "${flag}" _flag_id) string(TOUPPER "GAOL_COMPILER_SUPPORTS${_flag_id}" _flag_var) check_cxx_compiler_flag("${flag}" ${_flag_var}) - if(${_flag_var}) + if(${_flag_var} AND NOT GAOL_DEBUG) list(APPEND GAOL_LIBRARY_FLAGS "$<$:${flag}>") + list(APPEND GAOL_RELEASE_FLAGS ${flag}) endif() endforeach() endif() @@ -787,14 +813,19 @@ endif() # Without a build type, CMake gives no optimization flag at all. GAOL sets # Release when it is the top-level project, but brought in by a project that # sets none (add_subdirectory, FetchContent), GAOL and CORE-MATH were compiled -# without optimization: they are compiled with -O3 then, as in Release (/O2 -# with Visual C++). -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - if(MSVC) - target_compile_options(gaol PRIVATE /O2) - else() - target_compile_options(gaol PRIVATE -O3) - endif() +# without optimization: they are compiled then as in Release, with -O3 (/O2 +# with Visual C++), NDEBUG and the optimizations configure adds, as configure +# and meson build GAOL brought into another project (GAOL v5: GAOL alone had +# -O3, and CORE-MATH, compiled apart, no optimization) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES AND NOT GAOL_DEBUG) + foreach(target gaol gaol_core_math) + if(MSVC) + target_compile_options(${target} PRIVATE /O2) + else() + target_compile_options(${target} PRIVATE -O3 ${GAOL_RELEASE_FLAGS}) + endif() + target_compile_definitions(${target} PRIVATE NDEBUG) + endforeach() endif() if(MSVC) # The lexer includes , which Visual C++ does not have @@ -946,7 +977,7 @@ if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) set(CPACK_SOURCE_IGNORE_FILES "/\\.git/" "/\\.git$" "/\\.claude/" "/\\.vscode/" "/\\.idea/" "/\\.cache/" "\\.swp$" "~$" "/#" "/\\.#" - "/autom4te\\.cache/" "/doc/compare/code/work/" + "/autom4te\\.cache/" "/doc/compare/code/work/" "/tests/meson_subproject/subprojects/" "/coverage/[^/]*\\.(css|js)$" "/coverage/coverage\\.json$" "\\.o$" "\\.lo$" "/\\.libs/" "/\\.deps/" "\\.dirstamp$" "/check/performances_result\\.txt$" "^${_gaol_source_regex}/build[^/]*/" "/_CPack_Packages/" @@ -1080,9 +1111,10 @@ endif() # doc/compare/code/results.csv holds (see doc/compare/code/run_perf.sh). It # needs bash and Python 3 with numpy, which draws the intervals. GAOL 4.2.3, # filib++, libieeep1788 and PROFIL/BIAS are not run: doc/compare/code/run_all.sh -# measures them all again. Linux only, as the benchmark (GAOL v5). +# measures them all again. Linux only, as the benchmark, and not with +# GAOL_DEBUG, which would measure GAOL built for debugging (GAOL v5). -if(GAOL_IS_TOP_LEVEL AND CMAKE_SYSTEM_NAME STREQUAL "Linux") +if(GAOL_IS_TOP_LEVEL AND CMAKE_SYSTEM_NAME STREQUAL "Linux" AND NOT GAOL_DEBUG) find_program(GAOL_BASH bash) mark_as_advanced(GAOL_BASH) if(GAOL_BASH) @@ -1167,3 +1199,47 @@ if(GAOL_COVERAGE) COMMENT "Running the tests and writing the coverage report in coverage/" VERBATIM) endif() + +# GAOL_DEBUG: the targets of this directory, libgaol and the sources of +# CORE-MATH, compiled without optimization nor NDEBUG and with debugging +# information in every configuration (GAOL v5). Each configuration keeps its +# own flags but those of optimization and NDEBUG (the C runtime of Visual C++, +# sanitizers, macros of the project...), so that GAOL still links with the +# code of that configuration; where no build type is given, the flags are +# added to those of the project. The flags of a configuration are those of the +# directory of the target at its end: the tests and the examples, whose +# directories were added before, keep theirs, as does a project bringing GAOL +# in. With Visual C++, the debugging information is the property +# MSVC_DEBUG_INFORMATION_FORMAT where CMP0141 is NEW (CMake 3.25 and later), and +# /Zi otherwise. +if(GAOL_DEBUG) + if(MSVC) + set(_gaol_debug_flags /Od /Ob0) + set(_gaol_cmp0141 OLD) + if(POLICY CMP0141) + cmake_policy(GET CMP0141 _gaol_cmp0141) + endif() + if(_gaol_cmp0141 STREQUAL "NEW") + set_property(TARGET gaol gaol_core_math PROPERTY MSVC_DEBUG_INFORMATION_FORMAT ProgramDatabase) + else() + list(APPEND _gaol_debug_flags /Zi) + endif() + else() + set(_gaol_debug_flags -O0 -g) + endif() + string(REPLACE ";" " " _gaol_debug_string "${_gaol_debug_flags}") + foreach(lang C CXX) + if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) + foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES CMAKE_BUILD_TYPE) + string(TOUPPER "${config}" config) + separate_arguments(_gaol_flags UNIX_COMMAND "${CMAKE_${lang}_FLAGS_${config}}") + list(FILTER _gaol_flags EXCLUDE REGEX "^[-/](O[0-9sgdxz]?|Ofast|Ob[0-3]|DNDEBUG(=.*)?)$") + list(APPEND _gaol_flags ${_gaol_debug_flags}) + string(REPLACE ";" " " _gaol_flags "${_gaol_flags}") + set(CMAKE_${lang}_FLAGS_${config} "${_gaol_flags}") + endforeach() + else() + set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} ${_gaol_debug_string}") + endif() + endforeach() +endif() diff --git a/README.md b/README.md index adff3a8d..75eda5b5 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,8 @@ target_link_libraries(my_target PRIVATE gaol::gaol) `gaol::gaol`, and `gaol.pc` for pkg-config, carry the flags of interval arithmetic that the code including GAOL's headers has to be compiled with. A project can also build GAOL for itself, with FetchContent (see -[Using GAOL](doc/using.md#from-cmake)). +[Using GAOL](doc/using.md#from-cmake)), or as a meson subproject (see +[Using GAOL](doc/using.md#from-pkg-config)). A program calls `gaol::cleanup()` right after its last use of GAOL: GAOL's initialization, which runs by itself before `main()`, sets the diff --git a/doc/building.md b/doc/building.md index 65289550..9c7ab05c 100644 --- a/doc/building.md +++ b/doc/building.md @@ -109,8 +109,15 @@ CMake 3.14 or later. The build compiles the thirty-six sources of CORE-MATH into `libgaol`, which is static unless `BUILD_SHARED_LIBS` is `ON`: there is nothing else to build and nothing else to install. The build type is Release unless another is given; brought in by a project that gives none -(`add_subdirectory`, FetchContent), GAOL and CORE-MATH are compiled with `-O3` -all the same (`/O2` with Visual C++). +(`add_subdirectory`, FetchContent), GAOL and CORE-MATH are compiled as in +Release all the same: `-O3` (`/O2` with Visual C++), `NDEBUG` and the +optimizations of configure (GAOL v5: GAOL had `-O3` alone, and CORE-MATH no +optimization). With a generator of several configurations (Visual Studio, +Xcode, Ninja Multi-Config), GAOL built alone puts Release first among them, +which Ninja Multi-Config builds by default, unless `CMAKE_CONFIGURATION_TYPES` +is given; `cmake --build` with Visual Studio builds Debug all the same without +`--config` (GAOL v5). `GAOL_DEBUG` builds GAOL for debugging whatever the +build type or the configuration (below). | Option | Default | | |---|---|---| @@ -126,6 +133,7 @@ all the same (`/O2` with Visual C++). | `GAOL_FMA` | `ON` | Compile GAOL and CORE-MATH with the fused multiply-add instructions of the processor, where the compiler has a flag for them and the machine building runs a program compiled with it (not checked when cross-compiling): `-mfma` on x86 (not with GCC for Windows), `/arch:AVX2` with Visual C++ for x64, `-mfpu=neon-vfpv4 -mfloat-abi=hard` on 32-bit ARM; 64-bit ARM, POWER, s390x and RISC-V have them without a flag. The library then needs a processor with them (on x86, Intel Haswell and AMD Piledriver, 2012-2013, and later); `OFF` builds it for any processor of the architecture. The code using GAOL is given the flag too, in `gaol::gaol` and `gaol.pc`, and `-ffp-contract=off` stays (see [The three builds](three-builds.md)) | | `GAOL_ASM` | `ON` | Use GAOL's assembly code where it has some (`GAOL_USING_ASM`) | | `GAOL_VERBOSE_MODE` | `OFF` | Write a line on the standard error when GAOL initializes and cleans up (`GAOL_VERBOSE_MODE`); GAOL is silent by default | +| `GAOL_DEBUG` | `OFF` | Build `libgaol` and CORE-MATH for debugging, without optimization nor `NDEBUG`, with debugging information and `GAOL_DEBUGGING`, whatever the build type or the configuration, a project bringing GAOL in included, as `enable-debug` of meson and `--enable-debug` of configure. Each configuration keeps its other flags (the C runtime of Visual C++, sanitizers...); the tests and the examples, and the code of that project, keep their build type; there is no target `perf` (GAOL v5) | | `GAOL_PRESERVE_ROUNDING` | `OFF` | Restore the rounding direction found after each operation, rather than leaving it upward (see [The rounding direction](using.md#the-rounding-direction)) | | `GAOL_PREFER_AVX512` | `OFF`, `ON` with `GAOL_PRESERVE_ROUNDING` | Have +, -, *, / and sqrt take the AVX-512 instructions and the rounding direction they carry in themselves, on a processor that has them, which sets neither the rounding direction nor the flush-to-zero modes (GAOL v5, see [The rounding direction](using.md#the-avx-512-path)) | @@ -208,7 +216,7 @@ their defaults: | Option | Default | | |---|---|---| | `--enable-optimize` | `yes` | `-O3 -funroll-loops -fomit-frame-pointer -fexpensive-optimizations` and `NDEBUG`, for the C++ and C sources alike (GAOL and CORE-MATH), as the Release build of CMake; `--disable-optimize` compiles with `-O` | -| `--enable-debug` | `no` | The Debug build of CMake: `-g`, no optimization and no `NDEBUG` (`--enable-optimize` is then ignored), and GAOL's assertions (`GAOL_DEBUGGING`) | +| `--enable-debug` | `no` | The Debug build of CMake: `-g`, no optimization and no `NDEBUG` (`--enable-optimize` is then ignored), and GAOL's assertions (`GAOL_DEBUGGING`); brought into another project with `AC_CONFIG_SUBDIRS`, the `--enable-debug` of its configure, which passes on its options (and which that configure may read too), for the tests of GAOL as well, where `GAOL_DEBUG` of CMake and `enable-debug` of meson build the libraries alone so | | `--enable-simd` | `yes` | The SSE2 intervals on x86 processors, as `GAOL_SIMD` | | `--enable-fma` | `yes` | The fused multiply-add instructions of the processor, as `GAOL_FMA` | | `--enable-asm` | `yes` | GAOL's assembly code, as `GAOL_ASM` | @@ -244,10 +252,11 @@ Ubuntu 20.04, `ninja -C build` builds GAOL as well. The options | Option | Default | | |---|---|---| -| `buildtype` | `release` | `-O3`, `NDEBUG` and `-funroll-loops -fomit-frame-pointer -fexpensive-optimizations`, as the Release build of CMake and configure; `debug` builds GAOL without optimization, with debugging information, and GAOL checks its assertions (`GAOL_DEBUGGING`), as the Debug build of CMake and `configure --enable-debug`. The options `enable-optimize` and `enable-debug` are gone | +| `buildtype` | `release` | `-O3`, `NDEBUG` and `-funroll-loops -fomit-frame-pointer -fexpensive-optimizations`, as the Release build of CMake and configure; `debug` builds GAOL without optimization, with debugging information, and GAOL checks its assertions (`GAOL_DEBUGGING`), as the Debug build of CMake and `configure --enable-debug`. The option `enable-optimize` is gone. Brought in as a subproject, GAOL is built in `release` too where the project leaves the build type to its default (GAOL v5, see [Using GAOL](using.md#from-pkg-config)) | | `enable-simd` | `true` | The SSE2 intervals on x86 processors, as `GAOL_SIMD` | | `enable-fma` | `true` | The fused multiply-add instructions of the processor, as `GAOL_FMA` | | `enable-asm` | `true` | GAOL's assembly code, as `GAOL_ASM` | +| `enable-debug` | `false` | Build `libgaol` and CORE-MATH for debugging, without optimization nor `NDEBUG` and with `GAOL_DEBUGGING`, whatever the build type, a subproject included (`-Dgaol:enable-debug=true`), as `GAOL_DEBUG` of CMake and `--enable-debug` of configure; the tests and the examples keep the build type, and there is no target `perf` (GAOL v5: it defined `GAOL_DEBUGGING` alone, and was gone) | | `enable-verbose-mode` | `false` | The line on the standard error, as `GAOL_VERBOSE_MODE` | | `enable-preserve-rounding` | `false` | Restore the rounding direction after each operation, as `GAOL_PRESERVE_ROUNDING` | | `enable-prefer-avx512` | `false`, `true` with `enable-preserve-rounding` | Have +, -, *, / and sqrt take the AVX-512 instructions and the rounding direction they carry in themselves, on a processor that has them, as `GAOL_PREFER_AVX512`; meson cannot refuse the path under `enable-preserve-rounding`, which `-DGAOL_PREFER_AVX512=OFF` of CMake and `--disable-prefer-avx512` of configure do (GAOL v5) | @@ -275,16 +284,17 @@ of a file it refuses: the first of `python3` and `python` that it finds in Python for that name alone; the continuous integration checks it on Linux with a `meson setup` whose `PATH` holds no Python. -On Windows, the directory `%USERPROFILE%\AppData\Local\Microsoft\WindowsApps` -holds the aliases `python.exe` and `python3.exe`, which only open the -Microsoft Store when Python was not installed from it. meson 0.53.1 and later -(the 0.53.2 of Ubuntu 20.04 and the meson of pip among them) leave that -directory out of their search for programs, as long as `PATH` names it by -that path (not for a profile whose directory differs from `USERPROFILE`). -meson 0.53.0 and earlier take the alias, and `meson setup` stops on the -failure of the command that reads `VERSION.txt`: use a later meson -(`pip install meson`), or turn off the aliases of `python.exe` and -`python3.exe` in the Windows settings ("Manage app execution aliases"). +On Windows, none of what follows was checked, but read in the sources of +meson. The directory `%USERPROFILE%\AppData\Local\Microsoft\WindowsApps` can +hold aliases of Python, `python3.exe` and perhaps `python.exe` too, which only +open the Microsoft Store when Python was not installed from it. meson 0.53.1 +and later (the 0.53.2 of Ubuntu 20.04 and the meson of pip among them) leave +that directory out of their search for programs, as long as `PATH` names it +by that path (not for a profile whose directory differs from `USERPROFILE`). +meson 0.53.0 and earlier may take such an alias, and `meson setup` then stops +on the failure of the command that reads `VERSION.txt`: use a later meson +(`pip install meson`), or turn off the aliases of Python in the Windows +settings ("Manage app execution aliases"). ## Tests, examples, performance and the parser @@ -337,7 +347,7 @@ integration checks that they write the same header on each kind of machine | Macro | Defined | CMake | configure | meson | |---|---|---|---|---| | `GAOL_MAJOR_VERSION`, `GAOL_MINOR_VERSION`, `GAOL_MICRO_VERSION`, `GAOL_VERSION` | Always, from `VERSION.txt` (see [above](#the-version-of-gaol)): `5`, `0`, `0` and `"5.0.0"` for GAOL 5.0.0 | `project()` | `VERSION.txt`, read when configure runs | `project()` | -| `GAOL_DEBUGGING` | In a Debug build: GAOL checks its assertions (`GAOL_ASSERT`), and `GAOL_DEBUG` runs its commands | `CMAKE_BUILD_TYPE=Debug` | `--enable-debug` | `--buildtype=debug` | +| `GAOL_DEBUGGING` | In a Debug build: GAOL checks its assertions (`GAOL_ASSERT`), and `GAOL_DEBUG_VERBOSE(level, command)` runs its commands | `CMAKE_BUILD_TYPE=Debug`, or `GAOL_DEBUG` | `--enable-debug` | `--buildtype=debug`, or `enable-debug` | | `GAOL_EXCEPTIONS_ENABLED` | GAOL raises exceptions rather than abort | always | `--enable-exceptions` (default) | `enable-exception` (default) | | `GAOL_PRESERVE_ROUNDING` | The operations restore the rounding direction they found | `GAOL_PRESERVE_ROUNDING` | `--enable-preserve-rounding` | `enable-preserve-rounding` | | `GAOL_PREFER_AVX512` | +, -, *, / and sqrt take the AVX-512 instructions on a processor that has them | `GAOL_PREFER_AVX512` (with `GAOL_PRESERVE_ROUNDING`) | `--enable-prefer-avx512` (with `--enable-preserve-rounding`) | `enable-prefer-avx512` (with `enable-preserve-rounding`) | diff --git a/doc/continuous-integration.md b/doc/continuous-integration.md index f622cacb..d8821b41 100644 --- a/doc/continuous-integration.md +++ b/doc/continuous-integration.md @@ -56,10 +56,19 @@ Visual Studio 2022 and 2026 (x64, x86), run the tests (`make test`, GAOL they install, which is the only library installed, CORE-MATH being compiled into it; build GAOL as a part of another project, brought in by FetchContent (`tests/fetch_content`), and the tests with the GAOL that project -installs; check that the three builds agree on each of these machines; check -that configure and meson, and autoconf when it generates configure (Linux), -read a `VERSION.txt` that starts with a byte order mark or has the line ends -of Windows (`.github/scripts/version-file.sh`), and that meson reads it with +installs, and check that GAOL and CORE-MATH are compiled as in Release where +that project gives no build type (`tests/release_flags.py`, GAOL v5); build +GAOL as a subproject of a meson project (`tests/meson_subproject`, Ubuntu +x86_64, with the meson of pipx and the meson 1.3 of Ubuntu), whose code +compiled with `gaol_dep` has to get the flags of `gaol.pc`, and GAOL to be +built in release in the default build type of meson (GAOL v5); check that +`GAOL_DEBUG` and `enable-debug` build GAOL for debugging, alone and brought +into another project, and that GAOL built alone with Ninja Multi-Config builds +Release by default (`linux.yml`, `build-systems.yml`, configured only, GAOL +v5); check that the three builds agree on each of these machines; check that +configure and meson, and autoconf when it generates configure (Linux), read a +`VERSION.txt` that starts with a byte order mark or has the line ends of +Windows (`.github/scripts/version-file.sh`), and that meson reads it with no Python on `PATH` (Linux); check that `make distclean` gives the source tree back as git has it, after the autotools have built, installed and tested GAOL in it (Ubuntu, macOS); check that the builds diff --git a/doc/tests.md b/doc/tests.md index 392c1ba6..cd680af9 100644 --- a/doc/tests.md +++ b/doc/tests.md @@ -339,8 +339,9 @@ mode there. read as in the C locale, and `exact_string()` has to write points and read back bit for bit: the reading never ended there, and the test, which ctest would otherwise let run with no limit, fails after 5 minutes should it hang - again (GAOL v5), in `tests/find_package` and `tests/fetch_content` too; the - cache variable `GAOL_NUMBERS_TIMEOUT` gives it more time on a slower build + again (GAOL v5), in `tests/find_package`, `tests/fetch_content` and + `tests/meson_subproject` too; the cache variable `GAOL_NUMBERS_TIMEOUT` + gives it more time on a slower build (600 s with GCC and the sanitizers on macOS x86_64). Numbers of 5000 to 20000 characters, in decimal, in hexadecimal and in the uncertain form, have to be read as the tightest enclosures, known without reading them (`1.5` followed by zeros is 1.5, and @@ -639,10 +640,11 @@ mode there. - **`debugging`:** GAOL's headers compiled with `GAOL_DEBUGGING`, which the Debug builds define (`CMAKE_BUILD_TYPE=Debug`, `configure --enable-debug`, `meson setup --buildtype=debug`), whatever the build: an expression is built - and evaluated, its nodes calling `GAOL_DEBUG`, which has to run its command - at the level given to `gaol::init()` and not above. `gaol/gaol_expression.h` - did not compile with `GAOL_DEBUGGING`: its `GAOL_DEBUG` wrote on `std::cout`, - which no header included (GAOL v5). + and evaluated, its nodes calling `GAOL_DEBUG_VERBOSE` (`GAOL_DEBUG` before + GAOL v5), which has to run its command at the level given to `gaol::init()` + and not above. `gaol/gaol_expression.h` did not compile with + `GAOL_DEBUGGING`: its `GAOL_DEBUG_VERBOSE` wrote on `std::cout`, which no + header included (GAOL v5). - **`version_file`** (CMake only: a script of CMake, not a program): the reading of `VERSION.txt` by `CMakeLists.txt`, `gaol_read_version()` of `cmake/gaol_version.cmake`, has to ignore a UTF-8 byte order mark at the @@ -809,6 +811,21 @@ the examples of `examples/` too, where they are built (see continuous integration runs `make test` in every job. `tests/find_package` builds some of the same tests with an installed GAOL, and `.github/scripts/tests.sh` with a GAOL installed by configure or meson. +`tests/fetch_content` builds them with a GAOL brought in by FetchContent, and +`tests/meson_subproject` with a GAOL brought in as a meson subproject (GAOL +v5), which meson refused. Its test `flags` checks that `gaol_dep` gives their +compilation the flags of the `Cflags` of `gaol.pc`, without which the tests +pass all the same, and their link the options of its `Libs` (`-mno-daz-ftz`, +where the compiler takes it), and its test `release` that GAOL is built in release in +the default build type of meson, debug: `tests/release_flags.py` checks that +the sources of GAOL and CORE-MATH are compiled with `-O3` and `NDEBUG`, and +that `GAOL_DEBUGGING` is left undefined. The continuous integration runs it on +`tests/fetch_content` configured without a build type too, where CORE-MATH +was compiled without optimization. With `--debug`, it checks the other way +round that `GAOL_DEBUG` of CMake and `enable-debug` of meson build GAOL and +CORE-MATH for debugging (no optimization, no `NDEBUG`, `GAOL_DEBUGGING`), GAOL +built alone and brought into another project, which the continuous +integration configures (GAOL v5). `tests/performance.cpp` (`gaol_performance`) measures the time per operation of GAOL's arithmetic and elementary functions, of the constructor `interval(a, b)`, diff --git a/doc/three-builds.md b/doc/three-builds.md index 2733afa4..3eff07a5 100644 --- a/doc/three-builds.md +++ b/doc/three-builds.md @@ -14,7 +14,14 @@ build, and the CMake build follows them, apart from the errors corrected (see (`-funroll-loops -fomit-frame-pointer -fexpensive-optimizations`, each where the compiler takes it), `NDEBUG`, `-std=c++11`, hidden visibility (`-fvisibility=hidden -fvisibility-inlines-hidden`) and `-Wall -Wconversion`, - which GAOL compiles without warnings, `-Wsign-conversion` of Clang included; + which GAOL compiles without warnings, `-Wsign-conversion` of Clang included. + Its libraries are compiled in release too where a project brings GAOL in + without choosing a build type, as by a configure calling GAOL's: a CMake + project without `CMAKE_BUILD_TYPE`, with a generator of one configuration + (with a generator of several, as Visual Studio, Release comes first among + the configurations of GAOL built alone, and a project bringing GAOL in + chooses its configuration), a meson project in the default build type of + meson, with its ninja backend (GAOL v5); - with the flags of interval arithmetic of [Using GAOL](using.md), and the code using GAOL, the tests included, is linked with `-mno-daz-ftz` where the compiler accepts it (GCC 13 and later on x86, and from 11.4 and 12.4 in the @@ -78,7 +85,11 @@ optimization nor `NDEBUG`, and checks its assertions (`GAOL_DEBUGGING`). It was `configure --enable-debug` alone that defined `GAOL_DEBUGGING`, adding `-g -ansi -Weffc++ -pedantic` for `g++` alone to the optimizations of `--enable-optimize`; the Debug build of CMake did not define it, and meson -defined it with its option `enable-debug`, now gone (GAOL v5). +defined it with its option `enable-debug` (GAOL v5). `GAOL_DEBUG` of CMake and +`enable-debug` of meson build the libraries of GAOL and CORE-MATH so whatever +the build type or the configuration, a project bringing GAOL in included, as +`configure --enable-debug` does for a configure calling GAOL's: the code of +that project, and the tests and the examples, keep their own (GAOL v5). `.github/audit/` configures the three builds and compares the macros GAOL sees, the macros each writes into `gaol/gaol_configuration.h`, and the flags diff --git a/doc/using.md b/doc/using.md index 39e9b310..5f19e660 100644 --- a/doc/using.md +++ b/doc/using.md @@ -117,7 +117,10 @@ target_link_libraries(my_target PUBLIC gaol::gaol) GAOL is then a target of the project (`gaol::gaol`), built with it, and `cmake --install` of the project installs it with it, CMake package and `gaol.pc` included; nothing is downloaded beyond GAOL's sources. `tests/fetch_content` is a project -building GAOL this way. +building GAOL this way. GAOL is built in Release where the project gives no +build type, and `-DGAOL_DEBUG=ON` builds it for debugging whatever the build +type or the configuration of the project, whose own code keeps them (see +[Building GAOL](building.md#with-cmake)) (GAOL v5). GAOL, a static library, is compiled as position-independent code (`-fPIC`), so that `gaol::gaol` can be linked into a shared library, such as @@ -146,6 +149,36 @@ c++ -std=c++17 -O2 $(pkg-config --cflags gaol) program.cpp $(pkg-config --libs g In a meson project, `dependency('gaol')`. +A meson project can also build GAOL for itself, as a subproject, the sources +of GAOL being in its `subprojects/gaol` (GAOL v5): + +```meson +gaol_dep = dependency('gaol', fallback: ['gaol', 'gaol_dep']) +executable('program', 'program.cpp', dependencies: gaol_dep) +``` + +`dependency()` takes an installed GAOL where it finds one, and builds the +subproject otherwise; `subproject('gaol').get_variable('gaol_dep')` always +builds it. `gaol_dep` carries the include directory, the flags above and the +link option above, as `gaol.pc` does: the flags GAOL's `meson.build` gives its +own targets do not reach those of the project. GAOL is built in `release`, +as CMake and configure build it brought into another project, where the +project leaves the build type to its default, `debug`. meson 1.8.4 and later +give a subproject its own default build type, and a `--buildtype=debug` asked +for builds GAOL for debugging. Earlier ones give it the build type of the +project, which would have built GAOL without optimization, and before 1.8 with +its assertions: there, where the options are those of `debug`, GAOL compiles +its libraries as in `release` all the same, as it cannot tell the default +from a `--buildtype=debug` asked for: `-Dgaol:enable-debug=true` (or +`default_options: ['enable-debug=true']` in `subproject()` or `dependency()`) +builds GAOL for debugging, with any meson. Two cases keep the build type of the +project: Visual C++ with meson before 0.57, whose `debug` gives `/RTC1`, which +`cl` refuses with `/O2`, and the Visual Studio backend of meson +(`--backend=vs`), which takes the build type of the project for every target; +the default backend, ninja, is not one. `tests/meson_subproject` is a project +building GAOL this way. GAOL could not be a subproject before GAOL v5: meson +refuses the `add_global_arguments()` its `meson.build` called in a subproject. + ## Initialization and cleanup GAOL initializes itself before `main()`, with every compiler: `gaol::init()` diff --git a/gaol/gaol_common.h b/gaol/gaol_common.h index 1ed133d6..179d8525 100644 --- a/gaol/gaol_common.h +++ b/gaol/gaol_common.h @@ -32,23 +32,27 @@ #include "gaol/gaol_config.h" #include "gaol/gaol_port.h" -// The commands of GAOL_DEBUG (below) write on std::cout: gaol/gaol_expression.h -// did not compile with GAOL_DEBUGGING, which configure --enable-debug defined, -// without (GAOL v5) +// The commands of GAOL_DEBUG_VERBOSE (below) write on std::cout: +// gaol/gaol_expression.h did not compile with GAOL_DEBUGGING, which configure +// --enable-debug defined, without (GAOL v5) #if GAOL_DEBUGGING # include #endif namespace gaol_core { - // defined in gaol_common.cpp; public, as GAOL_DEBUG reads it in the inline - // functions of the headers, compiled into the code using GAOL (GAOL v5) + // defined in gaol_common.cpp; public, as GAOL_DEBUG_VERBOSE reads it in the + // inline functions of the headers, compiled into the code using GAOL (GAOL + // v5) extern GAOL_PUBLIC int debug_level; + // GAOL_DEBUG before GAOL v5, now the option of CMake that builds GAOL for + // debugging (GAOL v5) #if GAOL_DEBUGGING -# define GAOL_DEBUG(lvl,cmd) do { if (debug_level>=lvl) {cmd;} } while(0) +# define GAOL_DEBUG_VERBOSE(lvl,cmd) \ + do { if (debug_level>=lvl) {cmd;} } while(0) #else -# define GAOL_DEBUG(lvl,cmd) +# define GAOL_DEBUG_VERBOSE(lvl,cmd) #endif /*! @@ -109,7 +113,7 @@ GAOL_NODISCARD extern GAOL_PUBLIC double minimum(double a, double b); \brief Initialization of the library \return true if the library was not already initialized and false otherwise \param dbg_lvl current debugging level: a debugging code inside - a call to GAOL_DEBUG will be executed only if its level is lower or + a call to GAOL_DEBUG_VERBOSE will be executed only if its level is lower or equal to the current debugging level. A debugging level equal to zero means that no debugging message will appear. */ diff --git a/gaol/gaol_expression.cpp b/gaol/gaol_expression.cpp index 08877baf..b84a8f27 100644 --- a/gaol/gaol_expression.cpp +++ b/gaol/gaol_expression.cpp @@ -72,33 +72,33 @@ namespace gaol_core { expression::expression() : root(the_null_expr) { root->inc_refcount(); - GAOL_DEBUG(3,std::cout << "creating null expression" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "creating null expression" << std::endl); } expression::expression(double d) { - GAOL_DEBUG(3,std::cout << "creating expression from " << d << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "creating expression from " << d << std::endl); root= new double_node(d); root->inc_refcount(); } expression::expression(const interval& I) { - GAOL_DEBUG(3,std::cout << "creating expression from " << I << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "creating expression from " << I << std::endl); root= new interval_node(I); root->inc_refcount(); } expression::expression(const expression& e) : root(e.root) { - GAOL_DEBUG(3,std::cout << "creating expression from expression " + GAOL_DEBUG_VERBOSE(3,std::cout << "creating expression from expression " << std::endl); root->inc_refcount(); } expression::expression(const expr_node& e) { - GAOL_DEBUG(3,std::cout << "creating expression from node " << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "creating expression from node " << std::endl); root = &const_cast(e); root->inc_refcount(); } @@ -106,7 +106,7 @@ namespace gaol_core { expression::~expression() { - GAOL_DEBUG(3,std::cout << "deleting expression" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "deleting expression" << std::endl); if (root->dec_refcount() == 0) { delete root; @@ -269,13 +269,13 @@ namespace gaol_core { */ null_node::null_node() { - GAOL_DEBUG(3,std::cout << "null_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "null_node created" << std::endl); } null_node::~null_node() { - GAOL_DEBUG(3,std::cout << "null_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "null_node destroyed" << std::endl); } expr_node* null_node::clone() const @@ -300,12 +300,12 @@ namespace gaol_core { double_node::double_node(double d) : val(d) { - GAOL_DEBUG(3,std::cout << "double_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "double_node created" << std::endl); } double_node::~double_node() { - GAOL_DEBUG(3,std::cout << "double_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "double_node destroyed" << std::endl); } std::ostream& double_node::display(std::ostream& os) const @@ -336,13 +336,13 @@ namespace gaol_core { interval_node::interval_node(const interval& I) { val = new interval(I); - GAOL_DEBUG(3,std::cout << "interval_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "interval_node created" << std::endl); } interval_node::~interval_node() { delete val; - GAOL_DEBUG(3,std::cout << "interval_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "interval_node destroyed" << std::endl); } std::ostream& interval_node::display(std::ostream& os) const @@ -372,7 +372,7 @@ namespace gaol_core { { e_left->inc_refcount(); e_right->inc_refcount(); - GAOL_DEBUG(3,std::cout << "add_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "add_node created" << std::endl); } add_node::~add_node() @@ -383,7 +383,7 @@ namespace gaol_core { if (e_right->dec_refcount() == 0) { delete e_right; } - GAOL_DEBUG(3,std::cout << "add_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "add_node destroyed" << std::endl); } std::ostream& add_node::display(std::ostream& os) const @@ -412,7 +412,7 @@ namespace gaol_core { unary_minus_node::unary_minus_node(const expression& e) : e_uminus(e.get_root()) { e_uminus->inc_refcount(); - GAOL_DEBUG(3,std::cout << "unary_minus_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "unary_minus_node created" << std::endl); } unary_minus_node::~unary_minus_node() @@ -420,7 +420,7 @@ namespace gaol_core { if (e_uminus->dec_refcount() == 0) { delete e_uminus; } - GAOL_DEBUG(3,std::cout << "unary_minus_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "unary_minus_node destroyed" << std::endl); } std::ostream& unary_minus_node::display(std::ostream& os) const @@ -455,7 +455,7 @@ namespace gaol_core { { e_left->inc_refcount(); e_right->inc_refcount(); - GAOL_DEBUG(3,std::cout << "sub_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sub_node created" << std::endl); } sub_node::~sub_node() @@ -466,7 +466,7 @@ namespace gaol_core { if (e_right->dec_refcount() == 0) { delete e_right; } - GAOL_DEBUG(3,std::cout << "sub_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sub_node destroyed" << std::endl); } std::ostream& sub_node::display(std::ostream& os) const @@ -499,7 +499,7 @@ namespace gaol_core { { e_left->inc_refcount(); e_right->inc_refcount(); - GAOL_DEBUG(3,std::cout << "mult_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "mult_node created" << std::endl); } mult_node::~mult_node() @@ -510,7 +510,7 @@ namespace gaol_core { if (e_right->dec_refcount() == 0) { delete e_right; } - GAOL_DEBUG(3,std::cout << "mult_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "mult_node destroyed" << std::endl); } std::ostream& mult_node::display(std::ostream& os) const @@ -543,7 +543,7 @@ namespace gaol_core { { e_left->inc_refcount(); e_right->inc_refcount(); - GAOL_DEBUG(3,std::cout << "div_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "div_node created" << std::endl); } div_node::~div_node() @@ -554,7 +554,7 @@ namespace gaol_core { if (e_right->dec_refcount() == 0) { delete e_right; } - GAOL_DEBUG(3,std::cout << "div_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "div_node destroyed" << std::endl); } // '/', where GAOL wrote '*': x/(y*z) was shown as x*(y*z) (GAOL v5) @@ -585,7 +585,7 @@ namespace gaol_core { { exponent = n; e_pow->inc_refcount(); - GAOL_DEBUG(3,std::cout << "pow_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "pow_node created" << std::endl); } pow_node::~pow_node() @@ -593,7 +593,7 @@ namespace gaol_core { if (e_pow->dec_refcount() == 0) { delete e_pow; } - GAOL_DEBUG(3,std::cout << "pow_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "pow_node destroyed" << std::endl); } std::ostream& pow_node::display(std::ostream& os) const @@ -624,7 +624,7 @@ namespace gaol_core { { e_left->inc_refcount(); e_right->inc_refcount(); - GAOL_DEBUG(3,std::cout << "pow_itv_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "pow_itv_node created" << std::endl); } pow_itv_node::~pow_itv_node() @@ -635,7 +635,7 @@ namespace gaol_core { if (e_right->dec_refcount() == 0) { delete e_right; } - GAOL_DEBUG(3,std::cout << "pow_itv_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "pow_itv_node destroyed" << std::endl); } std::ostream& pow_itv_node::display(std::ostream& os) const @@ -665,7 +665,7 @@ namespace gaol_core { { exponent = n; e_nth_root->inc_refcount(); - GAOL_DEBUG(3,std::cout << "nth_root_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "nth_root_node created" << std::endl); } nth_root_node::~nth_root_node() @@ -673,7 +673,7 @@ namespace gaol_core { if (e_nth_root->dec_refcount() == 0) { delete e_nth_root; } - GAOL_DEBUG(3,std::cout << "nth_root_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "nth_root_node destroyed" << std::endl); } std::ostream& nth_root_node::display(std::ostream& os) const @@ -700,7 +700,7 @@ namespace gaol_core { cos_node::cos_node(const expression& e) : e_cos(e.get_root()) { e_cos->inc_refcount(); - GAOL_DEBUG(3,std::cout << "cos_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "cos_node created" << std::endl); } cos_node::~cos_node() @@ -708,7 +708,7 @@ namespace gaol_core { if (e_cos->dec_refcount() == 0) { delete e_cos; } - GAOL_DEBUG(3,std::cout << "cos_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "cos_node destroyed" << std::endl); } std::ostream& cos_node::display(std::ostream& os) const @@ -736,7 +736,7 @@ namespace gaol_core { sin_node::sin_node(const expression& e) : e_sin(e.get_root()) { e_sin->inc_refcount(); - GAOL_DEBUG(3,std::cout << "sin_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sin_node created" << std::endl); } sin_node::~sin_node() @@ -744,7 +744,7 @@ namespace gaol_core { if (e_sin->dec_refcount() == 0) { delete e_sin; } - GAOL_DEBUG(3,std::cout << "sin_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sin_node destroyed" << std::endl); } std::ostream& sin_node::display(std::ostream& os) const @@ -772,7 +772,7 @@ namespace gaol_core { tan_node::tan_node(const expression& e) : e_tan(e.get_root()) { e_tan->inc_refcount(); - GAOL_DEBUG(3,std::cout << "tan_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "tan_node created" << std::endl); } tan_node::~tan_node() @@ -780,7 +780,7 @@ namespace gaol_core { if (e_tan->dec_refcount() == 0) { delete e_tan; } - GAOL_DEBUG(3,std::cout << "tan_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "tan_node destroyed" << std::endl); } std::ostream& tan_node::display(std::ostream& os) const @@ -810,7 +810,7 @@ namespace gaol_core { { Y->inc_refcount(); X->inc_refcount(); - GAOL_DEBUG(3,std::cout << "atan2_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "atan2_node created" << std::endl); } atan2_node::~atan2_node() @@ -821,7 +821,7 @@ namespace gaol_core { if (X->dec_refcount() == 0) { delete X; } - GAOL_DEBUG(3,std::cout << "atan2_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "atan2_node destroyed" << std::endl); } std::ostream& atan2_node::display(std::ostream& os) const @@ -851,7 +851,7 @@ namespace gaol_core { acos_node::acos_node(const expression& e) : e_acos(e.get_root()) { e_acos->inc_refcount(); - GAOL_DEBUG(3,std::cout << "acos_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "acos_node created" << std::endl); } acos_node::~acos_node() @@ -859,7 +859,7 @@ namespace gaol_core { if (e_acos->dec_refcount() == 0) { delete e_acos; } - GAOL_DEBUG(3,std::cout << "acos_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "acos_node destroyed" << std::endl); } std::ostream& acos_node::display(std::ostream& os) const @@ -887,7 +887,7 @@ namespace gaol_core { asin_node::asin_node(const expression& e) : e_asin(e.get_root()) { e_asin->inc_refcount(); - GAOL_DEBUG(3,std::cout << "asin_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "asin_node created" << std::endl); } asin_node::~asin_node() @@ -895,7 +895,7 @@ namespace gaol_core { if (e_asin->dec_refcount() == 0) { delete e_asin; } - GAOL_DEBUG(3,std::cout << "asin_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "asin_node destroyed" << std::endl); } std::ostream& asin_node::display(std::ostream& os) const @@ -923,7 +923,7 @@ namespace gaol_core { atan_node::atan_node(const expression& e) : e_atan(e.get_root()) { e_atan->inc_refcount(); - GAOL_DEBUG(3,std::cout << "atan_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "atan_node created" << std::endl); } atan_node::~atan_node() @@ -931,7 +931,7 @@ namespace gaol_core { if (e_atan->dec_refcount() == 0) { delete e_atan; } - GAOL_DEBUG(3,std::cout << "atan_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "atan_node destroyed" << std::endl); } std::ostream& atan_node::display(std::ostream& os) const @@ -959,7 +959,7 @@ namespace gaol_core { cosh_node::cosh_node(const expression& e) : e_cosh(e.get_root()) { e_cosh->inc_refcount(); - GAOL_DEBUG(3,std::cout << "cosh_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "cosh_node created" << std::endl); } cosh_node::~cosh_node() @@ -967,7 +967,7 @@ namespace gaol_core { if (e_cosh->dec_refcount() == 0) { delete e_cosh; } - GAOL_DEBUG(3,std::cout << "cosh_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "cosh_node destroyed" << std::endl); } std::ostream& cosh_node::display(std::ostream& os) const @@ -995,7 +995,7 @@ namespace gaol_core { sinh_node::sinh_node(const expression& e) : e_sinh(e.get_root()) { e_sinh->inc_refcount(); - GAOL_DEBUG(3,std::cout << "sinh_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sinh_node created" << std::endl); } sinh_node::~sinh_node() @@ -1003,7 +1003,7 @@ namespace gaol_core { if (e_sinh->dec_refcount() == 0) { delete e_sinh; } - GAOL_DEBUG(3,std::cout << "sinh_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sinh_node destroyed" << std::endl); } std::ostream& sinh_node::display(std::ostream& os) const @@ -1031,7 +1031,7 @@ namespace gaol_core { tanh_node::tanh_node(const expression& e) : e_tanh(e.get_root()) { e_tanh->inc_refcount(); - GAOL_DEBUG(3,std::cout << "tanh_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "tanh_node created" << std::endl); } tanh_node::~tanh_node() @@ -1039,7 +1039,7 @@ namespace gaol_core { if (e_tanh->dec_refcount() == 0) { delete e_tanh; } - GAOL_DEBUG(3,std::cout << "tanh_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "tanh_node destroyed" << std::endl); } std::ostream& tanh_node::display(std::ostream& os) const @@ -1068,7 +1068,7 @@ namespace gaol_core { acosh_node::acosh_node(const expression& e) : e_acosh(e.get_root()) { e_acosh->inc_refcount(); - GAOL_DEBUG(3,std::cout << "acosh_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "acosh_node created" << std::endl); } acosh_node::~acosh_node() @@ -1076,7 +1076,7 @@ namespace gaol_core { if (e_acosh->dec_refcount() == 0) { delete e_acosh; } - GAOL_DEBUG(3,std::cout << "acosh_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "acosh_node destroyed" << std::endl); } std::ostream& acosh_node::display(std::ostream& os) const @@ -1104,7 +1104,7 @@ namespace gaol_core { asinh_node::asinh_node(const expression& e) : e_asinh(e.get_root()) { e_asinh->inc_refcount(); - GAOL_DEBUG(3,std::cout << "asinh_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "asinh_node created" << std::endl); } asinh_node::~asinh_node() @@ -1112,7 +1112,7 @@ namespace gaol_core { if (e_asinh->dec_refcount() == 0) { delete e_asinh; } - GAOL_DEBUG(3,std::cout << "asinh_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "asinh_node destroyed" << std::endl); } std::ostream& asinh_node::display(std::ostream& os) const @@ -1140,7 +1140,7 @@ namespace gaol_core { atanh_node::atanh_node(const expression& e) : e_atanh(e.get_root()) { e_atanh->inc_refcount(); - GAOL_DEBUG(3,std::cout << "atanh_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "atanh_node created" << std::endl); } atanh_node::~atanh_node() @@ -1148,7 +1148,7 @@ namespace gaol_core { if (e_atanh->dec_refcount() == 0) { delete e_atanh; } - GAOL_DEBUG(3,std::cout << "atanh_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "atanh_node destroyed" << std::endl); } std::ostream& atanh_node::display(std::ostream& os) const @@ -1177,7 +1177,7 @@ namespace gaol_core { exp_node::exp_node(const expression& e) : e_exp(e.get_root()) { e_exp->inc_refcount(); - GAOL_DEBUG(3,std::cout << "exp_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "exp_node created" << std::endl); } exp_node::~exp_node() @@ -1185,7 +1185,7 @@ namespace gaol_core { if (e_exp->dec_refcount() == 0) { delete e_exp; } - GAOL_DEBUG(3,std::cout << "exp_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "exp_node destroyed" << std::endl); } std::ostream& exp_node::display(std::ostream& os) const @@ -1213,7 +1213,7 @@ namespace gaol_core { log_node::log_node(const expression& e) : e_log(e.get_root()) { e_log->inc_refcount(); - GAOL_DEBUG(3,std::cout << "log_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "log_node created" << std::endl); } log_node::~log_node() @@ -1221,7 +1221,7 @@ namespace gaol_core { if (e_log->dec_refcount() == 0) { delete e_log; } - GAOL_DEBUG(3,std::cout << "log_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "log_node destroyed" << std::endl); } std::ostream& log_node::display(std::ostream& os) const @@ -1249,7 +1249,7 @@ namespace gaol_core { exp2_node::exp2_node(const expression& e) : e_exp2(e.get_root()) { e_exp2->inc_refcount(); - GAOL_DEBUG(3,std::cout << "exp2_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "exp2_node created" << std::endl); } exp2_node::~exp2_node() @@ -1257,7 +1257,7 @@ namespace gaol_core { if (e_exp2->dec_refcount() == 0) { delete e_exp2; } - GAOL_DEBUG(3,std::cout << "exp2_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "exp2_node destroyed" << std::endl); } std::ostream& exp2_node::display(std::ostream& os) const @@ -1285,7 +1285,7 @@ namespace gaol_core { log2_node::log2_node(const expression& e) : e_log2(e.get_root()) { e_log2->inc_refcount(); - GAOL_DEBUG(3,std::cout << "log2_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "log2_node created" << std::endl); } log2_node::~log2_node() @@ -1293,7 +1293,7 @@ namespace gaol_core { if (e_log2->dec_refcount() == 0) { delete e_log2; } - GAOL_DEBUG(3,std::cout << "log2_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "log2_node destroyed" << std::endl); } std::ostream& log2_node::display(std::ostream& os) const @@ -1321,7 +1321,7 @@ namespace gaol_core { sign_node::sign_node(const expression& e) : e_sign(e.get_root()) { e_sign->inc_refcount(); - GAOL_DEBUG(3,std::cout << "sign_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sign_node created" << std::endl); } sign_node::~sign_node() @@ -1329,7 +1329,7 @@ namespace gaol_core { if (e_sign->dec_refcount() == 0) { delete e_sign; } - GAOL_DEBUG(3,std::cout << "sign_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "sign_node destroyed" << std::endl); } std::ostream& sign_node::display(std::ostream& os) const @@ -1357,7 +1357,7 @@ namespace gaol_core { trunc_node::trunc_node(const expression& e) : e_trunc(e.get_root()) { e_trunc->inc_refcount(); - GAOL_DEBUG(3,std::cout << "trunc_node created" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "trunc_node created" << std::endl); } trunc_node::~trunc_node() @@ -1365,7 +1365,7 @@ namespace gaol_core { if (e_trunc->dec_refcount() == 0) { delete e_trunc; } - GAOL_DEBUG(3,std::cout << "trunc_node destroyed" << std::endl); + GAOL_DEBUG_VERBOSE(3,std::cout << "trunc_node destroyed" << std::endl); } std::ostream& trunc_node::display(std::ostream& os) const diff --git a/gaol/gaol_expression.h b/gaol/gaol_expression.h index f2dfd693..2a76375b 100644 --- a/gaol/gaol_expression.h +++ b/gaol/gaol_expression.h @@ -890,7 +890,7 @@ typedef struct { */ GAOL_INLINE void null_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "null_node accepting visitor" << std::endl); + GAOL_DEBUG_VERBOSE(2,std::cout << "null_node accepting visitor" << std::endl); visitor.visit(this); } @@ -900,7 +900,7 @@ typedef struct { */ GAOL_INLINE void double_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "double_node accepting visitor" << std::endl); + GAOL_DEBUG_VERBOSE(2,std::cout << "double_node accepting visitor" << std::endl); visitor.visit(this); } @@ -914,7 +914,7 @@ typedef struct { */ GAOL_INLINE void interval_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "interval_node accepting visitor" << std::endl); + GAOL_DEBUG_VERBOSE(2,std::cout << "interval_node accepting visitor" << std::endl); visitor.visit(this); } @@ -929,7 +929,7 @@ typedef struct { */ GAOL_INLINE void add_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "add_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "add_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -948,7 +948,7 @@ typedef struct { */ GAOL_INLINE void unary_minus_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "unary_minus_node accepting visitor" + GAOL_DEBUG_VERBOSE(2,std::cout << "unary_minus_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -963,7 +963,7 @@ typedef struct { */ GAOL_INLINE void sub_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "sub_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "sub_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -982,7 +982,7 @@ typedef struct { */ GAOL_INLINE void mult_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "mult_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "mult_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1001,7 +1001,7 @@ typedef struct { */ GAOL_INLINE void div_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "div_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "div_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1020,7 +1020,7 @@ typedef struct { */ GAOL_INLINE void pow_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "pow_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "pow_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1040,7 +1040,7 @@ typedef struct { */ GAOL_INLINE void pow_itv_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "pow_itv_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "pow_itv_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1065,7 +1065,7 @@ typedef struct { */ GAOL_INLINE void nth_root_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "nth_root_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "nth_root_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1085,7 +1085,7 @@ typedef struct { */ GAOL_INLINE void cos_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "cos_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "cos_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1099,7 +1099,7 @@ typedef struct { */ GAOL_INLINE void sin_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "sin_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "sin_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1113,7 +1113,7 @@ typedef struct { */ GAOL_INLINE void tan_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "tan_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "tan_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1127,7 +1127,7 @@ typedef struct { */ GAOL_INLINE void atan2_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "atan2_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "atan2_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1146,7 +1146,7 @@ typedef struct { */ GAOL_INLINE void acos_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "acos_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "acos_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1160,7 +1160,7 @@ typedef struct { */ GAOL_INLINE void asin_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "asin_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "asin_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1174,7 +1174,7 @@ typedef struct { */ GAOL_INLINE void atan_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "atan_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "atan_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1188,7 +1188,7 @@ typedef struct { */ GAOL_INLINE void cosh_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "cosh_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "cosh_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1202,7 +1202,7 @@ typedef struct { */ GAOL_INLINE void sinh_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "sinh_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "sinh_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1216,7 +1216,7 @@ typedef struct { */ GAOL_INLINE void tanh_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "tanh_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "tanh_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1230,7 +1230,7 @@ typedef struct { */ GAOL_INLINE void acosh_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "acosh_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "acosh_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1244,7 +1244,7 @@ typedef struct { */ GAOL_INLINE void asinh_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "asinh_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "asinh_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1258,7 +1258,7 @@ typedef struct { */ GAOL_INLINE void atanh_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "atanh_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "atanh_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1272,7 +1272,7 @@ typedef struct { */ GAOL_INLINE void exp_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "exp_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "exp_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1286,7 +1286,7 @@ typedef struct { */ GAOL_INLINE void log_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "log_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "log_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1300,7 +1300,7 @@ typedef struct { */ GAOL_INLINE void exp2_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "exp2_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "exp2_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1314,7 +1314,7 @@ typedef struct { */ GAOL_INLINE void log2_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "log2_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "log2_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1328,7 +1328,7 @@ typedef struct { */ GAOL_INLINE void sign_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "sign_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "sign_node accepting visitor" << std::endl;); visitor.visit(this); } @@ -1342,7 +1342,7 @@ typedef struct { */ GAOL_INLINE void trunc_node::accept(expr_visitor& visitor) { - GAOL_DEBUG(2,std::cout << "trunc_node accepting visitor" << std::endl;); + GAOL_DEBUG_VERBOSE(2,std::cout << "trunc_node accepting visitor" << std::endl;); visitor.visit(this); } diff --git a/gaol/meson.build b/gaol/meson.build index 3ba3ca9d..dc9e0779 100755 --- a/gaol/meson.build +++ b/gaol/meson.build @@ -51,8 +51,10 @@ endif # which the c99 of the project refuses, but with Visual C++, which has no GNU # C and compiles them as CMake does. And b_lto=false keeps the interprocedural # optimization of -Db_lto=true away from them: reached by it, sin and cos took -# half as long again (see doc/three-builds.md) -core_math_overrides = ['b_lto=false'] +# half as long again (see doc/three-builds.md). The options of enable-debug, or +# in a subproject those of release where meson gives it the build type of the +# project (gaol_build_options, see meson.build) +core_math_overrides = ['b_lto=false'] + gaol_build_options if not msvc core_math_overrides += ['c_std=gnu11'] endif @@ -177,6 +179,7 @@ if msvc include_directories: [incdir, include_directories('../cmake/msvc')], c_args: gaol_msvc_args, cpp_args: gaol_msvc_args, + override_options: gaol_build_options, ) gaollib_static = gaollib else @@ -190,15 +193,20 @@ else include_directories: incdir, version: meson.project_version(), soversion: major_version.to_string(), + override_options: gaol_build_options, ) gaollib_static = gaollib.get_static_lib() endif -# GAOL, for the tests and the examples of this build, and for a meson project -# bringing GAOL in as a subproject +# GAOL, for the examples of this build, and for a meson project bringing GAOL +# in as a subproject: the flags of interval arithmetic and the link option +# gaol.pc gives, which the code including GAOL's headers is to be compiled and +# linked with, the arguments of this project not reaching the targets of +# another one (GAOL v5) gaol_dep = declare_dependency( link_with: gaollib, include_directories: include_directories('..'), + compile_args: pc_cflags, link_args: gaol_link_args, dependencies: deps, ) diff --git a/manual/v5/gaol.tex b/manual/v5/gaol.tex index 0a2530fa..bdfd13c1 100644 --- a/manual/v5/gaol.tex +++ b/manual/v5/gaol.tex @@ -444,8 +444,12 @@ \section{Building and installing with CMake}\label{sec:cmake} \file{libgaol}, which is a static library unless \option{BUILD\_SHARED\_LIBS} is \code{ON}: there is nothing else to build and nothing else to install. The build type is \code{Release} unless another is given; brought in by a project that gives none (\code{add\_subdirectory}, -\code{FetchContent}), GAOL and CORE-MATH are compiled with \option{-O3} all -the same (\option{/O2} with Visual C++). +\code{FetchContent}), GAOL and CORE-MATH are compiled as in \code{Release} +all the same: \option{-O3} (\option{/O2} with Visual C++), \code{NDEBUG} and +the optimizations of \cmd{configure}. With a generator of several +configurations, GAOL built alone puts \code{Release} first among them, which +Ninja Multi-Config builds by default; \cmd{cmake --build} with Visual Studio +builds \code{Debug} all the same without \option{-{}-config}.\newinvfive \subsection{Options}\label{sec:cmake-options} %%.................. @@ -490,6 +494,11 @@ \subsection{Options}\label{sec:cmake-options} \item \option{GAOL\_VERBOSE\_MODE}. \code{OFF} by default: writes a line on the standard error when GAOL initializes and cleans up; \cindex{verbose mode}% +\item \option{GAOL\_DEBUG}. \code{OFF} by default: builds \file{libgaol} and + CORE-MATH for debugging, without optimization nor \code{NDEBUG} and with + \code{GAOL\_DEBUGGING}, whatever the build type or the configuration, a + project bringing GAOL in included, as \code{enable-debug} of meson and + \loption{enable-debug} of \cmd{configure};\newinvfive \item \option{GAOL\_PRESERVE\_ROUNDING}. \code{OFF} by default: each operation restores the rounding direction it found, rather than leaving it upward (\pxref{sec:rounding-direction}); @@ -672,6 +681,7 @@ \section{Building and installing with meson} \code{enable-asm} & \code{true}\\ \code{enable-verbose-mode} & \code{false}\\ \code{enable-preserve-rounding} & \code{false}\\ + \code{enable-debug} & \code{false}; builds \file{libgaol} for debugging whatever the build type, as \option{GAOL\_DEBUG}\\ \code{enable-exception} & \code{true}\\ \code{with-tests} & \code{false}; builds the unit tests\\ \code{with-examples} & \code{false}; builds the examples\\ @@ -684,10 +694,13 @@ \section{Building and installing with meson} \cmd{meson setup} runs Python to read the version of GAOL in \file{VERSION.txt}: the first of \cmd{python3} and \cmd{python} found in the \code{PATH}, or, if there is none, the Python that runs meson. On Windows, -meson 0.53.0 and earlier may take the \file{python.exe} or \file{python3.exe} -alias of the Microsoft Store (in \file{WindowsApps}), which only opens the -Store, and \cmd{meson setup} then stops; use meson 0.53.1 or later, or turn off -the aliases in the Windows settings (\emph{Manage app execution aliases}). +meson 0.53.0 and earlier may take an alias of Python of the Microsoft Store +(\file{python3.exe}, and perhaps \file{python.exe}, in \file{WindowsApps}; not +checked on Windows), which only opens the Store, and \cmd{meson setup} then +stops; use meson 0.53.1 or later, or turn off the aliases in the Windows +settings (\emph{Manage app execution aliases}). Later versions of meson leave +\file{WindowsApps} out only where the \code{PATH} names it under the directory +of \code{USERPROFILE}, not for a profile whose directory differs from it. \section{Tests}\label{sec:tests} %%------------- @@ -827,8 +840,9 @@ \chapter{An overview of GAOL}\label{chap:overview} \end{cmdshell} \noindent - GAOL is the only library to link, with the C mathematical library: CORE-MATH, - which computes its elementary functions, is compiled into it. + GAOL is the only library to link: CORE-MATH, which computes its elementary + functions, is compiled into it, and the C++ compiler links the mathematical + library of the system itself. Executing \file{f}, we obtain: @@ -950,7 +964,7 @@ \subsection{From pkg-config} Each build installs \file{gaol.pc} in the \file{pkgconfig} directory of its library directory, except the CMake build with Visual C++. Its \code{Cflags} carries the flags above with the include directory, and its \code{Libs} GAOL -itself with the C mathematical library and the link option above: +itself and the link option above: \cindex{pkg-config}% \begin{cmdshell} @@ -982,6 +996,29 @@ \subsection{From pkg-config} \noindent In a meson project, \code{dependency('gaol')} finds it. +A meson project can also build GAOL for itself, as a subproject, the sources +of GAOL being in its \file{subprojects/gaol}: +\cindex{meson!using gaol from}% + +\begin{example} +gaol_dep = dependency('gaol', fallback: ['gaol', 'gaol_dep']) +executable('program', 'program.cpp', dependencies: gaol_dep) +\end{example} + +\noindent +\code{dependency()} takes an installed GAOL where it finds one, and builds the +subproject otherwise. \code{gaol\_dep} carries the include directory, the flags +above and the link option above, as \file{gaol.pc} does. GAOL is built in +\code{release}, as CMake and \cmd{configure} build it brought into another +project, where the project leaves the build type to its default, +\code{debug}: meson 1.8.4 and later give a subproject its own default build +type, and GAOL compiles its libraries as in \code{release} with earlier ones, +which give it the build type of the project; it cannot tell there the default +from a \loption{buildtype=debug} asked for (but with Visual C++ before meson +0.57, and with the Visual Studio backend of meson, which keep the build type +of the project). \code{-Dgaol:enable-debug=true} builds it for +debugging.\newinvfive + \section{The rounding direction}\label{sec:rounding-direction} %%------------------------------ \cindex{rounding!direction}% @@ -4950,8 +4987,10 @@ \chapter{Debugging facilities}\label{sec:debugging-facilities} GAOL has been configured with the debugging facilities enabled, which the \code{Debug} build of each build does: \option{-DCMAKE\_BUILD\_TYPE=Debug} with CMake, the \option{-{}-enable-debug} option of \cmd{configure} -(\pxref{sec:configuration}), or \option{-{}-buildtype=debug} with meson. They -define \code{GAOL\_DEBUGGING} in \file{gaol/gaol\_configuration.h}: GAOL then +(\pxref{sec:configuration}), or \option{-{}-buildtype=debug} with meson, and +\option{-DGAOL\_DEBUG=ON} with CMake and \option{-Denable-debug=true} with +meson whatever the build type.\newinvfive{} They define +\code{GAOL\_DEBUGGING} in \file{gaol/gaol\_configuration.h}: GAOL then checks its assertions. \begin{deffun}{int}{debug\_level}{} @@ -4961,9 +5000,11 @@ \chapter{Debugging facilities}\label{sec:debugging-facilities} \code{gaol} too. \end{deffun} -\begin{defmacroA}{GAOL\_DEBUG}{(\var{lvl},\var{cmd})} +\begin{defmacroA}{GAOL\_DEBUG\_VERBOSE}{(\var{lvl},\var{cmd})} Executes \var{cmd} if \var{lvl} is lower or equal to the current debugging - level (see the variable \code{debug\_level} above). + level (see the variable \code{debug\_level} above). It was named + \code{GAOL\_DEBUG} before GAOL v5, which is now the option of CMake that + builds GAOL for debugging.\newinvfive This macro defaults to nothing if the library was not configured with the debugging facilities. @@ -4977,9 +5018,9 @@ \chapter{Debugging facilities}\label{sec:debugging-facilities} @emph^[Some code]~ -GAOL_DEBUG(1,cout << "The value of x is " << x); +GAOL_DEBUG_VERBOSE(1,cout << "The value of x is " << x); x += interval(3.5,4.5); -GAOL_DEBUG(2,cout << "Now the value of x is " << x); +GAOL_DEBUG_VERBOSE(2,cout << "Now the value of x is " << x); \end{example} The first message will be displayed whenever the debugging level is at least diff --git a/meson.build b/meson.build index e8e7daaf..aa1f06ea 100755 --- a/meson.build +++ b/meson.build @@ -16,12 +16,13 @@ project( # python3 stays first: only when the first name ends with python3 does # meson fall back on its own Python (the meson.exe of the Windows installer) # if it finds none. Looking for python first would lose that fallback, and - # would not avoid the Microsoft Store aliases of meson 0.53.0, which - # WindowsApps holds for python.exe as for python3.exe: meson 0.53.1 and later - # leave that directory out (doc/building.md). The encoding utf-8-sig skips - # the byte order mark that some editors of Windows write at - # the start of a file, which the default encoding (the code page of Windows, - # cp1252) reads as three characters of the version. The blanks stripped are + # would not avoid the Microsoft Store aliases that meson 0.53.0 and earlier + # take where WindowsApps holds a python.exe as well as a python3.exe (not + # checked on Windows): meson 0.53.1 and later leave that directory out + # (doc/building.md). The encoding utf-8-sig skips the byte order mark that + # some editors of Windows write at the start of a file, which the default + # encoding (the code page of Windows, cp1252) reads as three characters of + # the version. The blanks stripped are # the six of ASCII (string.whitespace), which CMake and configure strip, not # all those of Unicode, which strip() alone strips (a no-break space). What # is not the version is written as ASCII, with escapes (\u200b for a @@ -29,7 +30,7 @@ project( # byte, \n), which show in the error message below, on one line, and which # the pipe to meson carries whatever the code page (GAOL v5) version: run_command(find_program('python3', 'python', native: true), '-c', - 'import string, sys; print(ascii(open(sys.argv[-1], encoding=\'utf-8-sig\', errors=\'surrogateescape\').read().strip(string.whitespace))[1:-1])', + 'import string, sys\nwith open(sys.argv[-1], encoding=\'utf-8-sig\', errors=\'surrogateescape\') as f: print(ascii(f.read().strip(string.whitespace))[1:-1])', join_paths(meson.current_source_dir(), 'VERSION.txt'), check: true).stdout().strip(), # Optimized by default, as configure builds GAOL (meson's own default, debug, @@ -50,14 +51,14 @@ if not gaol_version_ok # The first bytes of the file in hexadecimal, which show what the quoted text # does not (a zero-width space, a second byte order mark) gaol_version_bytes = run_command(find_program('python3', 'python', native: true), '-c', - 'import sys; print(*[\'%02x\' % b for b in open(sys.argv[-1], \'rb\').read(32)])', + 'import sys\nwith open(sys.argv[-1], \'rb\') as f: print(*[\'%02x\' % b for b in f.read(32)])', join_paths(meson.current_source_dir(), 'VERSION.txt'), check: false).stdout().strip() # A file of UTF-16 characters, which starts with its byte order mark (FF FE, # FE FF) or holds NUL bytes, is not read as UTF-16: the message says so, as # those of CMake and configure do gaol_version_utf16 = run_command(find_program('python3', 'python', native: true), '-c', - 'import sys; b = open(sys.argv[-1], \'rb\').read(); print(\'mark\' if b[:2] in (bytes([255, 254]), bytes([254, 255])) else \'nul\' if 0 in b else \'\')', + 'import sys\nwith open(sys.argv[-1], \'rb\') as f: b = f.read()\nprint(\'mark\' if b[:2] in (bytes([255, 254]), bytes([254, 255])) else \'nul\' if 0 in b else \'\')', join_paths(meson.current_source_dir(), 'VERSION.txt'), check: false).stdout().strip() gaol_version_hint = '' @@ -100,10 +101,43 @@ preserve_rounding = get_option('enable-preserve-rounding') prefer_avx512_requested = get_option('enable-prefer-avx512') exception = get_option('enable-exception') # The Debug build, as CMAKE_BUILD_TYPE=Debug and configure --enable-debug: -# GAOL checks its assertions (GAOL_DEBUGGING). The option enable-debug, which -# only defined GAOL_DEBUGGING, is gone, as enable-optimize: the build type -# gives both (GAOL v5) +# GAOL checks its assertions (GAOL_DEBUGGING). The build type gives it with the +# optimizations, and enable-optimize is gone (GAOL v5) debug = get_option('buildtype') == 'debug' +release = get_option('buildtype') == 'release' +# The options of the libraries of GAOL and CORE-MATH (gaol/meson.build) +gaol_build_options = [] +# enable-debug builds them for debugging whatever the build type, a subproject +# included, as GAOL_DEBUG of CMake: without optimization, without NDEBUG, and +# with GAOL_DEBUGGING (GAOL v5: it defined GAOL_DEBUGGING alone, and was gone) +# +# Brought in as a subproject, GAOL is built in release by default, as CMake and +# configure build it brought into another project (GAOL v5). meson 1.8.4 and +# later give a subproject its own default build type, release here; earlier +# ones give it the build type of the project, without optimization in meson's +# default, debug, and before 1.8 with GAOL_DEBUGGING too, while 1.8.0 to 1.8.3 +# have get_option('buildtype') read the release of GAOL: the options +# optimization and debug tell the build type of the project there. A +# subproject cannot tell meson's default from a --buildtype=debug asked for: +# where they are those of debug, the libraries of GAOL and CORE-MATH are +# compiled as in release (override_options, gaol/meson.build), and in the +# release of the project with NDEBUG, which the b_ndebug=if-release of +# default_options gives where they apply. Not with Visual C++ before meson +# 0.57, whose build type debug gives /RTC1, which cl refuses with the /O2 of +# optimization=3, and whose C runtime follows the build type of the target. +if get_option('enable-debug') + gaol_build_options = ['optimization=0', 'debug=true', 'b_ndebug=false'] + debug = true +elif meson.is_subproject() and meson.version().version_compare('<1.8.4') and not (msvc and meson.version().version_compare('<0.57')) + debug = false + release = get_option('optimization') == '3' and not get_option('debug') + if get_option('optimization') == '0' and get_option('debug') + gaol_build_options = ['optimization=3', 'debug=false', 'b_ndebug=true'] + release = true + elif release + gaol_build_options = ['b_ndebug=true'] + endif +endif # The mathematical library # # GAOL bounds every one of its elementary functions with CORE-MATH @@ -202,27 +236,32 @@ endif # CMakeLists.txt and configure give them: -frounding-math; -ffp-contract=off # (without it, compilers contract a multiplication and an addition into a fused # one as if rounding to nearest: on 64-bit ARM, -(.5*l - .5*r) and -.5*l + .5*r -# both became fnma(.5, l, .5*r), and mid() a single double); -fno-fast-math +# both became fnma(.5, l, .5*r), and mid() a single double); -fno-fast-math. +# These flags, and the others below, are arguments of the project rather than +# global ones, which meson refuses in a subproject: GAOL can then be a +# subproject of a meson project, whose own targets they do not reach, and +# gaol_dep gives that project's code the flags gaol.pc gives (pc_cflags, see +# gaol/meson.build) (GAOL v5) pc_cflags = [] # the flags of interval arithmetic, which gaol.pc gives the code using GAOL foreach flag : ['-frounding-math', '-ffp-contract=off', '-fno-fast-math'] if cpp_comp.has_argument(flag) - add_global_arguments([flag], language: 'cpp') + add_project_arguments([flag], language: 'cpp') pc_cflags += [flag] endif if c_comp.has_argument(flag) - add_global_arguments([flag], language: 'c') + add_project_arguments([flag], language: 'c') endif endforeach # Visual C++: /fp:strict, as CMakeLists.txt gives it to GAOL and to CORE-MATH, # without which gaol/gaol_config.h refuses to compile if msvc - add_global_arguments(['/fp:strict'], language: ['c', 'cpp']) + add_project_arguments(['/fp:strict'], language: ['c', 'cpp']) pc_cflags += ['/fp:strict'] # clang-cl for 32-bit x86 computes doubles on the x87 unit, even with # /arch:SSE2, which gaol/gaol_config.h refuses: -msse2 has it compute them # in SSE2, as CMakeLists.txt gives it if cpp_comp.get_id() == 'clang-cl' and host_machine.cpu_family() == 'x86' - add_global_arguments(['-msse2'], language: ['c', 'cpp']) + add_project_arguments(['-msse2'], language: ['c', 'cpp']) pc_cflags += ['-msse2'] endif endif @@ -231,23 +270,23 @@ endif # public declarations carry __attribute__ ((visibility("default"))) if cpp_comp.has_multi_arguments('-fvisibility-inlines-hidden', '-fvisibility=hidden') conf_data.set('GAOL_HAVE_VISIBILITY_OPTIONS', 1) - add_global_arguments(['-fvisibility-inlines-hidden', '-fvisibility=hidden'], language: 'cpp') + add_project_arguments(['-fvisibility-inlines-hidden', '-fvisibility=hidden'], language: 'cpp') endif if cpp_comp.has_argument('-Wconversion') - add_global_arguments(['-Wconversion'], language: 'cpp') + add_project_arguments(['-Wconversion'], language: 'cpp') endif if c_comp.has_argument('-Wconversion') - add_global_arguments(['-Wconversion'], language: 'c') + add_project_arguments(['-Wconversion'], language: 'c') endif # The optimizations configure (--enable-optimize) and the Release build of # CMake add to -O3, in the release build type, where the compiler takes them -if get_option('buildtype') == 'release' +if release foreach flag : ['-funroll-loops', '-fomit-frame-pointer', '-fexpensive-optimizations'] if cpp_comp.has_argument(flag) - add_global_arguments([flag], language: 'cpp') + add_project_arguments([flag], language: 'cpp') endif if c_comp.has_argument(flag) - add_global_arguments([flag], language: 'c') + add_project_arguments([flag], language: 'c') endif endforeach endif @@ -277,18 +316,18 @@ int main() { return 0; } if target_x86 if target_x86_32 and cpp_comp.has_multi_arguments('-msse2', '-mfpmath=sse') x86_args = ['-msse2', '-mfpmath=sse'] - add_global_arguments(x86_args, language: 'cpp') - add_global_arguments(x86_args, language: 'c') + add_project_arguments(x86_args, language: 'cpp') + add_project_arguments(x86_args, language: 'c') pc_cflags += x86_args endif if simd and not msvc and not (target_x86_32 and os_win) and cpp_comp.has_argument('-msse2') use_sse2 = true conf_data.set('GAOL_USING_SSE2_INSTRUCTIONS', 1) - add_global_arguments(['-msse2'], language: 'cpp') + add_project_arguments(['-msse2'], language: 'cpp') pc_cflags += ['-msse2'] if cpp_comp.has_argument('-msse3') conf_data.set('GAOL_USING_SSE3_INSTRUCTIONS', 1) - add_global_arguments(['-msse3'], language: 'cpp') + add_project_arguments(['-msse3'], language: 'cpp') pc_cflags += ['-msse3'] endif endif @@ -399,8 +438,8 @@ if get_option('enable-fma') endif endif if fma_args.length() > 0 - add_global_arguments(fma_args, language: 'c') - add_global_arguments(fma_args, language: 'cpp') + add_project_arguments(fma_args, language: 'c') + add_project_arguments(fma_args, language: 'cpp') pc_cflags += fma_args endif endif @@ -409,7 +448,7 @@ message('Fused multiply-add flags: ' + ' '.join(fma_args)) # -ffloat-store only where doubles are still computed on the x87 unit # (FLT_EVAL_METHOD not 0), whose 80-bit registers keep more digits than a # double (as CMakeLists.txt): checked with the flags of 32-bit x86 above, which -# the checks of the compiler do not get from add_global_arguments() +# the checks of the compiler do not get from add_project_arguments() float_store_needed = cpp_comp.compiles(''' #include #if defined(FLT_EVAL_METHOD) && FLT_EVAL_METHOD == 0 @@ -418,8 +457,8 @@ float_store_needed = cpp_comp.compiles(''' int main() { return 0; } ''', args: x86_args, name: 'doubles computed in extended precision') if float_store_needed and cpp_comp.has_argument('-ffloat-store') - add_global_arguments(['-ffloat-store'], language: 'c') - add_global_arguments(['-ffloat-store'], language: 'cpp') + add_project_arguments(['-ffloat-store'], language: 'c') + add_project_arguments(['-ffloat-store'], language: 'cpp') pc_cflags += ['-ffloat-store'] endif @@ -454,13 +493,17 @@ endif if build_examples subdir('examples') endif -if meson.version().version_compare('>=0.57') +# Not in a subproject, whose default test setup would be the project's, which +# may have one of its own, and would leave out its tests of a suite examples; +# nor its target check, which names the build directory of the project (GAOL v5) +if meson.is_subproject() +elif meson.version().version_compare('>=0.57') add_test_setup('unit', exclude_suites: ['examples'], is_default: true) add_test_setup('check') else message('meson ' + meson.version() + ': meson test and ninja test run the examples too (meson test --suite unit runs the unit tests only)') endif -if build_tests or build_examples +if (build_tests or build_examples) and not meson.is_subproject() run_target('check', command: [find_program('meson'), 'test', '-C', meson.current_build_dir(), '--no-rebuild', '--print-errorlogs'] + (meson.version().version_compare('>=0.57') ? ['--setup', 'check'] : []), @@ -469,9 +512,10 @@ endif # make perf, as with CMake and configure: GAOL v5 measured on the benchmark of # doc/compare/performance.md, whose tables get its new times (see -# doc/compare/code/run_perf.sh). Linux only, as the benchmark (GAOL v5). +# doc/compare/code/run_perf.sh). Linux only, as the benchmark, and not with +# enable-debug, which would measure GAOL built for debugging (GAOL v5). bash = find_program('bash', required: false) -if host_machine.system() == 'linux' and bash.found() +if host_machine.system() == 'linux' and bash.found() and not get_option('enable-debug') bench_dir = meson.current_source_dir() + '/doc/compare/code' gaol_bench = executable('gaol_bench', bench_dir + '/bench_gaol.cpp', include_directories: include_directories('.', 'doc/compare/code'), diff --git a/meson_options.txt b/meson_options.txt index 71d00693..1f5fb6f1 100755 --- a/meson_options.txt +++ b/meson_options.txt @@ -6,14 +6,18 @@ # The build type gives the optimizations and the debugging, as with CMake: # --buildtype=release (the default) for -O3 and the optimizations of # configure's --enable-optimize, --buildtype=debug for GAOL_DEBUGGING, as -# configure's --enable-debug. The options enable-optimize and enable-debug, -# and enable-relations, with-test and check-perf, are gone (GAOL v5). +# configure's --enable-debug. enable-debug builds the libraries of GAOL for +# debugging whatever the build type, as GAOL_DEBUG of CMake, a subproject +# included, which meson before 1.8.4 builds in release otherwise (see +# meson.build). The options enable-optimize, enable-relations, with-test and +# check-perf are gone (GAOL v5). option('enable-simd', type : 'boolean', value : true, description : 'Compute the intervals with SSE2 instructions on x86 processors [default=yes, as configure]') option('enable-fma', type : 'boolean', value : true, description : 'Compile GAOL and CORE-MATH with the fused multiply-add instructions of the processor, where the compiler has a flag for them (false: a library for any processor of the architecture) [default=yes, as configure and CMake]') option('enable-asm', type : 'boolean', value : true, description : 'Use assembler code [default=yes, as configure]') option('enable-verbose-mode', type : 'boolean', value : false, description : 'Write a line on the standard error when GAOL initializes and cleans up [default=no: GAOL is silent, as with configure and CMake]') option('enable-preserve-rounding', type : 'boolean', value : false, description : 'Restore the rounding direction after each operation, rather than leaving it upward') option('enable-prefer-avx512', type : 'boolean', value : false, description : 'Have +, -, *, / and sqrt take the AVX-512 instructions and the rounding direction they carry in themselves, which sets neither the rounding direction nor the flush-to-zero modes, on a processor that has them [default=false, true with enable-preserve-rounding on a compiler that takes the path; meson cannot refuse the path under enable-preserve-rounding, which -DGAOL_PREFER_AVX512=OFF of CMake and --disable-prefer-avx512 of configure do, as CMake and configure]') +option('enable-debug', type: 'boolean', value: false, description: 'Build GAOL and CORE-MATH for debugging, without optimization and with GAOL_DEBUGGING, whatever the build type, a subproject included [default=no, as GAOL_DEBUG of CMake; configure --enable-debug]') option('enable-exception', type: 'boolean', value: true, description: 'Raise exceptions to signal errors [default=yes]') option('with-tests', type: 'boolean', value: false, description: 'Build the unit tests of tests/, which meson test (make test) and ninja check (make check) run [default=no, as WITH_TESTS of CMake and --with-tests of configure]') option('with-examples', type: 'boolean', value: false, description: 'Build the examples of examples/, which ninja check (make check) runs [default=no, as WITH_EXAMPLES of CMake and --with-examples of configure]') diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 464a9430..98740594 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,8 +7,10 @@ # check/ and ran with CppUnit, check the results of the operations on chosen # intervals (see unit_tests.h). They are compiled as any code using GAOL, with # the flags gaol::gaol carries, and in C++17 for the hexadecimal floating -# literals of elementary_values.h. WITH_TESTS builds them (CMakeLists.txt); -# make test and make check run them, with the label unit. +# literals of the tests, such as 0x1p-1060: those of gaol_tests.h, which all +# but u128.cpp include, of the *_values.h, and of several of the programs. +# WITH_TESTS builds them (CMakeLists.txt); make test and make check run them, +# with the label unit. # # Copyright (c) 2026 ENSTA, France # diff --git a/tests/Makefile.am b/tests/Makefile.am index 1efc7197..5253d2af 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -3,11 +3,13 @@ # ./configure --with-tests builds them with GAOL (make), and make check and # make test run them (see ../Makefile.am). They are compiled as any code using # GAOL, with the flags of interval arithmetic configure gives, in C++17 for the -# hexadecimal floating literals of elementary_values.h, and linked with the -# static libgaol just built (-static: a libtool library not installed), and -# with the link option gaol.pc gives (-mno-daz-ftz, where the compiler takes -# it), as CMake links them. Exit status 77 is a test skipped (intervalf and -# interval2f where the intervals of floats are not compiled). +# hexadecimal floating literals of the tests (those of gaol_tests.h, which all +# but u128.cpp include, of the *_values.h, and of several of the programs; see +# CMakeLists.txt), and linked with the static libgaol just built (-static: a +# libtool library not installed), and with the link option gaol.pc gives +# (-mno-daz-ftz, where the compiler takes it), as CMake links them. Exit status +# 77 is a test skipped (intervalf and interval2f where the intervals of floats +# are not compiled). # # make perf measures GAOL v5 on the benchmark of doc/compare/performance.md # (doc/compare/code/run_perf.sh). diff --git a/tests/Makefile.in b/tests/Makefile.in index 31d51b45..e9007d75 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -19,11 +19,13 @@ # ./configure --with-tests builds them with GAOL (make), and make check and # make test run them (see ../Makefile.am). They are compiled as any code using # GAOL, with the flags of interval arithmetic configure gives, in C++17 for the -# hexadecimal floating literals of elementary_values.h, and linked with the -# static libgaol just built (-static: a libtool library not installed), and -# with the link option gaol.pc gives (-mno-daz-ftz, where the compiler takes -# it), as CMake links them. Exit status 77 is a test skipped (intervalf and -# interval2f where the intervals of floats are not compiled). +# hexadecimal floating literals of the tests (those of gaol_tests.h, which all +# but u128.cpp include, of the *_values.h, and of several of the programs; see +# CMakeLists.txt), and linked with the static libgaol just built (-static: a +# libtool library not installed), and with the link option gaol.pc gives +# (-mno-daz-ftz, where the compiler takes it), as CMake links them. Exit status +# 77 is a test skipped (intervalf and interval2f where the intervals of floats +# are not compiled). # # make perf measures GAOL v5 on the benchmark of doc/compare/performance.md # (doc/compare/code/run_perf.sh). diff --git a/tests/debugging.cpp b/tests/debugging.cpp index 0df324da..7cfa8b67 100644 --- a/tests/debugging.cpp +++ b/tests/debugging.cpp @@ -6,13 +6,15 @@ * The Debug builds define GAOL_DEBUGGING in gaol/gaol_configuration.h * (CMAKE_BUILD_TYPE=Debug, configure --enable-debug, meson * --buildtype=debug): GAOL then checks its assertions (GAOL_ASSERT), and - * GAOL_DEBUG(level, command) runs command where the level given to + * GAOL_DEBUG_VERBOSE(level, command) runs command where the level given to * gaol::init() is level or more. gaol/gaol_expression.h did not compile with - * it: its GAOL_DEBUG write on std::cout, which no header of GAOL included - * (configure --enable-debug, the only build that defined it, failed). This - * test includes GAOL's headers with GAOL_DEBUGGING whatever the build, builds - * and evaluates an expression, whose nodes call GAOL_DEBUG, and checks that - * GAOL_DEBUG runs its command at the level given to gaol::init(). + * it: its GAOL_DEBUG_VERBOSE write on std::cout, which no header of GAOL + * included (configure --enable-debug, the only build that defined it, + * failed). This test includes GAOL's headers with GAOL_DEBUGGING whatever the + * build, builds and evaluates an expression, whose nodes call + * GAOL_DEBUG_VERBOSE, and checks that GAOL_DEBUG_VERBOSE runs its command at + * the level given to gaol::init(). The macro was named GAOL_DEBUG before GAOL + * v5. * * Copyright (c) 2026 ENSTA, France * @@ -40,7 +42,8 @@ using namespace gaol_tests; int main() { - // Level 2: the commands of GAOL_DEBUG(1, ...) and GAOL_DEBUG(2, ...) run + // Level 2: the commands of GAOL_DEBUG_VERBOSE(1, ...) and + // GAOL_DEBUG_VERBOSE(2, ...) run gaol::init(2); std::ostringstream out; @@ -49,15 +52,15 @@ int main() const expression e = x + x * expression(3.0); expr_eval ev; e.get_root()->accept(ev); - GAOL_DEBUG(2, std::cout << "level 2"); - GAOL_DEBUG(3, std::cout << "level 3"); + GAOL_DEBUG_VERBOSE(2, std::cout << "level 2"); + GAOL_DEBUG_VERBOSE(3, std::cout << "level 3"); std::cout.rdbuf(saved); check("GAOL_DEBUGGING: an expression is evaluated", ev.result().set_eq(interval(4.0, 8.0)), [&] { return hex(ev.result()); }); - check("GAOL_DEBUGGING: GAOL_DEBUG runs its command at the level given to init()", + check("GAOL_DEBUGGING: GAOL_DEBUG_VERBOSE runs its command at the level given to init()", out.str().find("level 2") != std::string::npos, [&] { return out.str(); }); - check("GAOL_DEBUGGING: GAOL_DEBUG does not run it above that level", + check("GAOL_DEBUGGING: GAOL_DEBUG_VERBOSE does not run it above that level", out.str().find("level 3") == std::string::npos, [&] { return out.str(); }); gaol::cleanup(); diff --git a/tests/meson.build b/tests/meson.build index 70a6a68a..c1c32327 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -8,10 +8,12 @@ # Built where with-tests is true; each is a test of the suite unit, which meson # test (make test) and meson test --setup check (make check) run. They are # compiled as any code using GAOL, in C++17 for the hexadecimal floating -# literals of elementary_values.h, and linked with the static libgaol, as CMake -# links them. Exit status 77 is a test skipped (intervalf and interval2f where -# the intervals of floats are not compiled). check/, which built the unit tests -# of GAOL 4 with CppUnit, is gone: they are among these (GAOL v5). +# literals of the tests (those of gaol_tests.h, which all but u128.cpp include, +# of the *_values.h, and of several of the programs; see CMakeLists.txt), and +# linked with the static libgaol, as CMake links them. Exit status 77 is a test +# skipped (intervalf and interval2f where the intervals of floats are not +# compiled). check/, which built the unit tests of GAOL 4 with CppUnit, is +# gone: they are among these (GAOL v5). gaol_tests = [ 'arithmetic', 'elementary', 'rounding_direction', 'numbers', 'other_functions', 'ieee1788', 'reverse', 'u128', 'core_math', 'expressions', 'extended_precision', diff --git a/tests/meson_subproject/check_flags.py b/tests/meson_subproject/check_flags.py new file mode 100644 index 00000000..c5a003fe --- /dev/null +++ b/tests/meson_subproject/check_flags.py @@ -0,0 +1,74 @@ +"""The flags of interval arithmetic in the code of a meson project using GAOL +as a subproject (GAOL v5). + + python3 check_flags.py + +Fails unless each command of compile_commands.json that compiles a source of +the project, not of its subprojects, holds the flags of the Cflags of the +gaol.pc the subproject GAOL wrote in meson-private, its include directory +aside, and unless each command of build.ninja that links an executable of the +project holds the options of its Libs, -L and -l aside (-mno-daz-ftz, where +the compiler takes it; with a compiler that refuses it, there is none): the +code including GAOL's headers is to be compiled and linked with them (see +doc/using.md), and gaol_dep alone gives them, the arguments of the project +GAOL reaching none of the targets of another project. + +Copyright (c) 2026 ENSTA, France + +Created 2026-10-06 by Jordan NININ +""" +import json +import os +import shlex +import sys + +build, source = sys.argv[1], sys.argv[2] +with open(os.path.join(build, 'meson-private', 'gaol.pc')) as pc: + lines = pc.read().splitlines() +cflags = [line for line in lines if line.startswith('Cflags:')][0] +libs = [line for line in lines if line.startswith('Libs:')][0] +flags = [f for f in shlex.split(cflags[len('Cflags:'):]) + if not f.startswith('-I')] +link_flags = [f for f in shlex.split(libs[len('Libs:'):]) + if not f.startswith(('-L', '-l'))] +with open(os.path.join(build, 'compile_commands.json')) as db: + commands = json.load(db) +subprojects = os.path.join(os.path.normpath(source), 'subprojects') + os.sep +checked = 0 +failed = 0 +for command in commands: + path = os.path.normpath(os.path.join(command['directory'], command['file'])) + if path.startswith(subprojects): + continue + checked += 1 + missing = [f for f in flags if f not in shlex.split(command['command'])] + if missing: + failed += 1 + print('%s is compiled without %s' + % (command['file'], ' '.join(missing))) +print('%d command(s) of the project checked for %s' + % (checked, ' '.join(flags))) + +# The links of the executables of the project: a statement "build : +# cpp_LINKER ..." of build.ninja, whose variable LINK_ARGS follows on an +# indented line; those of the subprojects are under subprojects/ +linked = 0 +with open(os.path.join(build, 'build.ninja')) as ninja: + statements = ninja.read().split('\nbuild ') +for statement in statements[1:]: + head, _, rest = statement.partition('\n') + target, _, rule = head.partition(': ') + if not rule.startswith(('cpp_LINKER', 'c_LINKER')) or \ + target.startswith('subprojects/'): + continue + args = [line.strip()[len('LINK_ARGS = '):] for line in rest.split('\n') + if line.startswith(' ') and line.strip().startswith('LINK_ARGS = ')] + linked += 1 + missing = [f for f in link_flags + if f not in shlex.split(args[0] if args else '')] + if missing: + failed += 1 + print('%s is linked without %s' % (target, ' '.join(missing))) +print('%d link(s) of the project checked for %s' + % (linked, ' '.join(link_flags) or 'no option (gaol.pc gives none)')) +sys.exit(1 if failed or not checked or not flags or not linked else 0) diff --git a/tests/meson_subproject/meson.build b/tests/meson_subproject/meson.build new file mode 100644 index 00000000..c5b65723 --- /dev/null +++ b/tests/meson_subproject/meson.build @@ -0,0 +1,59 @@ +# ================================================================== +# The tests of GAOL built with a GAOL brought in as a meson subproject +# ================================================================== +# +# Builds six of the tests of the parent directory, those of tests/fetch_content, +# as a meson project bringing GAOL in as a subproject would (GAOL v5): GAOL is +# then targets of this project, built with it, and gaol_dep gives the code of +# this project the flags of interval arithmetic, which the test flags checks. +# In the default build type of meson, debug, which this project is to be +# configured in, GAOL is built in release all the same, which the test release +# checks. GAOL is to be in subprojects/gaol, a link to its sources, as the +# continuous integration makes it (.github/workflows/build-systems.yml): +# +# mkdir tests/meson_subproject/subprojects +# ln -s tests/meson_subproject/subprojects/gaol +# meson setup build-meson-subproject tests/meson_subproject +# meson test -C build-meson-subproject +# rm tests/meson_subproject/subprojects/gaol +# +# The link, which git ignores, is to be removed after: it leads back to the +# root of the sources, and a copy of them that follows links, as tar -h does, +# would never end. +# +# Copyright (c) 2026 ENSTA, France +# +# Created 2026-10-06 by Jordan NININ + +project('gaol_tests_meson_subproject', 'cpp') + +# A default test setup of this project's own, as a project may have: GAOL +# declared one too as a subproject, and meson stopped on it ("is_default can be +# set to true only once") +add_test_setup('meson_subproject', is_default: true) + +gaol_dep = subproject('gaol').get_variable('gaol_dep') + +foreach t : ['arithmetic', 'elementary', 'rounding_direction', 'numbers', + 'other_functions', 'reverse'] + exe = executable('gaol_test_' + t, '../' + t + '.cpp', + dependencies: gaol_dep, + override_options: ['cpp_std=c++17']) + test(t, exe, timeout: 300) +endforeach + +# The arguments GAOL gives its own targets do not reach those of this project: +# the commands that compile the tests above have to hold the flags of the +# gaol.pc the subproject wrote, and those that link them its link option +# (-mno-daz-ftz, where the compiler takes it), which only gaol_dep gives them. +# Without them, the tests pass all the same (GCC 9.4, x86_64) +test('flags', find_program('python3'), + args: [files('check_flags.py'), meson.current_build_dir(), + meson.current_source_dir()]) + +# The libraries of GAOL and CORE-MATH compiled as in release, -O3 and NDEBUG, +# and GAOL_DEBUGGING undefined: before 1.8.4, meson gives a subproject the +# build type of the project (see meson.build) +test('release', find_program('python3'), + args: [files('../release_flags.py'), meson.current_build_dir(), + join_paths(meson.current_source_dir(), 'subprojects', 'gaol')]) diff --git a/tests/release_flags.py b/tests/release_flags.py new file mode 100644 index 00000000..dc229c9d --- /dev/null +++ b/tests/release_flags.py @@ -0,0 +1,81 @@ +"""GAOL built in release by default, brought into another project (GAOL v5). + + python3 release_flags.py [--debug] + +Fails unless each command of the compile_commands.json of the build directory +that compiles a source of GAOL or of CORE-MATH (/gaol/, +/3rd/) optimizes as the release build does (its last -O is -O3, or +/O2 with Visual C++) and defines NDEBUG, and unless the gaol_configuration.h +of the build leaves GAOL_DEBUGGING undefined: a project that brings GAOL in +without choosing a build type, as a CMake project without CMAKE_BUILD_TYPE +(add_subdirectory, FetchContent) or a meson project in the default build type +of meson (a subproject), gets GAOL in release, as configure builds it. +tests/meson_subproject runs it, and the continuous integration on +tests/fetch_content (.github/workflows/linux.yml). + +With --debug, the other way round, for GAOL_DEBUG of CMake and enable-debug of +meson: no optimization (no -O, or a last -O0 or /Od), NDEBUG not defined in +the end (no -DNDEBUG, or a -UNDEBUG after it), and GAOL_DEBUGGING defined, by +gaol_configuration.h or on the command line. + +Copyright (c) 2026 ENSTA, France + +Created 2026-10-06 by Jordan NININ +""" +import json +import os +import re +import shlex +import sys + +args = sys.argv[1:] +debug = args[:1] == ['--debug'] +if debug: + args = args[1:] +build, sources = args[0], os.path.normpath(args[1]) +roots = tuple(os.path.join(sources, d) + os.sep for d in ('gaol', '3rd')) +with open(os.path.join(build, 'compile_commands.json')) as db: + commands = json.load(db) +headers = [os.path.join(d, f) for d, _, files in os.walk(build) for f in files + if f == 'gaol_configuration.h'] +header_debugging = False +for header in headers: + with open(header) as h: + if re.search(r'^\s*#\s*define\s+GAOL_DEBUGGING\b', h.read(), re.M): + header_debugging = True +checked = 0 +failed = 0 +for command in commands: + path = os.path.normpath(os.path.join(command['directory'], command['file'])) + if not path.startswith(roots): + continue + checked += 1 + tokens = shlex.split(command['command']) + levels = [t for t in tokens if re.match(r'^[-/]O([0-3sgdxz]|fast)?$', t)] + level = levels[-1] if levels else None + ndebug = [t for t in tokens if re.match(r'^[-/][DU]NDEBUG(=1)?$', t)] + ndebug = bool(ndebug) and ndebug[-1][1] == 'D' + debugging = header_debugging or any( + re.match(r'^[-/]DGAOL_DEBUGGING(=1)?$', t) for t in tokens) + problems = [] + if debug: + if level not in (None, '-O0', '/Od'): + problems.append('optimization %s' % level) + if ndebug: + problems.append('NDEBUG') + if not debugging: + problems.append('no GAOL_DEBUGGING') + else: + if level not in ('-O3', '/O2'): + problems.append('optimization %s' % (level or 'none')) + if not ndebug: + problems.append('no NDEBUG') + if debugging: + problems.append('GAOL_DEBUGGING') + if problems: + failed += 1 + print('%s: %s' % (command['file'], ', '.join(problems))) +print('%d command(s) of GAOL and CORE-MATH checked for %s, ' + '%d gaol_configuration.h' + % (checked, 'debug' if debug else 'release', len(headers))) +sys.exit(1 if failed or not checked or not headers else 0)