From ba3ce67712c4c137482823dfcd8cd2c62973a221 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 17 Sep 2026 08:54:26 +1000 Subject: [PATCH 1/9] 0.0.1-alpha1 --- .gitattributes | 17 + .github/workflows/ci-cell.yml | 332 ++++++++++++++++++ .github/workflows/ci.yml | 204 +++++++++++ .gitignore | 242 +++++++++++++ .sis/project_name.txt | 1 + .sis/script_info_lines.txt | 2 + .vimrc | 70 ++++ .vscode/settings.json | 182 ++++++++++ AUTHORS.md | 21 ++ CHANGES.md | 11 + CMakeLists.txt | 279 +++++++++++++++ FAQ.md | 61 ++++ INSTALL.md | 143 ++++++++ LICENSE | 33 ++ NEWS.md | 16 + README.md | 118 ++++++- TODO.md | 48 +++ build_cmake.sh | 125 +++++++ clean_cmake.sh | 87 +++++ cmake/BuildType.cmake | 61 ++++ cmake/LanguageFullVersion.cmake | 63 ++++ cmake/TargetMacros.cmake | 104 ++++++ cmake/cmpfs-config.cmake.in | 2 + ctest_cmake.sh | 108 ++++++ examples/CMakeLists.txt | 33 ++ examples/c/CMakeLists.txt | 4 + examples/c/example.c.1/CMakeLists.txt | 1 + examples/c/example.c.1/example.c.1.c | 60 ++++ include/cmpfs/cmpfs.h | 241 +++++++++++++ prepare_cmake.sh | 193 ++++++++++ remove_cmake_artefacts.sh | 153 ++++++++ run_all_examples.sh | 132 +++++++ run_all_scratch_tests.sh | 137 ++++++++ run_all_unit_tests.cmd | 188 ++++++++++ run_all_unit_tests.sh | 200 +++++++++++ src/CMakeLists.txt | 89 +++++ src/compare.api.c | 107 ++++++ test/CMakeLists.txt | 34 ++ test/scratch/CMakeLists.txt | 4 + .../test.scratch.compare/CMakeLists.txt | 1 + test/scratch/test.scratch.compare/main.c | 36 ++ test/unit/CMakeLists.txt | 5 + .../unit/test.unit.compare.api/CMakeLists.txt | 1 + .../test.unit.compare.api.c | 84 +++++ test/unit/test.unit.version/CMakeLists.txt | 1 + .../test.unit.version/test.unit.version.c | 69 ++++ 46 files changed, 4101 insertions(+), 2 deletions(-) create mode 100644 .gitattributes create mode 100644 .github/workflows/ci-cell.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .sis/project_name.txt create mode 100644 .sis/script_info_lines.txt create mode 100644 .vimrc create mode 100644 .vscode/settings.json create mode 100644 AUTHORS.md create mode 100644 CHANGES.md create mode 100644 CMakeLists.txt create mode 100644 FAQ.md create mode 100644 INSTALL.md create mode 100644 LICENSE create mode 100644 NEWS.md create mode 100644 TODO.md create mode 100755 build_cmake.sh create mode 100755 clean_cmake.sh create mode 100644 cmake/BuildType.cmake create mode 100644 cmake/LanguageFullVersion.cmake create mode 100644 cmake/TargetMacros.cmake create mode 100644 cmake/cmpfs-config.cmake.in create mode 100755 ctest_cmake.sh create mode 100644 examples/CMakeLists.txt create mode 100644 examples/c/CMakeLists.txt create mode 100644 examples/c/example.c.1/CMakeLists.txt create mode 100644 examples/c/example.c.1/example.c.1.c create mode 100644 include/cmpfs/cmpfs.h create mode 100755 prepare_cmake.sh create mode 100755 remove_cmake_artefacts.sh create mode 100755 run_all_examples.sh create mode 100755 run_all_scratch_tests.sh create mode 100755 run_all_unit_tests.cmd create mode 100755 run_all_unit_tests.sh create mode 100644 src/CMakeLists.txt create mode 100644 src/compare.api.c create mode 100644 test/CMakeLists.txt create mode 100644 test/scratch/CMakeLists.txt create mode 100644 test/scratch/test.scratch.compare/CMakeLists.txt create mode 100644 test/scratch/test.scratch.compare/main.c create mode 100644 test/unit/CMakeLists.txt create mode 100644 test/unit/test.unit.compare.api/CMakeLists.txt create mode 100644 test/unit/test.unit.compare.api/test.unit.compare.api.c create mode 100644 test/unit/test.unit.version/CMakeLists.txt create mode 100644 test/unit/test.unit.version/test.unit.version.c diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e6605d1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,17 @@ +*.c linguist-language=C +*.cmake linguist-language=CMake +*.cmd linguist-detectable=false +*.cpp linguist-language=C++ +*.cxx linguist-language=C++ +*.dsp linguist-detectable=false +*.dsw linguist-detectable=false +*.h linguist-language=C +*.hpp linguist-language=C++ +*.html linguist-detectable=false +*.hxx linguist-language=C++ +*.sh linguist-detectable=false +*.sln linguist-detectable=false +*.vcxproj linguist-detectable=false +*.vimrc linguist-detectable=false +CMakeLists.txt linguist-language=CMake +makefile linguist-detectable=false diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml new file mode 100644 index 0000000..dc1f587 --- /dev/null +++ b/.github/workflows/ci-cell.yml @@ -0,0 +1,332 @@ +name: CI cell + +on: + workflow_call: + inputs: + cell-id: + required: true + type: string + os: + required: true + type: string + c-compiler: + required: true + type: string + cpp-compiler: + required: true + type: string + build-type: + required: false + type: string + default: Release + +jobs: + build: + name: Build (${{ inputs.cell-id }}) + runs-on: ${{ inputs.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Install Clang (Ubuntu) + if: runner.os == 'Linux' && inputs.c-compiler == 'clang' + run: sudo apt-get update && sudo apt-get install -y clang + + - name: Setup MSYS2 MinGW + if: runner.os == 'Windows' && inputs.c-compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: >- + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-make + + - name: Install test dependencies (STLSoft + shwild + xTests) + shell: bash + run: | + set -euxo pipefail + + DEPS="${RUNNER_TEMP}/sis-deps" + STLSRC="${RUNNER_TEMP}/stlsoft-src" + STLBUILD="${RUNNER_TEMP}/stlsoft-build" + SHWSRC="${RUNNER_TEMP}/shwild-src" + SHWBUILD="${RUNNER_TEMP}/shwild-build" + XTSRC="${RUNNER_TEMP}/xtests-src" + XTBUILD="${RUNNER_TEMP}/xtests-build" + + mkdir -p "$DEPS" + + # 1. STLSoft + git clone --depth 1 https://github.com/synesissoftware/STLSoft "$STLSRC" + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake -S "$STLSRC" -B "$STLBUILD" \ + -DCMAKE_DISABLE_FIND_PACKAGE_MFC=TRUE \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$STLBUILD" --config "${{ inputs.build-type }}" --parallel + cmake --install "$STLBUILD" --config "${{ inputs.build-type }}" + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake -S "$STLSRC" -B "$STLBUILD" -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$STLBUILD" --parallel 2 + cmake --install "$STLBUILD" + else + cmake -S "$STLSRC" -B "$STLBUILD" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER="${{ inputs.c-compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ inputs.cpp-compiler }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$STLBUILD" --parallel + cmake --install "$STLBUILD" + fi + + # 2. shwild + git clone --depth 1 https://github.com/synesissoftware/shwild "$SHWSRC" + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake -S "$SHWSRC" -B "$SHWBUILD" \ + -DCMAKE_DISABLE_FIND_PACKAGE_MFC=TRUE \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$SHWBUILD" --config "${{ inputs.build-type }}" --parallel + cmake --install "$SHWBUILD" --config "${{ inputs.build-type }}" + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake -S "$SHWSRC" -B "$SHWBUILD" -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$SHWBUILD" --parallel 2 + cmake --install "$SHWBUILD" + else + cmake -S "$SHWSRC" -B "$SHWBUILD" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER="${{ inputs.c-compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ inputs.cpp-compiler }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$SHWBUILD" --parallel + cmake --install "$SHWBUILD" + fi + + # 3. xTests + git clone --depth 1 https://github.com/synesissoftware/xTests "$XTSRC" + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake -S "$XTSRC" -B "$XTBUILD" \ + -DCMAKE_DISABLE_FIND_PACKAGE_MFC=TRUE \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$XTBUILD" --config "${{ inputs.build-type }}" --parallel + cmake --install "$XTBUILD" --config "${{ inputs.build-type }}" + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake -S "$XTSRC" -B "$XTBUILD" -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$XTBUILD" --parallel 2 + cmake --install "$XTBUILD" + else + cmake -S "$XTSRC" -B "$XTBUILD" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER="${{ inputs.c-compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ inputs.cpp-compiler }}" \ + -DCMAKE_INSTALL_PREFIX="$DEPS" \ + -DCMAKE_PREFIX_PATH="$DEPS" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + cmake --build "$XTBUILD" --parallel + cmake --install "$XTBUILD" + fi + + - name: Configure + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake -B build -S . \ + -DCMAKE_DISABLE_FIND_PACKAGE_MFC=TRUE \ + -DCMAKE_PREFIX_PATH="${RUNNER_TEMP}/sis-deps" \ + -DBUILD_EXAMPLES=ON \ + -DBUILD_TESTING=ON + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake -B build -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_PREFIX_PATH="${RUNNER_TEMP}/sis-deps" \ + -DBUILD_EXAMPLES=ON \ + -DBUILD_TESTING=ON + else + cmake -B build -S . \ + -DCMAKE_BUILD_TYPE="${{ inputs.build-type }}" \ + -DCMAKE_C_COMPILER="${{ inputs.c-compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ inputs.cpp-compiler }}" \ + -DCMAKE_PREFIX_PATH="${RUNNER_TEMP}/sis-deps" \ + -DBUILD_EXAMPLES=ON \ + -DBUILD_TESTING=ON + fi + + - name: Build + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "cl" ]; then + cmake --build build --config "${{ inputs.build-type }}" --parallel + elif [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake --build build --parallel 2 + else + cmake --build build --parallel + fi + + - name: Upload build tree + uses: actions/upload-artifact@v4 + with: + name: sis-build-${{ inputs.cell-id }} + path: build + retention-days: 1 + + run-examples: + name: Examples (${{ inputs.cell-id }}) + needs: build + runs-on: ${{ inputs.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup MSYS2 MinGW + if: runner.os == 'Windows' && inputs.c-compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: mingw-w64-x86_64-toolchain + + - name: Download build tree + uses: actions/download-artifact@v4 + with: + name: sis-build-${{ inputs.cell-id }} + path: build + + - name: Run examples + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_examples.sh -M + + test-unit: + name: Unit tests (${{ inputs.cell-id }}) + needs: build + runs-on: ${{ inputs.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup MSYS2 MinGW + if: runner.os == 'Windows' && inputs.c-compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: mingw-w64-x86_64-toolchain + + - name: Download build tree + uses: actions/download-artifact@v4 + with: + name: sis-build-${{ inputs.cell-id }} + path: build + + - name: Run unit tests + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_unit_tests.sh -M --unit-only + + test-component: + name: Component tests (${{ inputs.cell-id }}) + needs: build + runs-on: ${{ inputs.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup MSYS2 MinGW + if: runner.os == 'Windows' && inputs.c-compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: mingw-w64-x86_64-toolchain + + - name: Download build tree + uses: actions/download-artifact@v4 + with: + name: sis-build-${{ inputs.cell-id }} + path: build + + - name: Run component tests + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_unit_tests.sh -M --component-only + + test-scratch: + name: Scratch tests (${{ inputs.cell-id }}) + needs: build + continue-on-error: true + runs-on: ${{ inputs.os }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup MSYS2 MinGW + if: runner.os == 'Windows' && inputs.c-compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: mingw-w64-x86_64-toolchain + + - name: Download build tree + uses: actions/download-artifact@v4 + with: + name: sis-build-${{ inputs.cell-id }} + path: build + + - name: Run scratch tests + shell: bash + run: | + set -euo pipefail + if [ "${{ inputs.c-compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + fi + SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_scratch_tests.sh -M diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a4e5063 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,204 @@ +name: CI + +on: + push: + branches: + - master + - dev + - boilerplate + - idiomatic + - rc1 + - rc2 + - rc3 + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + BUILD_TYPE: Release + +jobs: + cell: + name: CI (${{ matrix.id }}) + strategy: + fail-fast: false + matrix: + include: + - id: linux-clang + os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + - id: linux-gcc + os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - id: macos-clang + os: macos-latest + c_compiler: clang + cpp_compiler: clang++ + - id: macos-gcc + os: macos-latest + c_compiler: gcc + cpp_compiler: g++ + - id: windows-cl + os: windows-latest + c_compiler: cl + cpp_compiler: cl + - id: windows-mingw + os: windows-latest + c_compiler: mingw + cpp_compiler: g++ + uses: ./.github/workflows/ci-cell.yml + with: + cell-id: ${{ matrix.id }} + os: ${{ matrix.os }} + c-compiler: ${{ matrix.c_compiler }} + cpp-compiler: ${{ matrix.cpp_compiler }} + build-type: Release + secrets: inherit + + install-smoke: + name: Install smoke (${{ matrix.os }}, ${{ matrix.c_compiler }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + - os: macos-latest + c_compiler: clang + cpp_compiler: clang++ + - os: windows-latest + c_compiler: cl + cpp_compiler: cl + - os: windows-latest + c_compiler: mingw + cpp_compiler: g++ + + steps: + - uses: actions/checkout@v4 + + - name: Install Clang (Ubuntu) + if: runner.os == 'Linux' && matrix.c_compiler == 'clang' + run: sudo apt-get update && sudo apt-get install -y clang + + - name: Setup MSYS2 MinGW + if: runner.os == 'Windows' && matrix.c_compiler == 'mingw' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + update: true + install: >- + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-make + + - name: Configure + shell: bash + run: | + set -euo pipefail + if [ "${{ matrix.c_compiler }}" = "cl" ]; then + cmake -B build -S . \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + elif [ "${{ matrix.c_compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake -B build -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ env.BUILD_TYPE }}" \ + -DCMAKE_C_COMPILER=gcc \ + -DCMAKE_CXX_COMPILER=g++ \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + else + cmake -B build -S . \ + -DCMAKE_BUILD_TYPE="${{ env.BUILD_TYPE }}" \ + -DCMAKE_C_COMPILER="${{ matrix.c_compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ matrix.cpp_compiler }}" \ + -DBUILD_EXAMPLES=OFF \ + -DBUILD_TESTING=OFF + fi + + - name: Build + shell: bash + run: | + set -euo pipefail + if [ "${{ matrix.c_compiler }}" = "cl" ]; then + cmake --build build --config "${{ env.BUILD_TYPE }}" --parallel + elif [ "${{ matrix.c_compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake --build build --parallel 2 + else + cmake --build build --parallel + fi + + - name: Install + shell: bash + run: | + set -euo pipefail + PREFIX="${RUNNER_TEMP}/install-prefix" + echo "INSTALL_PREFIX=$PREFIX" >> "$GITHUB_ENV" + if [ "${{ matrix.c_compiler }}" = "cl" ]; then + cmake --install build --config "${{ env.BUILD_TYPE }}" --prefix "$PREFIX" + else + cmake --install build --prefix "$PREFIX" + fi + + - name: Verify install tree + shell: bash + run: | + set -euo pipefail + test -f "${INSTALL_PREFIX}/include/cmpfs/cmpfs.h" + test -f "${INSTALL_PREFIX}/lib/cmake/cmpfs/cmpfs-config.cmake" + + - name: Configure and run install smoke consumer + shell: bash + run: | + set -euo pipefail + CONSUMER="${RUNNER_TEMP}/consumer" + mkdir -p "$CONSUMER" + cat > "$CONSUMER/CMakeLists.txt" <<'EOF' + cmake_minimum_required(VERSION 3.20) + project(cmpfs_install_smoke C) + find_package(cmpfs REQUIRED) + add_executable(consumer consumer.c) + target_link_libraries(consumer PRIVATE cmpfs::core) + EOF + cat > "$CONSUMER/consumer.c" <<'EOF' + #include + #include + #ifndef ENOSYS + # define ENOSYS 78 + #endif + int main(void) + { + return (ENOSYS == cmpfs_compare_binary_files("a", "b", 0)) ? 0 : 1; + } + EOF + if [ "${{ matrix.c_compiler }}" = "cl" ]; then + cmake -S "$CONSUMER" -B consumer-build \ + -DCMAKE_PREFIX_PATH="${INSTALL_PREFIX}" + cmake --build consumer-build --config "${{ env.BUILD_TYPE }}" --parallel + consumer-build/${{ env.BUILD_TYPE }}/consumer.exe + elif [ "${{ matrix.c_compiler }}" = "mingw" ]; then + export PATH="/mingw64/bin:$PATH" + cmake -S "$CONSUMER" -B consumer-build -G "MinGW Makefiles" \ + -DCMAKE_BUILD_TYPE="${{ env.BUILD_TYPE }}" \ + -DCMAKE_PREFIX_PATH="${INSTALL_PREFIX}" + cmake --build consumer-build --parallel 2 + consumer-build/consumer.exe + else + cmake -S "$CONSUMER" -B consumer-build \ + -DCMAKE_BUILD_TYPE="${{ env.BUILD_TYPE }}" \ + -DCMAKE_C_COMPILER="${{ matrix.c_compiler }}" \ + -DCMAKE_CXX_COMPILER="${{ matrix.cpp_compiler }}" \ + -DCMAKE_PREFIX_PATH="${INSTALL_PREFIX}" + cmake --build consumer-build --parallel + consumer-build/consumer + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68e4424 --- /dev/null +++ b/.gitignore @@ -0,0 +1,242 @@ +# Synesis Information Systems .gitignore for C/C++ libraries + + +# directories (by name) + +/.git-old/ +/.vs/ + +.svn/ + +.classpath +/.idea/ +/__pycache__ +/node_modules + +/_build/ +/_build-ci/ +/_internal/ +/_analyses/ + +/bin/ +/ipch/ +/lib/ +bin/ +ipch/ +lib/ + +/doc/ +/docs/ +/dox/ +/dox +/ideas/ +ideas/ +/included/ +/releases/ +/scratch/ +/temp/ + +/--include +/--src +/-include +/-src + +/examples/bin +/examples/c/bin +/examples/cpp/bin + +/examples/lib +/examples/c/lib +/examples/cpp/lib + +projects/util/vc10-generated/ + +perf_test/ + +scripts/internal/ + +/include/shwild/ +/include/xcontract/ +/include/xcover/ +/include/xtests/ +/src/shwild/ +/src/xcontract/ +/src/xcover/ +/src/xtests/ + +Debug Multithreaded DLL/ +Debug Multithreaded Dll/ +Debug Multithreaded pseudoUNIX/ +Debug Multithreaded pseudoUnix/ +Debug Multithreaded/ +Debug/ +DebugDLL/ +DebugDLLUNIX/ +DebugDll/ +DebugMTDLL/ +DebugMTDll/ +DebugMTUnix/ +DebugMt/ +DebugNox/ +DebugUNIX/ +DebugUnix/ +Release Multithreaded DLL/ +Release Multithreaded Dll/ +Release Multithreaded pseudoUNIX/ +Release Multithreaded pseudoUnix/ +Release Multithreaded/ +Release/ +ReleaseDLL/ +ReleaseDLLUNIX/ +ReleaseDll/ +ReleaseMTDLL/ +ReleaseMTDll/ +ReleaseMTUnix/ +ReleaseMt/ +ReleaseNox/ +ReleaseUnix/ +UDebug/ +UDebugMt/ +URelease/ +UReleaseMt/ +Unicode Debug Multithreaded DLL/ +Unicode Debug Multithreaded Dll/ +Unicode Debug Multithreaded/ +Unicode Debug/ +Unicode Release Multithreaded DLL/ +Unicode Release Multithreaded Dll/ +Unicode Release Multithreaded/ +Unicode Release/ + +Win32/ +x64/ + + +# directories (by pattern) + +/build/ar* +/build/bc5* +/build/como* +/build/cw* +/build/gcc3* +/build/gcc4* +/build/icl* +/build/vc5* +/build/*.zip + +/include-*/ + + +# files (by name) + +.DS_Store +.ruby-version +.ruby-version-exclusions +.svnignore +.svnignore-at-root +.update_deps +.env.local +.env.development.local +.env.test.local +.env.production.local + +list_changes.cmd +logging-bailout.txt +prepare.cmd +sh.exe.stackdump +tidydir.cmd +update_deps.cmd + +build/makefile.tmpl +build/makefile.tools.xml +build/shwild.tmplgen +build/CMakeCache.txt + +include/fastformat/internal/dos2unix.has.been.performed +include/pantheios/internal/dos2unix.has.been.performed +include/stlsoft/dos2unix.has.been.performed +include/stlsoft/internal/dos2unix.has.been.performed + +test/testpatterns.orj +test/tests-plan.txt + + +# files (by pattern) + +*~ +*.*~ +*.???_obj +*.VC.db +*.VC.opendb +*.a +*.app +*.aps +*.b64 +*.bak +*.chm +*.class +*.d +*.diff +*.dll +*.dsp +*.dylib +*.exe +*.gch +*.gem +*.idb +*.ilk +*.iobj +*.ipch +*.ipdb +*.la +*.lai +*.lib +*.lo +*.log +*.ncb +*.o +*.obj +*.opensdf +*.opt +*.org +*.out +*.pch +*.pdb +*.pyc +*.rar +*.res +*.sbr +*.scc +*.sdf +*.slo +*.so +*.suo +*.swp +*.sw[ponm] +*.test +*.tlog +*.tmp +*.unsuccessfulbuild +*.vcproj*.user +*.vcxproj*.user +*.csproj*user +*.vcproj*user +*.vcxproj*user +*.xcuserstate +*.zip + +*.vc71.sln +*.vc8.sln +*.vc9.sln + +RCa0* +RCb0* + +build/*.tmplgen +build/*.tmpl +build/*.tools.xml + +npm-debug.log* +yarn-debug.log* +yarn-error.log* + diff --git a/.sis/project_name.txt b/.sis/project_name.txt new file mode 100644 index 0000000..be808fd --- /dev/null +++ b/.sis/project_name.txt @@ -0,0 +1 @@ +cmpfs diff --git a/.sis/script_info_lines.txt b/.sis/script_info_lines.txt new file mode 100644 index 0000000..fb6316a --- /dev/null +++ b/.sis/script_info_lines.txt @@ -0,0 +1,2 @@ +cmpfs - compare file-system entities, for C and C++ +Copyright (c) 2010-2026, Matthew Wilson and Synesis Information Systems diff --git a/.vimrc b/.vimrc new file mode 100644 index 0000000..1bf33a0 --- /dev/null +++ b/.vimrc @@ -0,0 +1,70 @@ +" Synesis C/C++ project .vimrc — aligned with .sis/.vscode/c_cxx/settings.json + +set nocompatible +filetype indent plugin on +syntax enable +set autoindent +set backspace=indent,eol,start +set hlsearch +set incsearch +set number + +" files.insertFinalNewline +set eol +set fixeol + +" editor.renderWhitespace: all +set list +set listchars=tab:->,trail:-,extends:>,precedes:<,nbsp:+ + +" editor.detectIndentation: false — global defaults (editor.tabSize: 4, insertSpaces: true) +set colorcolumn=76 +set expandtab +set shiftwidth=4 +set softtabstop=4 +set tabstop=4 + +" colorcolumn draws a full-column tint in Vim (not a VS Code-style 1px line). +" Keep it subtle via the ColorColumn highlight group; reapply after colorscheme changes. +if has('termguicolors') + " set termguicolors +endif + +function! s:ConfigureColorColumn() abort + highlight ColorColumn ctermbg=236 guibg=#2a2a2a cterm=NONE gui=NONE +endfunction + +call s:ConfigureColorColumn() +autocmd ColorScheme * call s:ConfigureColorColumn() + +" files.trimTrailingWhitespace +autocmd BufWritePre * %s/\s\+$//e + +augroup sis_c_cxx + autocmd! + + " [c] / [cpp] + autocmd FileType c,cpp setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,64,68,72,76 + + " [rust] + autocmd FileType rs setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 + + " [cmake] + autocmd FileType cmake setlocal noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 + + " [shellscript] + autocmd FileType sh,bash,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 + + " [bat] + autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + + " [json] / [markdown] / [yaml] / [ruby] + autocmd FileType json,markdown,yaml,ruby setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 + + " [python] + autocmd FileType python setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + + " [toml] + autocmd FileType toml setlocal noexpandtab tabstop=2 shiftwidth=2 softtabstop=2 +augroup END + diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3fe51d2 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,182 @@ +{ + "[bat]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 4, + }, + "[c]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[cmake]": { + "editor.insertSpaces": false, + "editor.tabSize": 4, + }, + "[cpp]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.tabSize": 4, + }, + "[json]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[markdown]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[python]": { + "diffEditor.ignoreTrimWhitespace": false, + "editor.insertSpaces": true, + "editor.rulers": [ 51, 60, 61, 76 ], + "editor.tabSize": 4, + }, + "[ruby]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "[shellscript]": { + "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], + "editor.tabSize": 2, + }, + "[toml]": { + "editor.insertSpaces": false, + "editor.tabSize": 2, + }, + "[yaml]": { + "editor.insertSpaces": true, + "editor.tabSize": 2, + }, + "cmake.configureOnOpen": false, + "editor.detectIndentation": false, + "editor.insertSpaces": false, + "editor.renderWhitespace": "all", + "editor.rulers": [ 76 ], + "editor.tabSize": 2, + "files.associations": { + "__bit_reference": "cpp", + "__bits": "cpp", + "__config": "cpp", + "__debug": "cpp", + "__errc": "cpp", + "__functional_03": "cpp", + "__functional_base": "cpp", + "__hash_table": "cpp", + "__locale": "cpp", + "__memory": "cpp", + "__mutex_base": "cpp", + "__node_handle": "cpp", + "__nullptr": "cpp", + "__split_buffer": "cpp", + "__string": "cpp", + "__threading_support": "cpp", + "__tree": "cpp", + "__tuple": "cpp", + "__verbose_abort": "cpp", + "algorithm": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "bitset": "cpp", + "cctype": "cpp", + "charconv": "cpp", + "chrono": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "complex": "cpp", + "concepts": "cpp", + "console_functions.h": "c", + "corecrt.h": "c", + "crtdefs.h": "c", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "exception": "cpp", + "execution": "cpp", + "fcntl.h": "c", + "format": "cpp", + "forward_list": "cpp", + "functional": "cpp", + "implicit_link.h": "c", + "initializer_list": "cpp", + "io.h": "c", + "iomanip": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "locale": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "mutex": "cpp", + "new": "cpp", + "numbers": "cpp", + "numeric": "cpp", + "optional": "cpp", + "ostream": "cpp", + "queue": "cpp", + "random": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "semaphore": "cpp", + "set": "cpp", + "setenv.h": "c", + "shwild.h": "c", + "span": "cpp", + "sstream": "cpp", + "stack": "cpp", + "stdexcept": "cpp", + "stdio.h": "c", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "terse-api.h": "c", + "text_encoding": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "uio.h": "c", + "unixem.h": "c", + "unordered_map": "cpp", + "util.h": "c", + "utility": "cpp", + "variant": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocbuf": "cpp", + "xlocinfo": "cpp", + "xlocmes": "cpp", + "xlocmon": "cpp", + "xlocnum": "cpp", + "xloctime": "cpp", + "xmemory": "cpp", + "xstring": "cpp", + "xtests.internal.string.c": "cpp", + "xtr1common": "cpp", + "xtree": "cpp", + "xutility": "cpp", + }, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + "git.mergeEditor": false, +} diff --git a/AUTHORS.md b/AUTHORS.md new file mode 100644 index 0000000..48aa7d8 --- /dev/null +++ b/AUTHORS.md @@ -0,0 +1,21 @@ +# cmpfs - Authors + + +## Major Contributors + +| Name | GitHub | +| -------------- | ------------------------------------- | +| Matthew Wilson | [mwsis](https://github.com/mwsis) | + + +## Defect reports, fixes and suggestions (for which we are very grateful) + +| Name | GitHub | +| ------- | ------ | +| \ | | + + +Contributions are welcomed. + + + diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..77dd7dd --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,11 @@ +# cmpfs - Changes + + +## 0.0.1-alpha1 - 21st August 2026 + +* Created a Synesis-style **C** library skeleton: version macros, **CMake** packaging, **.sis** helper-script identity, modular GitHub Actions CI (**ci.yml** / **ci-cell.yml**), and install-smoke as a C consumer; +* Declared stub **`cmpfs_compare_binary_files()`** and **`cmpfs_compare_text_files()`** (currently **`ENOSYS`**); +* Added C example **example.c.1** and **xTests** unit coverage for version macros and the stub compare API; + + + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..abb9e5b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,279 @@ + +# ######################################################################## # +# File: /CMakeLists.txt +# +# Purpose: Top-level CMake lists file for cmpfs +# +# Created: 21st August 2026 +# Updated: 21st August 2026 +# +# ######################################################################## # + + +# ########################################################## +# CMake + +cmake_minimum_required(VERSION 3.20 FATAL_ERROR) + +# require out-of-source builds +file(TO_CMAKE_PATH "${CMAKE_CURRENT_BINARY_DIR}/CMakeLists.txt" LOC_PATH) +if(EXISTS "${LOC_PATH}") + + message(FATAL_ERROR "You cannot build in a source directory (or any directory with a CMakeLists.txt file). Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.") +endif() + +# directory for CMake specific extensions and source files. +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) + + +# ########################################################## +# project + +project(cmpfs + DESCRIPTION "cmpfs is a C library for comparing file-system entities" + HOMEPAGE_URL "https://github.com/synesissoftware/cmpfs" + LANGUAGES C CXX +) + +string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) +string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER) + +# handle version number +set(RX_PROJ_TAG "CMPFS") +set(RX_WS "[ \t]") +file(READ "${CMAKE_SOURCE_DIR}/include/cmpfs/cmpfs.h" _header_file) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_MAJOR${RX_WS}+([0-9]+)" MAJOR_DUMMY ${_header_file}) +set(_VERSION_MAJOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_MINOR${RX_WS}+([0-9]+)" MINOR_DUMMY ${_header_file}) +set(_VERSION_MINOR ${CMAKE_MATCH_1}) +string(REGEX MATCH "#${RX_WS}*define${RX_WS}+_?${RX_PROJ_TAG}_VER_(PATCH|REVISION)${RX_WS}+([0-9]+)" PATCH_DUMMY ${_header_file}) +set(_VERSION_PATCH ${CMAKE_MATCH_2}) + +# set project version number here +set(PROJECT_VERSION_MAJOR ${_VERSION_MAJOR}) +set(PROJECT_VERSION_MINOR ${_VERSION_MINOR}) +set(PROJECT_VERSION_PATCH ${_VERSION_PATCH}) +set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") + +# adhere strictly to C and C++ standards plus extensions. These state +# our intention for the core library (C) and xTests-backed unit tests (C++). +set(CMAKE_C_STANDARD 17) +set(CMAKE_C_STANDARD_REQUIRED ON) +set(CMAKE_C_EXTENSIONS ON) # GNU extensions and POSIX standard +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS ON) + +if(MSVC) + + if(MSVC_VERSION LESS 1930) + + set(CMAKE_C_STANDARD 90) + set(CMAKE_CXX_STANDARD 98) + endif() + + if(MSVC_USE_MT) + + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif(MSVC_USE_MT) +else(MSVC) + + if(MSVC_USE_MT) + + # this here just to absorb warning about not using `MSVC_USE_MT` (to + # enable **prepare_cmake.sh** to be simple) + endif(MSVC_USE_MT) +endif(MSVC) + + +# ########################################################## +# dependencies, includes, options + +# ################################################ +# includes - 1 + +include(BuildType) +include(LanguageFullVersion) +include(TargetMacros) + + +# ################################################ +# dependencies, features, and options + +# ###################################### +# options + +option(BUILD_EXAMPLES "Build examples" ON) + +option(BUILD_TESTING "Build tests" ON) + + +# ###################################### +# dependencies +# +# required: +# - none for the core library; +# +# optional: +# - STLSoft - required by xTests (for testing); +# - xTests - required for testing; + + +# ############################ +# STLSoft + +if(BUILD_TESTING) + + if(NOT DEFINED STLSOFT AND NOT DEFINED ENV{STLSOFT}) + + set(STLSoft_REQUIRED_VERSION_ 1.11) + + find_package(STLSoft ${STLSoft_REQUIRED_VERSION_} REQUIRED) + + message("-- CMake package STLSoft found (version ${STLSoft_VERSION}; ${STLSoft_REQUIRED_VERSION_} requested)") + else() + + if(DEFINED STLSOFT) + + message("-- STLSOFT provided as CMake variable with value '${STLSOFT}'") + + set(STLSOFT_INCLUDE_DIR ${STLSOFT}/include) + else() + + message("-- STLSOFT provided as environment variable with value '$ENV{STLSOFT}'") + + set(STLSOFT_INCLUDE_DIR $ENV{STLSOFT}/include) + endif() + + get_filename_component(STLSOFT_INCLUDE_DIR "${STLSOFT_INCLUDE_DIR}" ABSOLUTE) + + include_directories(${STLSOFT_INCLUDE_DIR}) + endif() +endif() + + +# ############################ +# xTests + +if(BUILD_TESTING) + + set(xTests_REQUIRED_VERSION_ 0.26.3) + + find_package(xTests ${xTests_REQUIRED_VERSION_} REQUIRED) + + message("-- CMake package xTests found (version ${xTests_VERSION}; ${xTests_REQUIRED_VERSION_} requested)") +endif(BUILD_TESTING) + + +# ################################################ +# includes - 2 + +include(CMakePackageConfigHelpers) +if(BUILD_TESTING) + + include(CTest) +endif(BUILD_TESTING) +include(GNUInstallDirs) + + +# ########################################################## +# targets + +# ################################################ +# custom definitions + +if(UNIX) + + set(_BUILD_AS_UNIX 1) + + message("-- Operating system Unix") +else(UNIX) + + if(WIN32) + + set(_BUILD_AS_WIN32 1) + + message("-- Operating system Windows") + else(WIN32) + + message("-- Operating system unknown") + endif(WIN32) +endif(UNIX) + + +# ################################################ +# main libraries + +add_subdirectory(src) + + +# ################################################ +# examples + +if(BUILD_EXAMPLES) + + message("-- enabled building of examples ...") + + add_subdirectory(examples) +else(BUILD_EXAMPLES) + + message("-- disabled building of examples - define BUILD_EXAMPLES to enable") +endif(BUILD_EXAMPLES) + + +# ################################################ +# tests + +if(BUILD_TESTING) + + message("-- enabled building of tests ...") + + add_subdirectory(test) +else(BUILD_TESTING) + + message("-- disabled building of tests - define BUILD_TESTING to enable") +endif(BUILD_TESTING) + + +# ########################################################## +# export + +set(EXPORT_NAME ${PROJECT_NAME_LOWER}) + +configure_package_config_file( + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/${EXPORT_NAME}-config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${EXPORT_NAME}-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/${EXPORT_NAME}/cmake +) + +write_basic_package_version_file( + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${EXPORT_NAME}-config-version.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) + +export(EXPORT project-targets + FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${EXPORT_NAME}-targets.cmake" + NAMESPACE "${PROJECT_NAME}::" +) + +install(EXPORT project-targets + NAMESPACE "${PROJECT_NAME}::" + FILE "${EXPORT_NAME}-targets.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${EXPORT_NAME} +) + +install( FILES + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${EXPORT_NAME}-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/${EXPORT_NAME}-config-version.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${EXPORT_NAME} +) + + +# ########################################################## +# completion + +message(NOTICE "Generating CMake build scripts for ${PROJECT_NAME} ${PROJECT_VERSION}, for C${CMAKE_C_STANDARD} C++${CMAKE_CXX_STANDARD}, with build type ${CMAKE_BUILD_TYPE}") + + +# ############################## end of file ############################# # diff --git a/FAQ.md b/FAQ.md new file mode 100644 index 0000000..f19a31c --- /dev/null +++ b/FAQ.md @@ -0,0 +1,61 @@ +# cmpfs - FAQ + +The FAQ list is under (constant) development. If you post a question on the +Issues forum (https://github.com/synesissoftware/cmpfs/issues) +it will be used to create one. + + +## Table of Contents + +- [Q1: "How do I build cmpfs?"](#q1-how-do-i-build-cmpfs) +- [Q2: "How do I install cmpfs?"](#q2-how-do-i-install-cmpfs) +- [Q3: "How do I use cmpfs?"](#q3-how-do-i-use-cmpfs) +- [Q4: "Why do the compare functions return ENOSYS?"](#q4-why-do-the-compare-functions-return-enosys) + + +# FAQs: + +## Q1: "How do I build cmpfs?" + +See [INSTALL.md](./INSTALL.md) for the recommended **CMake** flow +(**prepare_cmake.sh**, then **build_cmake.sh**). + +For a minimal core-only build with no external dependencies: + +```bash +$ ./prepare_cmake.sh --disable-testing --disable-examples -m +``` + +For a full build (including tests), install **STLSoft** 1.11 and **xTests** +first, then: + +```bash +$ ./prepare_cmake.sh -m +``` + +Execute `$ ./prepare_cmake.sh --help` for the full set of options. + + +## Q2: "How do I install cmpfs?" + +See [INSTALL.md](./INSTALL.md). + + +## Q3: "How do I use cmpfs?" + +Include **cmpfs/cmpfs.h** and link against **libcmpfs** (the **CMake** +target is `cmpfs::core`). + +Call `cmpfs_compare_binary_files()` or `cmpfs_compare_text_files()`. Paths +must be non-`NULL` (`assert`). + + +## Q4: "Why do the compare functions return ENOSYS?" + +This release is a project skeleton. The public API, packaging, tests, and +CI are present so implementation can land without restructuring the tree. +Comparison currently returns `ENOSYS` until the binary/text algorithms are +filled in. + + + diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..f88f129 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,143 @@ +# cmpfs - Installation and Use + +**cmpfs** is a classic-form C library, insofar as it has implementation files +in its **src** directory and header files in its **include/cmpfs** directory. +Thus, once "installed", one must simply include **cmpfs/cmpfs.h** and +compile-in or link-in the implementation. + +The **C API** has no non-standard dependencies. Building the project's tests +additionally requires **STLSoft** and **xTests**. + + +## Table of Contents + +- [CMake](#cmake) +- [Bundled](#bundled) + + +## CMake + +The primary choice for installation is by use of **CMake**. + +1. Obtain the latest distribution of **cmpfs**, from + https://github.com/synesissoftware/cmpfs/, e.g. + + ```bash + $ mkdir -p ~/open-source + $ cd ~/open-source + $ git clone https://github.com/synesissoftware/cmpfs/ + ``` + +2. Prepare the CMake configuration, via the **prepare_cmake.sh** script. + + For a minimal core-only install (no **STLSoft** / **xTests** required): + + ```bash + $ cd ~/open-source/cmpfs + $ ./prepare_cmake.sh --disable-testing --disable-examples -v + ``` + + For a full build including examples and tests, install **STLSoft** 1.11 + (and **xTests** for tests) via their own **CMake** scripts first, then: + + ```bash + $ cd ~/open-source/cmpfs + $ ./prepare_cmake.sh -v + ``` + + If **STLSoft** is available as a source tree rather than an installed + **CMake** package, pass its root with `--stlsoft-root-dir` / `-s`. + + (**Hint**: execute `$ ./prepare_cmake.sh --help` for more information.) + +3. Run a build of the generated **CMake**-derived build files via the + **build_cmake.sh** script, as in: + + ```bash + $ ./build_cmake.sh + ``` + + (**NOTE**: if you provide the flag `--run-make` (=== `-m`) in step 2 then + you do not need this step.) + +4. As a check (when testing was not disabled), execute the built unit-test + programs via **run_all_unit_tests.sh**, as in: + + ```bash + $ ./run_all_unit_tests.sh + ``` + +5. Install the library on the host, via `cmake`, as in: + + ```bash + $ sudo cmake --install ${SIS_CMAKE_BUILD_DIR:-./_build} --config Release + ``` + +6. Then to use the library, it is a simple matter as follows: + + 1. Assuming a simplest possible program to verify the installation: + + ```c + /* main.c */ + #include + + #include + #include + #include + + #ifndef ENOSYS + # define ENOSYS 78 + #endif + + int main(void) + { + int const r = cmpfs_compare_binary_files("a.bin", "b.bin", NULL); + + printf("status %d (ENOSYS=%d while skeleton)\n", r, ENOSYS); + + return EXIT_SUCCESS; + } + ``` + + 2. Compile your project against **cmpfs**: + + Due to the installation step (step 5 above) there is no requirement + for an explicit include directory: + + ```bash + $ cc -c main.c + ``` + + 3. Link your project against **cmpfs**: + + ```bash + $ cc main.o -lcmpfs + ``` + + 4. Test your project: + + ```bash + $ ./a.out + status 78 (ENOSYS=78 while skeleton) + $ + ``` + + Consumers that use **CMake** may instead depend on the installed package: + + ```cmake + find_package(cmpfs REQUIRED) + target_link_libraries(your_target PRIVATE cmpfs::core) + ``` + + +## Bundled + +**cmpfs** is small enough that it may be bundled into other projects. In +that case: + +* add **cmpfs**'s **include** directory to your project's include path; +* compile **src/compare.api.c** into your build (or link a previously built **libcmpfs**); and +* `#include `. + + + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..663ff33 --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +cmpfs - BSD 3-Clause License + +Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems +Copyright (c) 2010-2019, Matthew Wilson and Synesis Software + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..22fc3c7 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,16 @@ +# cmpfs - News + + +## Table of Contents + +- [News](#news) + + +## News + +| Date | News Item | +| ---------------- | -------------------------------------------------------------------------------- | +| 21st August 2026 | cmpfs 0.0.1-alpha1 | + + + diff --git a/README.md b/README.md index faddfea..a8b679f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,116 @@ -# cmpfs -Compare File-System entities, for C and C++ +# cmpfs + +**Com**pare **F**ile-**S**ystem entities, for **C** and **C++** + +![C](https://img.shields.io/badge/C-00599C?style=flat&logo=c&logoColor=white) +[![License](https://img.shields.io/badge/License-BSD_3--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +[![GitHub release](https://img.shields.io/github/v/release/synesissoftware/cmpfs.svg)](https://github.com/synesissoftware/cmpfs/releases/latest) +[![Last Commit](https://img.shields.io/github/last-commit/synesissoftware/cmpfs)](https://github.com/synesissoftware/cmpfs/commits/master) +[![CI](https://github.com/synesissoftware/cmpfs/actions/workflows/ci.yml/badge.svg)](https://github.com/synesissoftware/cmpfs/actions/workflows/ci.yml) + + +## Table of Contents + +- [Introduction](#introduction) + - [Dependencies](#dependencies) +- [Installation](#installation) +- [Components](#components) + - [C API / core library](#c-api--core-library) +- [Examples](#examples) +- [Project Information](#project-information) + - [Where to get help](#where-to-get-help) + - [Contribution guidelines](#contribution-guidelines) + - [Dependencies](#dependencies-1) + - [Development dependencies](#development-dependencies) + - [Related projects](#related-projects) + - [License](#license) + + +## Introduction + +**cmpfs** is a compiled **C** library for platform-independent comparison of file-system entities, including binary and text file contents. + +This tree is a **skeleton**: version macros, CMake packaging, helper scripts, CI, an example, and unit tests are in place. The comparison functions currently return `ENOSYS` until the algorithm is implemented. + +The core library has **no dependencies** on any other non-standard library. + + +### Dependencies + +| Component | Implemented in | Use in | Dependencies | +| ------------ | -------------- | ----------------------------- | ------------ | +| Core library | C | C — via **cmpfs/cmpfs.h** | C standard library | +| Examples (C) | C | — | — | +| Tests (C) | C | — | [STLSoft](https://github.com/synesissoftware/STLSoft/), [xTests](https://github.com/synesissoftware/xTests/) | + + +## Installation + +Detailed instructions — via **CMake**, via bundling — are provided in the accompanying [INSTALL.md](./INSTALL.md) file. + + +## Components + +### C API / core library + +```C +int +cmpfs_compare_binary_files( + char const* path1 +, char const* path2 +, unsigned flags +, cmpfs_comparison_result_t* result +); + +int +cmpfs_compare_text_files( + char const* path1 +, char const* path2 +, unsigned flags +, cmpfs_comparison_result_t* result +); +``` + +Text flags include `CMPFS_F_NONE`, `CMPFS_F_TRIM_LINES`, and `CMPFS_F_SKIP_BLANK_LINES`. Both functions currently return `ENOSYS`. + + +## Examples + +Examples are provided in the `examples` directory. + + +## Project Information + + +### Where to get help + +[GitHub Page](https://github.com/synesissoftware/cmpfs) + + +### Contribution guidelines + +Defect reports, feature requests, and pull requests are welcome on https://github.com/synesissoftware/cmpfs. + + +### Dependencies + +* none for the core library; + + +#### Development dependencies + +* [STLSoft](https://github.com/synesissoftware/STLSoft/); +* [xTests](https://github.com/synesissoftware/xTests/); + + +### Related projects + +* [cmpfs.Ruby](https://github.com/synesissoftware/cmpfs.Ruby); + + +### License + +**cmpfs** is released under the 3-clause BSD license. See [LICENSE](./LICENSE) for details. + + + diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..321bfe0 --- /dev/null +++ b/TODO.md @@ -0,0 +1,48 @@ +# cmpfs - TODO + + +## Functional improvements + + +### High + +* [ ] Implement **`cmpfs_compare_binary_files()`**; +* [ ] Implement **`cmpfs_compare_text_files()`** with **`CMPFS_TEXT_F_TRIM_LINES`** and **`CMPFS_TEXT_F_SKIP_BLANK_LINES`**; +* [ ] Provide **`cmpfs_compare_binary_streams()`** and **`cmpfs_compare_text_streams()`**; +* [ ] Document (and enforce in tests) that **`cmpfs_comparison_result_t::result`** is an ordering relation, and is meaningful **only** when the API function returns **0**; any other return value means the comparison did not produce a result; + + +### Medium + +* [ ] Add a text-only left-strip flag; +* [ ] Add a text-only right-strip flag; +* [ ] Add a text-only strip flag as the bit combination of left-strip and right-strip; +* [ ] Allow file/stream text encodings to be specified separately (per operand); +* [ ] Complete **`cmpfs_comparison_result_t`** field semantics (items read, difference offsets, line/column for text); + + +### Low + +* [ ] Recover behaviour from the historical Hautacam **cmpfs** C API and reconcile with **cmpfs.Ruby**; + + +### Enhancements + +* [ ] C++ façade over the C API; +* [ ] Asynchronous comparison of large files; +* [ ] Callback functions for binary chunk comparison; +* [ ] Callback functions for text line(s) comparison; + + +## Performance improvements + +* [ ] Multi-threaded comparison of large files; +* [ ] **`readv()`** / **`writev()`** compatibility for binary comparison (**`iovec[]`**); + + +## Packaging improvements + +* [ ] Defer rewriting helper `MSYSTEM` → `mingw32-make` / MinGW-generator detection until the **HELPER-SCRIPTS-C-CXX.md** contract is frozen (same defect class as other Synesis C/C++ helpers); + + + diff --git a/build_cmake.sh b/build_cmake.sh new file mode 100755 index 0000000..1f6b55d --- /dev/null +++ b/build_cmake.sh @@ -0,0 +1,125 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + +IgnoreRemainingFlagsAndOptions=0 +Targets=() + + +# ########################################################## +# functions + +function join_by { local IFS="$1"; shift; echo "$*"; } + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + if [ $IgnoreRemainingFlagsAndOptions -ne 0 ]; then + + Targets+=($1) + + shift + + continue + else + + if [ ! ${1:0:1} = '-' ]; then + + Targets+=($1) + + shift + + continue + fi + fi + + case $1 in + --) + + IgnoreRemainingFlagsAndOptions=1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Executes CMake-generated artefacts to (re)build project + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 1 +else + + cd $CMakeDir + + if [ ! -f "$CMakeDir/Makefile" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" + + cd ->/dev/null + + exit 1 + else + + if [ -z "$Targets" ]; then + + echo "Executing build (via command \`$MakeCmd\`)" + else + + echo "Executing build (via command \`$MakeCmd\`) with specific target(s) $(join_by , "${Targets[@]}")" + fi + + $MakeCmd ${Targets[*]} + status=$? + + cd ->/dev/null + + exit $status + fi +fi + + +# ############################## end of file ############################# # + diff --git a/clean_cmake.sh b/clean_cmake.sh new file mode 100755 index 0000000..87b42eb --- /dev/null +++ b/clean_cmake.sh @@ -0,0 +1,87 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Executes CMake-generated artefacts to clean project + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 1 +else + + cd $CMakeDir + + if [ ! -f "$CMakeDir/Makefile" ]; then + + >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" + + cd ->/dev/null + + exit 1 + else + + echo "Cleaning build (via command \`$MakeCmd clean\`)" + + $MakeCmd clean + status=$? + + cd ->/dev/null + + exit $status + fi +fi + + +# ############################## end of file ############################# # + diff --git a/cmake/BuildType.cmake b/cmake/BuildType.cmake new file mode 100644 index 0000000..e83cfbb --- /dev/null +++ b/cmake/BuildType.cmake @@ -0,0 +1,61 @@ + +# ######################################################################## # +# File: /cmake/BuildType.cmake +# +# Purpose: CMake module file (for BuildType) +# +# Created: 16th October 2019 +# Updated: 12th January 2024 +# +# ######################################################################## # + + +# Including this module sets the `CMAKE_BUILD_TYPE` value as follows: +# +# 1. If user specifies on the command line, then `CMAKE_BUILD_TYPE` already +# has a valid, so this is accepted; +# 2. If the top-level .git directory is specified, then "Debug" is used; +# otherwise +# 3. "Release" is used. +# +# Note: +# - `CMAKE_BUILD_TYPE` is the build (configuration) type; +# - `CMAKE_CONFIGURATION_TYPES` is, if specified, a list of valid +# configurations (see +# https://cmake.org/cmake/help/latest/variable/CMAKE_CONFIGURATION_TYPES.html); +# +# Example usage: +# +#[========[ + +# CMakeLists.txt + +include(BuildType) + +]========] + + +if(EXISTS "${CMAKE_SOURCE_DIR}/.git") + + set(default_build_type "Debug") +else() + + set(default_build_type "Release") +endif() + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + + set(CACHE CMAKE_BUILD_TYPE "${default_build_type}" + STRING "Choose the type of build." FORCE + ) + + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Release" "MinSizeRel" "RelWithDebInfo" + ) +endif() + +# ############################## end of file ############################# # + diff --git a/cmake/LanguageFullVersion.cmake b/cmake/LanguageFullVersion.cmake new file mode 100644 index 0000000..c0882b4 --- /dev/null +++ b/cmake/LanguageFullVersion.cmake @@ -0,0 +1,63 @@ + +# ################################################ +# X_CMAKE_C_FULLSTANDARD + +set(X_CMAKE_C_FULLSTANDARD 0) + +if(FALSE) +elseif(CMAKE_C_STANDARD EQUAL 99) + + set(X_CMAKE_C_FULLSTANDARD 1999) +elseif(CMAKE_C_STANDARD EQUAL 90) + + set(X_CMAKE_C_FULLSTANDARD 1990) +elseif(CMAKE_C_STANDARD GREATER_EQUAL 23) + + set(X_CMAKE_C_FULLSTANDARD 2023) +elseif(CMAKE_C_STANDARD GREATER_EQUAL 17) + + set(X_CMAKE_C_FULLSTANDARD 2017) +elseif(CMAKE_C_STANDARD GREATER_EQUAL 11) + + set(X_CMAKE_C_FULLSTANDARD 2011) +else() + + message(FATAL_ERROR "mechanism for discriminating X_CMAKE_C_FULLSTANDARD has failed") +endif() + + +# ################################################ +# X_CMAKE_CXX_FULLSTANDARD + +set(X_CMAKE_CXX_FULLSTANDARD 0) + +if(FALSE) +elseif(CMAKE_CXX_STANDARD EQUAL 98) + + set(X_CMAKE_CXX_FULLSTANDARD 1998) +elseif(CMAKE_CXX_STANDARD GREATER_EQUAL 26) + + set(X_CMAKE_CXX_FULLSTANDARD 2026) +elseif(CMAKE_CXX_STANDARD GREATER_EQUAL 23) + + set(X_CMAKE_CXX_FULLSTANDARD 2023) +elseif(CMAKE_CXX_STANDARD GREATER_EQUAL 20) + + set(X_CMAKE_CXX_FULLSTANDARD 2020) +elseif(CMAKE_CXX_STANDARD GREATER_EQUAL 17) + + set(X_CMAKE_CXX_FULLSTANDARD 2017) +elseif(CMAKE_CXX_STANDARD GREATER_EQUAL 14) + + set(X_CMAKE_CXX_FULLSTANDARD 2014) +elseif(CMAKE_CXX_STANDARD GREATER_EQUAL 11) + + set(X_CMAKE_CXX_FULLSTANDARD 2011) +else() + + message(FATAL_ERROR "mechanism for discriminating X_CMAKE_CXX_FULLSTANDARD has failed") +endif() + + +# ############################## end of file ############################# # + diff --git a/cmake/TargetMacros.cmake b/cmake/TargetMacros.cmake new file mode 100644 index 0000000..f66ca8b --- /dev/null +++ b/cmake/TargetMacros.cmake @@ -0,0 +1,104 @@ + +function(define_automated_test_program program_name entry_point_source_name) + + add_executable(${program_name} + ${entry_point_source_name} + ) + + target_link_libraries(${program_name} + PRIVATE + core + $<$:STLSoft::STLSoft> + $,xTests::xTests.core,xTests::core> + ) + + set_target_properties(${program_name} PROPERTIES + LINKER_LANGUAGE CXX + ) + + set(X_GCC_CUSTOM_WARNINGS_ "") + + if(X_GCC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED) + foreach(warning ${X_GCC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED}) + + list(APPEND X_GCC_CUSTOM_WARNINGS_ "-Wno-${warning}") + endforeach() + endif() + + set(X_MSVC_CUSTOM_WARNINGS_ "") + + if(X_MSVC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED) + foreach(warning ${X_MSVC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED}) + + list(APPEND X_MSVC_CUSTOM_WARNINGS_ "/wd${warning}") + endforeach() + endif() + + target_compile_options(${program_name} PRIVATE + $<$,$,$>: + -Werror -Wall -Wextra -pedantic + + ${GCC_WARN_NO_cxx11_long_long} + ${X_GCC_CUSTOM_WARNINGS_} + > + $<$,$>: + -Wno-unused-lambda-capture + > + $<$: + /WX /W4 + + ${X_MSVC_CUSTOM_WARNINGS_} + > + ) +endfunction(define_automated_test_program) + + +function(define_example_program program_name entry_point_source_name) + + add_executable(${program_name} + ${entry_point_source_name} + ) + + target_link_libraries(${program_name} + PRIVATE + core + ) + + set(X_GCC_CUSTOM_WARNINGS_ "") + + if(X_GCC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED) + foreach(warning ${X_GCC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED}) + + list(APPEND X_GCC_CUSTOM_WARNINGS_ "-Wno-${warning}") + endforeach() + endif() + + set(X_MSVC_CUSTOM_WARNINGS_ "") + + if(X_MSVC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED) + foreach(warning ${X_MSVC_CUSTOM_WARNINGS_TO_BE_SUPPRESSED}) + + list(APPEND X_MSVC_CUSTOM_WARNINGS_ "/wd${warning}") + endforeach() + endif() + + target_compile_options(${program_name} PRIVATE + $<$,$,$>: + -Werror -Wall -Wextra -pedantic + + ${GCC_WARN_NO_cxx11_long_long} + ${X_GCC_CUSTOM_WARNINGS_} + > + $<$,$>: + -Wno-unused-lambda-capture + > + $<$: + /WX /W4 + + ${X_MSVC_CUSTOM_WARNINGS_} + > + ) +endfunction(define_example_program) + + +# ############################## end of file ############################# # diff --git a/cmake/cmpfs-config.cmake.in b/cmake/cmpfs-config.cmake.in new file mode 100644 index 0000000..479320d --- /dev/null +++ b/cmake/cmpfs-config.cmake.in @@ -0,0 +1,2 @@ +@PACKAGE_INIT@ +include("${CMAKE_CURRENT_LIST_DIR}/@EXPORT_NAME@-targets.cmake") diff --git a/ctest_cmake.sh b/ctest_cmake.sh new file mode 100755 index 0000000..24c2172 --- /dev/null +++ b/ctest_cmake.sh @@ -0,0 +1,108 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") + +CMakeVerbose= +RunMake=1 + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --no-make|-M) + + RunMake=0 + ;; + --verbose|-V) + + CMakeVerbose=--verbose + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs CMake's CTest test program(s) + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -M + --no-make + does not execute CMake and make before running tests + + -V + --verbose + verbose test output + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +status=0 + +if [ $RunMake -ne 0 ]; then + + echo "Executing build for ${ProjectName} (via command \`$MakeCmd\`) and then running all component and unit test programs" + + mkdir -p $CMakeDir || exit 1 + + cd $CMakeDir + + $MakeCmd + status=$? + + cd ->/dev/null +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + + >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + fi +fi + +if [ $status -eq 0 ]; then + + echo "Running CMake tests" + + ctest --test-dir $CMakeDir $CMakeVerbose + status=$? +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..b7bb9f1 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,33 @@ + +include_directories(${CMAKE_SOURCE_DIR}/include) + +if(_BUILD_AS_UNIX) + + add_definitions(-DUNIX) + add_definitions(-Dunix) +endif(_BUILD_AS_UNIX) + +if(_BUILD_AS_WIN32) + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + + message (STATUS "Compiling for 64-bit Windows") + + add_definitions(-DWIN64) + else() + + message (STATUS "Compiling for 32-bit Windows") + + add_definitions(-DWIN32) + endif() +endif(_BUILD_AS_WIN32) + +if((MSVC) AND (MSVC_VERSION GREATER_EQUAL 1914)) + + add_compile_options("/Zc:__cplusplus") +endif() + +add_subdirectory(c) + + +# ############################## end of file ############################# # diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt new file mode 100644 index 0000000..49cb8cd --- /dev/null +++ b/examples/c/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(example.c.1) + + +# ############################## end of file ############################# # diff --git a/examples/c/example.c.1/CMakeLists.txt b/examples/c/example.c.1/CMakeLists.txt new file mode 100644 index 0000000..d0668ad --- /dev/null +++ b/examples/c/example.c.1/CMakeLists.txt @@ -0,0 +1 @@ +define_example_program(example.c.1 example.c.1.c) diff --git a/examples/c/example.c.1/example.c.1.c b/examples/c/example.c.1/example.c.1.c new file mode 100644 index 0000000..3f0811b --- /dev/null +++ b/examples/c/example.c.1/example.c.1.c @@ -0,0 +1,60 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: example.c.1.c + * + * Purpose: Example of cmpfs: report library version and the skeleton + * compare-API status. + * + * Created: 21st August 2026 + * Updated: 21st August 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include +#include +#include +#include + +#ifndef ENOSYS +# define ENOSYS 78 +#endif /* !ENOSYS */ + + +int +main(void) +{ + cmpfs_comparison_result_t result; + int r; + + printf( + "cmpfs %d.%d.%d (composite 0x%08x)\n" + , CMPFS_VER_MAJOR + , CMPFS_VER_MINOR + , CMPFS_VER_PATCH + , CMPFS_VER + ); + + r = cmpfs_compare_binary_files("left.bin", "right.bin", &result); + + if (ENOSYS == r) + { + puts("cmpfs_compare_binary_files() is a skeleton stub (ENOSYS)"); + + return EXIT_SUCCESS; + } + + fprintf( + stderr + , "unexpected cmpfs_compare_binary_files() status : %s (%d)\n" + , strerror(r) + , r + ); + + return EXIT_FAILURE; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/include/cmpfs/cmpfs.h b/include/cmpfs/cmpfs.h new file mode 100644 index 0000000..27c1dd5 --- /dev/null +++ b/include/cmpfs/cmpfs.h @@ -0,0 +1,241 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: cmpfs/cmpfs.h + * + * Purpose: Main C header for the cmpfs library. + * + * Created: ... 2010 ... + * Updated: 21st August 2026 + * + * Home: https://github.com/synesissoftware/cmpfs + * + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Software nor the + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/** \file cmpfs/cmpfs.h + * [C, C++] Main header for the \ref group__library__cmpfs "cmpfs" + * library. + */ + +#ifndef CMPFS_INCL_CMPFS_H_CMPFS +#define CMPFS_INCL_CMPFS_H_CMPFS + +/* ///////////////////////////////////////////////////////////////////////// + * version information + */ + +#ifndef CMPFS_DOCUMENTATION_SKIP_SECTION +# define CMPFS_VER_CMPFS_H_CMPFS_MAJOR 1 +# define CMPFS_VER_CMPFS_H_CMPFS_MINOR 1 +# define CMPFS_VER_CMPFS_H_CMPFS_REVISION 1 +# define CMPFS_VER_CMPFS_H_CMPFS_EDIT 12 +#endif /* !CMPFS_DOCUMENTATION_SKIP_SECTION */ + +/** \def CMPFS_VER_MAJOR + * The major version number of cmpfs + */ + +/** \def CMPFS_VER_MINOR + * The minor version number of cmpfs + */ + +/** \def CMPFS_VER_PATCH + * The patch version number of cmpfs + */ + +/** \def CMPFS_VER_AB + * The alpha/beta designator of cmpfs, or 0xFF for a non-prerelease + */ + +/** \def CMPFS_VER + * The current composite version number of cmpfs + */ + +#define CMPFS_VER_MAJOR 1 +#define CMPFS_VER_MINOR 1 +#define CMPFS_VER_PATCH 0 +#define CMPFS_VER_AB 0x41 + +#define CMPFS_VER \ + (0\ + | ( CMPFS_VER_MAJOR << 24 ) \ + | ( CMPFS_VER_MINOR << 16 ) \ + | ( CMPFS_VER_PATCH << 8 ) \ + | ( CMPFS_VER_AB << 0 ) \ + ) + +#ifndef CMPFS_DOCUMENTATION_SKIP_SECTION +# define CMPFS_VER_REVISION CMPFS_VER_PATCH +#endif /* !CMPFS_DOCUMENTATION_SKIP_SECTION */ + + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include +#include + + +/* ///////////////////////////////////////////////////////////////////////// + * language + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* ///////////////////////////////////////////////////////////////////////// + * flags + */ + +/** No text-comparison flags. */ +#define CMPFS_F_NONE (0) + +/** Trim leading and trailing whitespace from each line (text compare). */ +#define CMPFS_F_TRIM_LINES (0x0001) + +/** Skip blank lines (text compare). */ +#define CMPFS_F_SKIP_BLANK_LINES (0x0002) + + +/* ///////////////////////////////////////////////////////////////////////// + * types + */ + +/** Result of a file or stream comparison. + * + * \note This structure is a skeleton placeholder. Field semantics will be + * completed when comparison is implemented. + */ +struct cmpfs_comparison_result_t +{ + int equal; /*!< Non-zero if the compared entities are equal. */ + size_t offset_1; /*!< First differing offset in the first entity. */ + size_t offset_2; /*!< First differing offset in the second entity. */ +}; +#ifndef __cplusplus +typedef struct cmpfs_comparison_result_t cmpfs_comparison_result_t; +#endif /* !__cplusplus */ + + +/* ///////////////////////////////////////////////////////////////////////// + * API + */ + +/** Compares two files as binary sequences. + * + * \param path1 Path of the first file. May not be NULL. + * \param path2 Path of the second file. May not be NULL. + * \param flags Combination of CMPFS_F_* flags. + * \param result Optional result structure. May be NULL. + * + * \retval 0 The comparison completed successfully (see \c result). + * \retval !0 A C failure code, suitable for strerror(). + * + * \note This function is a skeleton stub and currently returns + * ENOSYS. + * + * \pre (NULL != path1) + * \pre (NULL != path2) + */ +int +cmpfs_compare_binary_files( + char const* path1 +, char const* path2 +, unsigned flags +, cmpfs_comparison_result_t* result +); + +int +cmpfs_compare_binary_streams( + FILE* stm1 +, FILE* stm2 +, unsigned flags +, cmpfs_comparison_result_t* result +); + +/** Compares two files as text. + * + * \param path1 Path of the first file. May not be NULL. + * \param path2 Path of the second file. May not be NULL. + * \param flags Combination of CMPFS_F_* flags. + * \param result Optional result structure. May be NULL. + * + * \retval 0 The comparison completed successfully (see \c result). + * \retval !0 A C failure code, suitable for strerror(). + * + * \note This function is a skeleton stub and currently returns + * ENOSYS. + * + * \pre (NULL != path1) + * \pre (NULL != path2) + */ +int +cmpfs_compare_text_files( + char const* path1 +, char const* path2 +, unsigned flags +, cmpfs_comparison_result_t* result +); + +int +cmpfs_compare_text_streams( + FILE* stm1 +, FILE* stm2 +, unsigned flags +, cmpfs_comparison_result_t* result +); + + +/* ///////////////////////////////////////////////////////////////////////// + * language + */ + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +/* ///////////////////////////////////////////////////////////////////////// + * inclusion control + */ + +#ifdef STLSOFT_CF_PRAGMA_ONCE_SUPPORT +# pragma once +#endif /* STLSOFT_CF_PRAGMA_ONCE_SUPPORT */ + +#endif /* !CMPFS_INCL_CMPFS_H_CMPFS */ + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/prepare_cmake.sh b/prepare_cmake.sh new file mode 100755 index 0000000..cd236f2 --- /dev/null +++ b/prepare_cmake.sh @@ -0,0 +1,193 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + +Configuration=Release +ExamplesDisabled=0 +MSVC_MT=0 +MinGW=0 +RunMake=0 +STLSoftDirGiven= +TestingDisabled=0 +VerboseMakefile=0 + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --cmake-verbose-makefile|-v) + + VerboseMakefile=1 + ;; + --debug-configuration|-d) + + Configuration=Debug + ;; + --disable-examples|-E) + + ExamplesDisabled=1 + ;; + --disable-testing|-T) + + TestingDisabled=1 + ;; + --mingw) + + MinGW=1 + ;; + --msvc-mt) + + MSVC_MT=1 + ;; + --run-make|-m) + + RunMake=1 + ;; + --stlsoft-root-dir|-s) + + shift + STLSoftDirGiven=$1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Creates/reinitialises the CMake build script(s) for ${ProjectName} + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -v + --cmake-verbose-makefile + configures CMake to run verbosely (by setting CMAKE_VERBOSE_MAKEFILE + to be ON) + + -d + --debug-configuration + use Debug configuration (by setting CMAKE_BUILD_TYPE=Debug). Default + is to use Release + + -E + --disable-examples + disables building of examples (by setting BUILD_EXAMPLES=OFF) + + -T + --disable-testing + disables building of tests (by setting BUILD_TESTING=OFF). Unless + testing is disabled the STLSoft and xTests libraries will be + required to be available to CMake + + --mingw + uses explicitly the "MinGW Makefiles" generator + + --msvc-mt + when using Visual C++ (MSVC), the static runtime library will be + selected; the default is the dynamic runtime library + + -m + --run-make + executes make after a successful running of CMake + + -s + --stlsoft-root-dir + specifies the STLSoft root-directory, which will be passed to CMake + as the variable STLSOFT, and which will override the environment + variable STLSOFT (if present) + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +mkdir -p $CMakeDir || exit 1 + +cd $CMakeDir + +echo "Executing CMake (in ${CMakeDir})" + +if [ $ExamplesDisabled -eq 0 ]; then CMakeBuildExamplesFlag="ON" ; else CMakeBuildExamplesFlag="OFF" ; fi +if [ $MSVC_MT -eq 0 ]; then CMakeMsvcMtFlag="OFF" ; else CMakeMsvcMtFlag="ON" ; fi +if [ -z $STLSoftDirGiven ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi +if [ $TestingDisabled -eq 0 ]; then CMakeBuildTestingFlag="ON" ; else CMakeBuildTestingFlag="OFF" ; fi +if [ $VerboseMakefile -eq 0 ]; then CMakeVerboseMakefileFlag="OFF" ; else CMakeVerboseMakefileFlag="ON" ; fi + +if [ $MinGW -ne 0 ]; then + + cmake \ + $CMakeSTLSoftVariable \ + -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -G "MinGW Makefiles" \ + -S $Dir \ + -B $CMakeDir \ + || (cd ->/dev/null ; exit 1) +else + + cmake \ + $CMakeSTLSoftVariable \ + -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ + -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ + -S $Dir \ + -B $CMakeDir \ + || (cd ->/dev/null ; exit 1) +fi + +status=0 + +if [ $RunMake -ne 0 ]; then + + echo "Executing build (via command \`$MakeCmd\`)" + + $MakeCmd + status=$? +fi + +cd ->/dev/null + +if [ $VerboseMakefile -ne 0 ]; then + + echo -e "contents of $CMakeDir:" + ls -al $CMakeDir +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/remove_cmake_artefacts.sh b/remove_cmake_artefacts.sh new file mode 100755 index 0000000..076a84a --- /dev/null +++ b/remove_cmake_artefacts.sh @@ -0,0 +1,153 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} + +Directories=( + CMakeFiles + Testing + cmake + examples + projects + src + test +) +Files=( + CMakeCache.txt + CTestTestfile.cmake + DartConfiguration.tcl + Makefile + cmake_install.cmake + install_manifest.txt +) + + +# ########################################################## +# operating environment detection + +OsName="$(uname -s)" +case "${OsName}" in + CYGWIN*|MINGW*|MSYS_NT*) + + Directories+=( + ARM64 + Win32 + x64 + ) + Files+=( + "*.filters" + "*.sln" + "*.vcxproj" + ) + ;; + *) + + ;; +esac + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Removes all known CMake artefacts + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +if [ ! -d "$CMakeDir" ]; then + + echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + + exit 0 +else + + echo "Removing all cmake artefacts in '$CMakeDir'" + + num_dirs_removed=0 + num_files_removed=0 + + for d in ${Directories[@]} + do + + fq_dir_path="$CMakeDir/$d" + + [ -d "$fq_dir_path" ] || continue + + echo "removing directory '$d'" + + rm -dfr "$fq_dir_path" + + num_dirs_removed=$((num_dirs_removed+1)) + done + + cd "$CMakeDir" + + for f in ${Files[@]} + do + + for fq_file_path in $f + do + + [ -f "$fq_file_path" ] || continue + + echo "removing file '$fq_file_path'" + + rm -f "$fq_file_path" + + num_files_removed=$((num_files_removed+1)) + done + done + + cd ->/dev/null + + if [ 0 -eq $num_dirs_removed ] && [ 0 -eq $num_files_removed ]; then + + echo "nothing to do" + else + + echo "removed $num_dirs_removed directories and $num_files_removed files" + fi +fi + + +# ############################## end of file ############################# # + diff --git a/run_all_examples.sh b/run_all_examples.sh new file mode 100755 index 0000000..bb7ef70 --- /dev/null +++ b/run_all_examples.sh @@ -0,0 +1,132 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + +ListOnly=0 +RunMake=1 + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all example programs + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute CMake and make before running tests + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +status=0 + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo "Executing build (via command \`$MakeCmd\`) and then running all example programs" + + mkdir -p $CMakeDir || exit 1 + + cd $CMakeDir + + $MakeCmd + status=$? + + cd ->/dev/null + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + + >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo "Listing all example programs" + else + + echo "Running all example programs" + fi + + for f in $(find $CMakeDir -type f '(' -name 'example.c.*' -o -name 'example.cpp.*' ')' -exec test -x {} \; -print) + do + + if [ $ListOnly -ne 0 ]; then + + echo "would execute $f:" + + continue + fi + + echo + echo "executing $f:" + + # NOTE: we do not break on fail, because, this being a unit-testing library, the scratch-tests actually fail + $f + done +fi + +exit $status + + +# ############################## end of file ############################# # + diff --git a/run_all_scratch_tests.sh b/run_all_scratch_tests.sh new file mode 100755 index 0000000..25aa4c1 --- /dev/null +++ b/run_all_scratch_tests.sh @@ -0,0 +1,137 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + +ListOnly=0 +RunMake=1 + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) scratch-test programs + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute CMake and make before running tests + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +status=0 + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo "Executing build (via command \`$MakeCmd\`) and then running all scratch test programs" + + mkdir -p $CMakeDir || exit 1 + + cd $CMakeDir + + $MakeCmd + status=$? + + cd ->/dev/null + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + + >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo "Listing all scratch (and performance) test programs" + else + + echo "Running all scratch (and performance) test programs" + fi + + for f in $(find $CMakeDir -type f '(' -name 'test_scratch*' -o -name 'test.scratch.*' -o -name 'test_performance*' -o -name 'test.performance.*' ')' -exec test -x {} \; -print) + do + + if [ $ListOnly -ne 0 ]; then + + echo "would execute $f:" + + continue + fi + + echo + echo "executing $f:" + + if $f; then + + : + else + + status=$? + fi + done +fi + +exit $status + + +# ############################## end of file ############################# # + diff --git a/run_all_unit_tests.cmd b/run_all_unit_tests.cmd new file mode 100755 index 0000000..b68c97e --- /dev/null +++ b/run_all_unit_tests.cmd @@ -0,0 +1,188 @@ +@echo off + +SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET "CMAKE_DIR=%SIS_CMAKE_BUILD_DIR%" +) ELSE ( + + SET "CMAKE_DIR=%SCRIPT_DIRECTORY%_build" +) + +SET ListOnly=0 +SET Verbose=0 +SET UnitOnly=0 +SET ComponentOnly=0 +SET status=0 + +FOR %%a IN (%*) DO ( + IF /I {--help}=={%%a} ( + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) unit-test and/or component-test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + -l ^ + + --list-only ^ + + lists the target programs but does not execute them ^ + +^ + + -M ^ + + --no-make ^ + + accepted for parity with the .sh script ^(build is not invoked^) ^ + +^ + + --unit-only ^ + + runs only unit-test programs ^(test.unit.* / test_unit*^) ^ + +^ + + --component-only ^ + + runs only component-test programs ^(test.component.* / test_component*^) ^ + +^ + + -v ^ + + --verbose ^ + + lists each test program before executing it ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {-l}=={%%a} ( + SET ListOnly=1 + ) ELSE IF /I {--list-only}=={%%a} ( + SET ListOnly=1 + ) ELSE IF /I {-M}=={%%a} ( + REM no-op: this .cmd never invokes the build + ) ELSE IF /I {--no-make}=={%%a} ( + REM no-op: this .cmd never invokes the build + ) ELSE IF /I {--unit-only}=={%%a} ( + SET UnitOnly=1 + ) ELSE IF /I {--component-only}=={%%a} ( + SET ComponentOnly=1 + ) ELSE IF /I {-v}=={%%a} ( + SET Verbose=1 + ) ELSE IF /I {--verbose}=={%%a} ( + SET Verbose=1 + ) ELSE ( + ECHO %SCRIPT_PATH_DOC%: unrecognised argument '%%a'; use --help for usage 1>&2 + + EXIT /B 1 + ) +) + +IF !UnitOnly! EQU 1 IF !ComponentOnly! EQU 1 ( + + ECHO %SCRIPT_PATH_DOC%: --unit-only and --component-only are mutually exclusive 1>&2 + + EXIT /B 1 +) + +IF NOT EXIST "%CMAKE_DIR%" ( + + ECHO %SCRIPT_PATH_DOC%: CMake build directory '%CMAKE_DIR%' does not exist 1>&2 + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +IF !UnitOnly! EQU 1 ( + + SET "TestKindDescription=unit test" +) ELSE IF !ComponentOnly! EQU 1 ( + + SET "TestKindDescription=component test" +) ELSE ( + + SET "TestKindDescription=component and unit test" +) + +IF !ListOnly! EQU 1 ( + + ECHO Listing all !ProjectName! !TestKindDescription! programs +) ELSE ( + + ECHO Running all !ProjectName! !TestKindDescription! programs +) + +IF !UnitOnly! EQU 1 ( + + SET "FindPattern=test\.unit\..*\.exe$" +) ELSE IF !ComponentOnly! EQU 1 ( + + SET "FindPattern=test\.component\..*\.exe$" +) ELSE ( + + SET "FindPattern=test\.unit\..*\.exe$ test\.component\..*\.exe$" +) + +FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%\*.exe" 2^>NUL ^| FINDSTR /I /R "!FindPattern!"`) DO ( + IF !ListOnly! EQU 1 ( + + ECHO would execute %%f: + ) ELSE ( + + IF !Verbose! EQU 1 ( + + ECHO executing %%f: + ) + + "%%f" + IF ERRORLEVEL 1 ( + + SET status=1 + + GOTO :done + ) + ) +) + +:done +EXIT /B !status! diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh new file mode 100755 index 0000000..22efd84 --- /dev/null +++ b/run_all_unit_tests.sh @@ -0,0 +1,200 @@ +#! /bin/bash + +ScriptPath=$0 +Dir=$(cd $(dirname "$ScriptPath"); pwd) +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +Basename=$(basename "$ScriptPath") +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make +MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} + +ListOnly=0 +RunMake=1 +UnitOnly=0 +ComponentOnly=0 +Verbosity=${XTESTS_VERBOSITY:-${TEST_VERBOSITY:-3}} + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --unit-only) + + UnitOnly=1 + ;; + --component-only) + + ComponentOnly=1 + ;; + --verbosity) + + shift + Verbosity=$1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) unit-test and/or component-test programs + +$ScriptPath [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute CMake and make before running tests + + --unit-only + runs only unit-test programs (test.unit.* / test_unit*) + + --component-only + runs only component-test programs (test.component.* / test_component*) + + --verbosity + specifies an explicit verbosity for the unit-test(s) + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + +if [ $UnitOnly -ne 0 ] && [ $ComponentOnly -ne 0 ]; then + + >&2 echo "$ScriptPath: --unit-only and --component-only are mutually exclusive" + + exit 1 +fi + + +# ########################################################## +# main() + +status=0 + +if [ $UnitOnly -ne 0 ]; then + + TestKindDescription='unit test' +elif [ $ComponentOnly -ne 0 ]; then + + TestKindDescription='component test' +else + + TestKindDescription='component and unit test' +fi + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo "Executing build (via command \`$MakeCmd\`) and then running all ${TestKindDescription} programs" + + mkdir -p $CMakeDir || exit 1 + + cd $CMakeDir + + $MakeCmd + status=$? + + cd ->/dev/null + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + + >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + + exit 1 + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo "Listing all ${TestKindDescription} programs" + else + + echo "Running all ${TestKindDescription} programs" + fi + + if [ $UnitOnly -ne 0 ]; then + + find_name_expr=( \( -name 'test_unit*' -o -name 'test.unit.*' \) ) + elif [ $ComponentOnly -ne 0 ]; then + + find_name_expr=( \( -name 'test_component*' -o -name 'test.component.*' \) ) + else + + find_name_expr=( \( -name 'test_unit*' -o -name 'test.unit.*' -o -name 'test_component*' -o -name 'test.component.*' \) ) + fi + + for f in $(find "$CMakeDir" -type f "${find_name_expr[@]}" -exec test -x {} \; -print | sort) + do + + if [ $ListOnly -ne 0 ]; then + + echo "would execute $f:" + + continue + fi + + if [ $Verbosity -ge 3 ]; then + + echo + fi + if [ $Verbosity -ge 2 ]; then + + echo "executing $f:" + fi + + if $f --verbosity=$Verbosity; then + + : + else + + status=$? + + break 1 + fi + done +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..cece598 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,89 @@ + +# ######################################################################## # +# File: /src/CMakeLists.txt +# +# Purpose: CMake lists file for cmpfs core library +# +# Created: 21st August 2026 +# Updated: 21st August 2026 +# +# ######################################################################## # + + +if(_BUILD_AS_UNIX) + + add_definitions(-DUNIX) + add_definitions(-Dunix) +endif(_BUILD_AS_UNIX) + +if(_BUILD_AS_WIN32) + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + + message (STATUS "Compiling for 64-bit Windows") + + add_definitions(-DWIN64) + else() + + message (STATUS "Compiling for 32-bit Windows") + + add_definitions(-DWIN32) + endif() +endif(_BUILD_AS_WIN32) + +if(MSVC) + if(MSVC_VERSION GREATER_EQUAL 1914) + + add_compile_options("/Zc:__cplusplus") + endif() +endif(MSVC) + + +set(CORE_SRCS + compare.api.c +) + +add_library(core + ${CORE_SRCS} +) + +set_target_properties(core PROPERTIES + OUTPUT_NAME "cmpfs" +) + +target_include_directories(core + PUBLIC + $ + $ +) + +target_compile_options(core + PRIVATE + $<$,$,$>: + -Werror -Wall -Wextra -pedantic + > + $<$: + /WX /W4 + > +) + + +# ########################################################## +# install + +install(TARGETS core + EXPORT project-targets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +install( + DIRECTORY ${CMAKE_SOURCE_DIR}/include/cmpfs/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cmpfs/ + FILES_MATCHING + PATTERN "*.h*" +) + + +# ############################## end of file ############################# # diff --git a/src/compare.api.c b/src/compare.api.c new file mode 100644 index 0000000..27f6aa5 --- /dev/null +++ b/src/compare.api.c @@ -0,0 +1,107 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: compare.api.c + * + * Purpose: Skeleton implementation of the cmpfs comparison API. + * + * Created: ... 2010 ... + * Updated: 21st August 2026 + * + * Home: https://github.com/synesissoftware/cmpfs + * + * Copyright (c) 2019-2026, Matthew Wilson and Synesis Information Systems + * Copyright (c) 2010-2019, Matthew Wilson and Synesis Software + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * - Neither the name(s) of Matthew Wilson and Synesis Software nor the + * names of any contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * ////////////////////////////////////////////////////////////////////// */ + + +/* ///////////////////////////////////////////////////////////////////////// + * includes + */ + +#include + +#include +#include +#include + +#ifndef ENOSYS +# define ENOSYS 78 +#endif /* !ENOSYS */ + +/* ///////////////////////////////////////////////////////////////////////// + * API + */ + +int +cmpfs_compare_binary_files( + char const* path1 +, char const* path2 +, unsigned flags +, cmpfs_comparison_result_t* result +) +{ + assert(NULL != path1); + assert(NULL != path2); + + ((void)path1); + ((void)path2); + + if (NULL != result) + { + memset(result, 0, sizeof(*result)); + } + + return ENOSYS; +} + +int +cmpfs_compare_text_files( + char const* path1 +, char const* path2 +, unsigned flags +, cmpfs_comparison_result_t* result +) +{ + assert(NULL != path1); + assert(NULL != path2); + + ((void)path1); + ((void)path2); + ((void)flags); + + if (NULL != result) + { + memset(result, 0, sizeof(*result)); + } + + return ENOSYS; +} + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..88529c5 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,34 @@ + +include_directories(${CMAKE_SOURCE_DIR}/include) + +if(_BUILD_AS_UNIX) + + add_definitions(-DUNIX) + add_definitions(-Dunix) +endif(_BUILD_AS_UNIX) + +if(_BUILD_AS_WIN32) + + if(CMAKE_SIZEOF_VOID_P EQUAL 8) + + message (STATUS "Compiling for 64-bit Windows") + + add_definitions(-DWIN64) + else() + + message (STATUS "Compiling for 32-bit Windows") + + add_definitions(-DWIN32) + endif() +endif(_BUILD_AS_WIN32) + +if((MSVC) AND (MSVC_VERSION GREATER_EQUAL 1914)) + + add_compile_options("/Zc:__cplusplus") +endif() + +add_subdirectory(unit) +add_subdirectory(scratch) + + +# ############################## end of file ############################# # diff --git a/test/scratch/CMakeLists.txt b/test/scratch/CMakeLists.txt new file mode 100644 index 0000000..17608a6 --- /dev/null +++ b/test/scratch/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(test.scratch.compare) + + +# ############################## end of file ############################# # diff --git a/test/scratch/test.scratch.compare/CMakeLists.txt b/test/scratch/test.scratch.compare/CMakeLists.txt new file mode 100644 index 0000000..8757b1b --- /dev/null +++ b/test/scratch/test.scratch.compare/CMakeLists.txt @@ -0,0 +1 @@ +define_example_program(test.scratch.compare main.c) diff --git a/test/scratch/test.scratch.compare/main.c b/test/scratch/test.scratch.compare/main.c new file mode 100644 index 0000000..6dac726 --- /dev/null +++ b/test/scratch/test.scratch.compare/main.c @@ -0,0 +1,36 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: main.c + * + * Purpose: Scratch test for cmpfs. + * + * Created: 21st August 2026 + * Updated: 21st August 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include +#include + + +int +main(void) +{ + cmpfs_comparison_result_t result; + int const r = cmpfs_compare_text_files( + "left.txt" + , "right.txt" + , CMPFS_F_NONE + , &result + ); + + printf("cmpfs_compare_text_files() -> %d\n", r); + + return EXIT_SUCCESS; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt new file mode 100644 index 0000000..ad05ceb --- /dev/null +++ b/test/unit/CMakeLists.txt @@ -0,0 +1,5 @@ +add_subdirectory(test.unit.compare.api) +add_subdirectory(test.unit.version) + + +# ############################## end of file ############################# # diff --git a/test/unit/test.unit.compare.api/CMakeLists.txt b/test/unit/test.unit.compare.api/CMakeLists.txt new file mode 100644 index 0000000..74cb7e8 --- /dev/null +++ b/test/unit/test.unit.compare.api/CMakeLists.txt @@ -0,0 +1 @@ +define_automated_test_program(test.unit.compare.api test.unit.compare.api.c) diff --git a/test/unit/test.unit.compare.api/test.unit.compare.api.c b/test/unit/test.unit.compare.api/test.unit.compare.api.c new file mode 100644 index 0000000..c7c0654 --- /dev/null +++ b/test/unit/test.unit.compare.api/test.unit.compare.api.c @@ -0,0 +1,84 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.unit.compare.api.c + * + * Purpose: Unit tests for the cmpfs skeleton comparison API. + * + * Created: 21st August 2026 + * Updated: 21st August 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include + +#include +#include + +#ifndef ENOSYS +# define ENOSYS 78 +#endif /* !ENOSYS */ + + +static void +test_compare_binary_files_is_stub(void) +{ + cmpfs_comparison_result_t result; + int const r = cmpfs_compare_binary_files("a", "b", &result); + + XTESTS_TEST_INTEGER_EQUAL(ENOSYS, r); + XTESTS_TEST_INTEGER_EQUAL(0, result.equal); + XTESTS_TEST_INTEGER_EQUAL(0, (int)result.offset_1); + XTESTS_TEST_INTEGER_EQUAL(0, (int)result.offset_2); +} + +static void +test_compare_binary_files_accepts_null_result(void) +{ + int const r = cmpfs_compare_binary_files("a", "b", NULL); + + XTESTS_TEST_INTEGER_EQUAL(ENOSYS, r); +} + +static void +test_compare_text_files_is_stub(void) +{ + cmpfs_comparison_result_t result; + int const r = cmpfs_compare_text_files( + "a" + , "b" + , CMPFS_F_TRIM_LINES | CMPFS_F_SKIP_BLANK_LINES + , &result + ); + + XTESTS_TEST_INTEGER_EQUAL(ENOSYS, r); + XTESTS_TEST_INTEGER_EQUAL(0, result.equal); +} + + +int +main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.compare.api", verbosity)) + { + XTESTS_RUN_CASE(test_compare_binary_files_is_stub); + XTESTS_RUN_CASE(test_compare_binary_files_accepts_null_result); + XTESTS_RUN_CASE(test_compare_text_files_is_stub); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + diff --git a/test/unit/test.unit.version/CMakeLists.txt b/test/unit/test.unit.version/CMakeLists.txt new file mode 100644 index 0000000..af5addc --- /dev/null +++ b/test/unit/test.unit.version/CMakeLists.txt @@ -0,0 +1 @@ +define_automated_test_program(test.unit.version test.unit.version.c) diff --git a/test/unit/test.unit.version/test.unit.version.c b/test/unit/test.unit.version/test.unit.version.c new file mode 100644 index 0000000..b13e8b0 --- /dev/null +++ b/test/unit/test.unit.version/test.unit.version.c @@ -0,0 +1,69 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test.unit.version.c + * + * Purpose: Unit tests for cmpfs version macros. + * + * Created: 21st August 2026 + * Updated: 21st August 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include + +#include + + +static void +test_version_components(void) +{ + XTESTS_TEST_INTEGER_EQUAL(0, CMPFS_VER_MAJOR); + XTESTS_TEST_INTEGER_EQUAL(0, CMPFS_VER_MINOR); + XTESTS_TEST_INTEGER_EQUAL(1, CMPFS_VER_PATCH); + XTESTS_TEST_INTEGER_EQUAL(0x41, CMPFS_VER_ALPHABETA); + XTESTS_TEST_INTEGER_EQUAL(CMPFS_VER_PATCH, CMPFS_VER_REVISION); +} + +static void +test_version_composite(void) +{ + int const computed = + (0 + | ( CMPFS_VER_MAJOR << 24 ) + | ( CMPFS_VER_MINOR << 16 ) + | ( CMPFS_VER_PATCH << 8 ) + | ( CMPFS_VER_ALPHABETA << 0 ) + ); + + XTESTS_TEST_INTEGER_EQUAL(computed, CMPFS_VER); + XTESTS_TEST_INTEGER_EQUAL(CMPFS_VER_0_0_1_ALPHA_1, CMPFS_VER); + XTESTS_TEST_INTEGER_EQUAL(0x00000141, CMPFS_VER); +} + + +int +main(int argc, char* argv[]) +{ + int retCode = EXIT_SUCCESS; + int verbosity = 2; + + XTESTS_COMMANDLINE_PARSEVERBOSITY(argc, argv, &verbosity); + + if (XTESTS_START_RUNNER("test.unit.version", verbosity)) + { + XTESTS_RUN_CASE(test_version_components); + XTESTS_RUN_CASE(test_version_composite); + + XTESTS_PRINT_RESULTS(); + + XTESTS_END_RUNNER_UPDATE_EXITCODE(&retCode); + } + + return retCode; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ + From 7dc2ad8d49586205bb1bc8817678dfcdb917f187 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 17 Sep 2026 16:45:26 +1000 Subject: [PATCH 2/9] fix --- src/compare.api.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compare.api.c b/src/compare.api.c index 27f6aa5..f386835 100644 --- a/src/compare.api.c +++ b/src/compare.api.c @@ -4,7 +4,7 @@ * Purpose: Skeleton implementation of the cmpfs comparison API. * * Created: ... 2010 ... - * Updated: 21st August 2026 + * Updated: 17th September 2026 * * Home: https://github.com/synesissoftware/cmpfs * @@ -71,6 +71,7 @@ cmpfs_compare_binary_files( ((void)path1); ((void)path2); + ((void)flags); if (NULL != result) { From ec8e7fdd61045b23c6ff249177a1047aca856c09 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 17 Sep 2026 17:00:37 +1000 Subject: [PATCH 3/9] fix --- examples/c/example.c.1/example.c.1.c | 10 ++++++-- include/cmpfs/cmpfs.h | 23 +++++++++++-------- .../test.unit.compare.api.c | 6 ++--- .../test.unit.version/test.unit.version.c | 2 +- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/examples/c/example.c.1/example.c.1.c b/examples/c/example.c.1/example.c.1.c index 3f0811b..94090bd 100644 --- a/examples/c/example.c.1/example.c.1.c +++ b/examples/c/example.c.1/example.c.1.c @@ -5,11 +5,17 @@ * compare-API status. * * Created: 21st August 2026 - * Updated: 21st August 2026 + * Updated: 17th September 2026 * * ////////////////////////////////////////////////////////////////////// */ +#if defined(_MSC_VER) && \ + !defined(_CRT_SECURE_NO_WARNINGS) +# define _CRT_SECURE_NO_WARNINGS +#endif /* _MSC_VER && !_CRT_SECURE_NO_WARNINGS */ + + #include #include @@ -36,7 +42,7 @@ main(void) , CMPFS_VER ); - r = cmpfs_compare_binary_files("left.bin", "right.bin", &result); + r = cmpfs_compare_binary_files("left.bin", "right.bin", CMPFS_F_NONE, &result); if (ENOSYS == r) { diff --git a/include/cmpfs/cmpfs.h b/include/cmpfs/cmpfs.h index 27c1dd5..ad16a1d 100644 --- a/include/cmpfs/cmpfs.h +++ b/include/cmpfs/cmpfs.h @@ -4,7 +4,7 @@ * Purpose: Main C header for the cmpfs library. * * Created: ... 2010 ... - * Updated: 21st August 2026 + * Updated: 17th September 2026 * * Home: https://github.com/synesissoftware/cmpfs * @@ -55,8 +55,8 @@ #ifndef CMPFS_DOCUMENTATION_SKIP_SECTION # define CMPFS_VER_CMPFS_H_CMPFS_MAJOR 1 # define CMPFS_VER_CMPFS_H_CMPFS_MINOR 1 -# define CMPFS_VER_CMPFS_H_CMPFS_REVISION 1 -# define CMPFS_VER_CMPFS_H_CMPFS_EDIT 12 +# define CMPFS_VER_CMPFS_H_CMPFS_REVISION 2 +# define CMPFS_VER_CMPFS_H_CMPFS_EDIT 13 #endif /* !CMPFS_DOCUMENTATION_SKIP_SECTION */ /** \def CMPFS_VER_MAJOR @@ -71,7 +71,7 @@ * The patch version number of cmpfs */ -/** \def CMPFS_VER_AB +/** \def CMPFS_VER_ALPHABETA * The alpha/beta designator of cmpfs, or 0xFF for a non-prerelease */ @@ -79,19 +79,24 @@ * The current composite version number of cmpfs */ -#define CMPFS_VER_MAJOR 1 -#define CMPFS_VER_MINOR 1 -#define CMPFS_VER_PATCH 0 -#define CMPFS_VER_AB 0x41 +#define CMPFS_VER_MAJOR 0 +#define CMPFS_VER_MINOR 0 +#define CMPFS_VER_PATCH 1 +#define CMPFS_VER_ALPHABETA 0x41 #define CMPFS_VER \ (0\ | ( CMPFS_VER_MAJOR << 24 ) \ | ( CMPFS_VER_MINOR << 16 ) \ | ( CMPFS_VER_PATCH << 8 ) \ - | ( CMPFS_VER_AB << 0 ) \ + | ( CMPFS_VER_ALPHABETA << 0 ) \ ) +/** \def CMPFS_VER_0_0_1_ALPHA_1 + * Composite version number for 0.0.1-alpha1 + */ +#define CMPFS_VER_0_0_1_ALPHA_1 0x00000141 + #ifndef CMPFS_DOCUMENTATION_SKIP_SECTION # define CMPFS_VER_REVISION CMPFS_VER_PATCH #endif /* !CMPFS_DOCUMENTATION_SKIP_SECTION */ diff --git a/test/unit/test.unit.compare.api/test.unit.compare.api.c b/test/unit/test.unit.compare.api/test.unit.compare.api.c index c7c0654..ae6e2c1 100644 --- a/test/unit/test.unit.compare.api/test.unit.compare.api.c +++ b/test/unit/test.unit.compare.api/test.unit.compare.api.c @@ -4,7 +4,7 @@ * Purpose: Unit tests for the cmpfs skeleton comparison API. * * Created: 21st August 2026 - * Updated: 21st August 2026 + * Updated: 17th September 2026 * * ////////////////////////////////////////////////////////////////////// */ @@ -25,7 +25,7 @@ static void test_compare_binary_files_is_stub(void) { cmpfs_comparison_result_t result; - int const r = cmpfs_compare_binary_files("a", "b", &result); + int const r = cmpfs_compare_binary_files("a", "b", CMPFS_F_NONE, &result); XTESTS_TEST_INTEGER_EQUAL(ENOSYS, r); XTESTS_TEST_INTEGER_EQUAL(0, result.equal); @@ -36,7 +36,7 @@ test_compare_binary_files_is_stub(void) static void test_compare_binary_files_accepts_null_result(void) { - int const r = cmpfs_compare_binary_files("a", "b", NULL); + int const r = cmpfs_compare_binary_files("a", "b", CMPFS_F_NONE, NULL); XTESTS_TEST_INTEGER_EQUAL(ENOSYS, r); } diff --git a/test/unit/test.unit.version/test.unit.version.c b/test/unit/test.unit.version/test.unit.version.c index b13e8b0..8856005 100644 --- a/test/unit/test.unit.version/test.unit.version.c +++ b/test/unit/test.unit.version/test.unit.version.c @@ -4,7 +4,7 @@ * Purpose: Unit tests for cmpfs version macros. * * Created: 21st August 2026 - * Updated: 21st August 2026 + * Updated: 17th September 2026 * * ////////////////////////////////////////////////////////////////////// */ From 5e2a318bb67cbb3e989d80928b62658dfb3fa9ca Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Thu, 17 Sep 2026 17:03:33 +1000 Subject: [PATCH 4/9] fix(cmpfs): pass flags and result in the install-smoke consumer The smoke consumer still called the 3-arg form. Pass 0 and NULL so find_package(cmpfs) compile-and-run matches the public signature; --- .github/workflows/ci.yml | 2 +- INSTALL.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4e5063..c3255ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,7 +178,7 @@ jobs: #endif int main(void) { - return (ENOSYS == cmpfs_compare_binary_files("a", "b", 0)) ? 0 : 1; + return (ENOSYS == cmpfs_compare_binary_files("a", "b", 0, NULL)) ? 0 : 1; } EOF if [ "${{ matrix.c_compiler }}" = "cl" ]; then diff --git a/INSTALL.md b/INSTALL.md index f88f129..49d5ad0 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -91,7 +91,7 @@ The primary choice for installation is by use of **CMake**. int main(void) { - int const r = cmpfs_compare_binary_files("a.bin", "b.bin", NULL); + int const r = cmpfs_compare_binary_files("a.bin", "b.bin", 0, NULL); printf("status %d (ENOSYS=%d while skeleton)\n", r, ENOSYS); From d99aa7f7a621a55ae884b85114684d333d2001e0 Mon Sep 17 00:00:00 2001 From: synesissoftware Date: Mon, 21 Sep 2026 12:20:52 +1000 Subject: [PATCH 5/9] Boilerplate, CI (#1) * chore(c-cpp): union files.associations from ~/dev vscode settings Give the 28 in-wave C/C++ projects (and gold **c** / **cxx** / **c_cxx** templates) a sorted **files.associations** union of all associations found under **~/dev**; * .gitattributes * .vscode/settings.json * .vimrc * CHANGES.md * chore(): use computed PREFIX_VER with documented PATCH Align library version macros to c-cpp-standards. Define MAJOR, MINOR, PATCH, and ALPHABETA; compute PREFIX_VER by shifts; keep REVISION as a skip-section alias of PATCH (target at column 60); retain named historical VER_* constants only for comparison and documentation. * squash-merge * squash-commit --- .editorconfig | 50 ++++++++ .gitattributes | 116 ++++++++++++++--- .gitignore | 182 ++++++++++++--------------- .vimrc | 22 ++-- .vscode/settings.json | 42 ++++++- CHANGES.md | 4 +- NEWS.md | 6 +- include/cmpfs/cmpfs.h | 5 +- test/scratch/CMakeLists.txt | 1 + test/scratch/versions/CMakeLists.txt | 1 + test/scratch/versions/main.c | 60 +++++++++ 11 files changed, 348 insertions(+), 141 deletions(-) create mode 100644 .editorconfig create mode 100644 test/scratch/versions/CMakeLists.txt create mode 100644 test/scratch/versions/main.c diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b409470 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,50 @@ +root = true + +# Language indent/EOL/charset overlap with .vscode/settings.json. +# Rulers, renderWhitespace, detectIndentation, mergeEditor, and +# language-server settings cannot be expressed here — they stay in +# settings.json. + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +# [bat] +[*.{bat,cmd}] +end_of_line = crlf +indent_size = 4 +indent_style = space + +# [c] +[*.{c,h}] +indent_size = 4 +indent_style = space + +# [cmake] +[{CMakeLists.txt,*.cmake}] +indent_size = 4 +indent_style = tab + +# [json] +[*.json] +indent_size = 2 +indent_style = space + +# [markdown] +[*.md] +indent_size = 2 +indent_style = space + +# [shellscript] +[*.{bash,sh,zsh}] +indent_size = 2 +indent_style = space + +# [yaml] +[*.{yaml,yml}] +indent_size = 2 +indent_style = space diff --git a/.gitattributes b/.gitattributes index e6605d1..76a2f86 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,17 +1,99 @@ -*.c linguist-language=C -*.cmake linguist-language=CMake -*.cmd linguist-detectable=false -*.cpp linguist-language=C++ -*.cxx linguist-language=C++ -*.dsp linguist-detectable=false -*.dsw linguist-detectable=false -*.h linguist-language=C -*.hpp linguist-language=C++ -*.html linguist-detectable=false -*.hxx linguist-language=C++ -*.sh linguist-detectable=false -*.sln linguist-detectable=false -*.vcxproj linguist-detectable=false -*.vimrc linguist-detectable=false -CMakeLists.txt linguist-language=CMake -makefile linguist-detectable=false +# .gitattributes — C / C++ (GitHub-hosted) +# +# Sources: GitHub Docs (line endings), git-scm gitattributes (diff=cpp), +# gitattributes/gitattributes C++.gitattributes + Common.gitattributes, +# github-linguist overrides. + +# Default: detect text, normalize to LF in the repository +* text=auto + +# --- Source --- +*.c text diff=cpp +*.c++ text diff=cpp +*.cc text diff=cpp +*.cpp text diff=cpp +*.cxx text diff=cpp +*.h text diff=cpp +*.h++ text diff=cpp +*.hh text diff=cpp +*.hpp text diff=cpp +*.hxx text diff=cpp +*.inc text +*.inl text +*.ipp text +*.tcc text +*.tpp text + +# --- Build / config --- +*.am text +*.cmake text +*.m4 text +*.mak text +*.mk text +*akefile text +CMakeLists.txt text +configure text eol=lf +configure.ac text + +# --- Scripts --- +*.bash text eol=lf +*.bat text eol=crlf +*.cmd text eol=crlf +*.ps1 text eol=crlf +*.sh text eol=lf +*.zsh text eol=lf + +# --- Docs / meta --- +*.adoc text +*.markdown text diff=markdown +*.md text diff=markdown +*.txt text +AUTHORS text +CHANGELOG text +CHANGES text +CONTRIBUTING text +COPYING text +LICENSE text +NEWS text +README text +TODO text +.gitattributes text +.gitignore text + +# --- Serialisation --- +*.json text +*.toml text +*.xml text +*.yaml text +*.yml text + +# --- Compiled / binary artefacts --- +*.a binary +*.dll binary +*.dylib binary +*.exe binary +*.gch binary +*.la binary +*.lai binary +*.lib binary +*.lo binary +*.o binary +*.obj binary +*.out binary +*.pch binary +*.slo binary +*.so binary + +# --- Archives / images (common) --- +*.gif binary +*.gz binary +*.ico binary +*.jpeg binary +*.jpg binary +*.png binary +*.tar binary +*.zip binary + +# --- GitHub Linguist --- +**/build/** linguist-generated +**/cmake-build-*/** linguist-generated diff --git a/.gitignore b/.gitignore index 68e4424..226c160 100644 --- a/.gitignore +++ b/.gitignore @@ -1,164 +1,127 @@ -# Synesis Information Systems .gitignore for C/C++ libraries +# Synesis Information Systems .gitignore for C / C++ libraries # directories (by name) -/.git-old/ -/.vs/ +bin/ +ideas/ +ipch/ +lib/ +scripts/internal/ +Win32/ +x64/ +.idea/ .svn/ +.vs/ -.classpath -/.idea/ -/__pycache__ -/node_modules +__pycache__/ -/_build/ +/_analyses/ /_build-ci/ +/_build/ /_internal/ -/_analyses/ - -/bin/ -/ipch/ -/lib/ -bin/ -ipch/ -lib/ -/doc/ /docs/ /dox/ -/dox /ideas/ -ideas/ +/include/xcontract/ +/include/xcover/ /included/ +/node_modules/ /releases/ /scratch/ -/temp/ - -/--include -/--src -/-include -/-src - -/examples/bin -/examples/c/bin -/examples/cpp/bin - -/examples/lib -/examples/c/lib -/examples/cpp/lib - -projects/util/vc10-generated/ - -perf_test/ - -scripts/internal/ - -/include/shwild/ -/include/xcontract/ -/include/xcover/ -/include/xtests/ -/src/shwild/ /src/xcontract/ /src/xcover/ -/src/xtests/ +/target/ +/temp/ + +/examples/bin/ +/examples/c/bin/ +/examples/c/lib/ +/examples/cpp/bin/ +/examples/cpp/lib/ +/examples/lib/ -Debug Multithreaded DLL/ Debug Multithreaded Dll/ -Debug Multithreaded pseudoUNIX/ +Debug Multithreaded DLL/ Debug Multithreaded pseudoUnix/ +Debug Multithreaded pseudoUNIX/ Debug Multithreaded/ Debug/ +DebugDll/ DebugDLL/ DebugDLLUNIX/ -DebugDll/ -DebugMTDLL/ +DebugMt/ DebugMTDll/ +DebugMTDLL/ DebugMTUnix/ -DebugMt/ DebugNox/ -DebugUNIX/ DebugUnix/ -Release Multithreaded DLL/ +DebugUNIX/ Release Multithreaded Dll/ -Release Multithreaded pseudoUNIX/ +Release Multithreaded DLL/ Release Multithreaded pseudoUnix/ +Release Multithreaded pseudoUNIX/ Release Multithreaded/ Release/ +ReleaseDll/ ReleaseDLL/ ReleaseDLLUNIX/ -ReleaseDll/ -ReleaseMTDLL/ +ReleaseMt/ ReleaseMTDll/ +ReleaseMTDLL/ ReleaseMTUnix/ -ReleaseMt/ ReleaseNox/ ReleaseUnix/ UDebug/ UDebugMt/ -URelease/ -UReleaseMt/ -Unicode Debug Multithreaded DLL/ Unicode Debug Multithreaded Dll/ +Unicode Debug Multithreaded DLL/ Unicode Debug Multithreaded/ Unicode Debug/ -Unicode Release Multithreaded DLL/ Unicode Release Multithreaded Dll/ +Unicode Release Multithreaded DLL/ Unicode Release Multithreaded/ Unicode Release/ - -Win32/ -x64/ +URelease/ +UReleaseMt/ # directories (by pattern) -/build/ar* -/build/bc5* -/build/como* -/build/cw* -/build/gcc3* -/build/gcc4* -/build/icl* -/build/vc5* -/build/*.zip - /include-*/ # files (by name) .DS_Store + +.classpath +.env.development.local +.env.local +.env.production.local +.env.test.local .ruby-version -.ruby-version-exclusions .svnignore .svnignore-at-root .update_deps -.env.local -.env.development.local -.env.test.local -.env.production.local - -list_changes.cmd -logging-bailout.txt -prepare.cmd -sh.exe.stackdump -tidydir.cmd -update_deps.cmd +build/CMakeCache.txt build/makefile.tmpl build/makefile.tools.xml build/shwild.tmplgen -build/CMakeCache.txt - -include/fastformat/internal/dos2unix.has.been.performed include/pantheios/internal/dos2unix.has.been.performed include/stlsoft/dos2unix.has.been.performed include/stlsoft/internal/dos2unix.has.been.performed - +list_changes.cmd +logging-bailout.txt +prepare.cmd +sh.exe.stackdump test/testpatterns.orj test/tests-plan.txt +tidydir.cmd +update_deps.cmd # files (by pattern) @@ -166,8 +129,6 @@ test/tests-plan.txt *~ *.*~ *.???_obj -*.VC.db -*.VC.opendb *.a *.app *.aps @@ -175,6 +136,7 @@ test/tests-plan.txt *.bak *.chm *.class +*.csproj*user *.d *.diff *.dll @@ -211,32 +173,42 @@ test/tests-plan.txt *.slo *.so *.suo -*.swp *.sw[ponm] +*.swp *.test *.tlog *.tmp *.unsuccessfulbuild -*.vcproj*.user -*.vcxproj*.user -*.csproj*user -*.vcproj*user -*.vcxproj*user +*.VC.db +*.VC.opendb *.xcuserstate *.zip -*.vc71.sln -*.vc8.sln -*.vc9.sln +/build/*.tmpl +/build/*.tmplgen +/build/*.tools.xml +/build/*.zip +/build/ar* +/build/bc5* +/build/como* +/build/cw* +/build/gcc3* +/build/gcc4* +/build/icl* +/build/vc5* RCa0* RCb0* -build/*.tmplgen -build/*.tmpl -build/*.tools.xml - npm-debug.log* yarn-debug.log* yarn-error.log* +*.vc71.sln +*.vc8.sln +*.vc9.sln +*.vcproj*.user +*.vcproj*user +*.vcxproj*.user +*.vcxproj*user + diff --git a/.vimrc b/.vimrc index 1bf33a0..cebe6af 100644 --- a/.vimrc +++ b/.vimrc @@ -42,29 +42,29 @@ autocmd BufWritePre * %s/\s\+$//e augroup sis_c_cxx autocmd! + " [bat] + autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 " [c] / [cpp] autocmd FileType c,cpp setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,64,68,72,76 - " [rust] - autocmd FileType rs setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 - " [cmake] autocmd FileType cmake setlocal noexpandtab tabstop=4 shiftwidth=4 softtabstop=4 - " [shellscript] - autocmd FileType sh,bash,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 - - " [bat] - autocmd FileType bat,dosbatch setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 - - " [json] / [markdown] / [yaml] / [ruby] - autocmd FileType json,markdown,yaml,ruby setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 + " [json] / [markdown] / [ruby] / [yaml] + autocmd FileType json,markdown,ruby,yaml setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 " [python] autocmd FileType python setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=60,76 + " [rust] + autocmd FileType rs setlocal expandtab tabstop=4 shiftwidth=4 softtabstop=4 colorcolumn=76 + + " [shellscript] + autocmd FileType bash,sh,zsh setlocal expandtab tabstop=2 shiftwidth=2 softtabstop=2 colorcolumn=60,76 + " [toml] autocmd FileType toml setlocal noexpandtab tabstop=2 shiftwidth=2 softtabstop=2 + augroup END diff --git a/.vscode/settings.json b/.vscode/settings.json index 3fe51d2..6aa78f6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,8 +5,10 @@ "editor.tabSize": 4, }, "[c]": { + "editor.defaultFormatter": "ms-vscode.cpptools", + "editor.formatOnSave": true, "editor.insertSpaces": true, - "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.rulers": [ 60, 64, 68, 72, 76, 120 ], "editor.tabSize": 4, }, "[cmake]": { @@ -14,8 +16,10 @@ "editor.tabSize": 4, }, "[cpp]": { + "editor.defaultFormatter": "ms-vscode.cpptools", + "editor.formatOnSave": true, "editor.insertSpaces": true, - "editor.rulers": [ 60, 64, 68, 72, 76 ], + "editor.rulers": [ 60, 64, 68, 72, 76, 120 ], "editor.tabSize": 4, }, "[json]": { @@ -34,6 +38,7 @@ }, "[ruby]": { "editor.insertSpaces": true, + "editor.rulers": [ 60, 76 ], "editor.tabSize": 2, }, "[shellscript]": { @@ -49,13 +54,28 @@ "editor.insertSpaces": true, "editor.tabSize": 2, }, + "C_Cpp.autocompleteAddParentheses": true, + "C_Cpp.clang_format_fallbackStyle": "none", + "C_Cpp.clang_format_style": "file", + "C_Cpp.default.cStandard": "c17", + "C_Cpp.default.cppStandard": "c++17", + "C_Cpp.enhancedColorization": "enabled", + "C_Cpp.errorSquiggles": "enabled", + "C_Cpp.formatting": "clangFormat", + "C_Cpp.intelliSenseEngine": "default", "cmake.configureOnOpen": false, + "debug.allowBreakpointsEverywhere": true, "editor.detectIndentation": false, "editor.insertSpaces": false, "editor.renderWhitespace": "all", "editor.rulers": [ 76 ], "editor.tabSize": 2, "files.associations": { + "*.gemspec": "ruby", + "*.mdoc": "troff", + "*.roff": "troff", + "Gemfile": "ruby", + "Rakefile": "ruby", "__bit_reference": "cpp", "__bits": "cpp", "__config": "cpp", @@ -76,13 +96,17 @@ "__tuple": "cpp", "__verbose_abort": "cpp", "algorithm": "cpp", + "api.h": "c", "array": "cpp", "atomic": "cpp", + "auto_buffer.h": "c", "bit": "cpp", "bitset": "cpp", "cctype": "cpp", "charconv": "cpp", "chrono": "cpp", + "clasp.h": "c", + "cli_helpers.h": "c", "clocale": "cpp", "cmath": "cpp", "compare": "cpp", @@ -109,6 +133,7 @@ "functional": "cpp", "implicit_link.h": "c", "initializer_list": "cpp", + "invoke.h": "c", "io.h": "c", "iomanip": "cpp", "ios": "cpp", @@ -119,28 +144,39 @@ "limits": "cpp", "list": "cpp", "locale": "cpp", + "main.h": "c", "map": "cpp", "memory": "cpp", "memory_resource": "cpp", "mutex": "cpp", + "net_helpers.h": "c", "new": "cpp", "numbers": "cpp", "numeric": "cpp", "optional": "cpp", "ostream": "cpp", + "path_functions.h": "c", + "print": "cpp", "queue": "cpp", "random": "cpp", "ranges": "cpp", "ratio": "cpp", + "rc.h": "c", + "recls.h": "c", + "result_codes_.h": "c", "semaphore": "cpp", "set": "cpp", "setenv.h": "c", "shwild.h": "c", + "sleep_functions.h": "c", "span": "cpp", "sstream": "cpp", "stack": "cpp", + "stdatomic.h": "c", + "stdbool.h": "c", "stdexcept": "cpp", "stdio.h": "c", + "stock.h": "c", "stop_token": "cpp", "streambuf": "cpp", "string": "cpp", @@ -149,6 +185,7 @@ "terse-api.h": "c", "text_encoding": "cpp", "thread": "cpp", + "trace.h": "c", "tuple": "cpp", "type_traits": "cpp", "typeinfo": "cpp", @@ -159,6 +196,7 @@ "utility": "cpp", "variant": "cpp", "vector": "cpp", + "williamscrc.h": "c", "xfacet": "cpp", "xhash": "cpp", "xiosbase": "cpp", diff --git a/CHANGES.md b/CHANGES.md index 77dd7dd..cb66909 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,11 +1,13 @@ # cmpfs - Changes -## 0.0.1-alpha1 - 21st August 2026 +## 0.0.1-alpha1 - 21st September 2026 * Created a Synesis-style **C** library skeleton: version macros, **CMake** packaging, **.sis** helper-script identity, modular GitHub Actions CI (**ci.yml** / **ci-cell.yml**), and install-smoke as a C consumer; * Declared stub **`cmpfs_compare_binary_files()`** and **`cmpfs_compare_text_files()`** (currently **`ENOSYS`**); * Added C example **example.c.1** and **xTests** unit coverage for version macros and the stub compare API; +* Applied **misc-dev-scripts** **0.6.0** editor/Git/`.sis` drop-in templates on **boilerplate**; +* Restored historical **.gitignore** patterns as a sorted union with **misc-dev-scripts** gold section layout; diff --git a/NEWS.md b/NEWS.md index 22fc3c7..10c9826 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,9 +8,9 @@ ## News -| Date | News Item | -| ---------------- | -------------------------------------------------------------------------------- | -| 21st August 2026 | cmpfs 0.0.1-alpha1 | +| Date | News Item | Details | +| ---------------- | ------------------- | ------- | +| 21st August 2026 | cmpfs 0.0.1-alpha1 | initial public release | diff --git a/include/cmpfs/cmpfs.h b/include/cmpfs/cmpfs.h index ad16a1d..6087438 100644 --- a/include/cmpfs/cmpfs.h +++ b/include/cmpfs/cmpfs.h @@ -4,7 +4,7 @@ * Purpose: Main C header for the cmpfs library. * * Created: ... 2010 ... - * Updated: 17th September 2026 + * Updated: 21st September 2026 * * Home: https://github.com/synesissoftware/cmpfs * @@ -98,7 +98,8 @@ #define CMPFS_VER_0_0_1_ALPHA_1 0x00000141 #ifndef CMPFS_DOCUMENTATION_SKIP_SECTION -# define CMPFS_VER_REVISION CMPFS_VER_PATCH +# define CMPFS_VER_REVISION CMPFS_VER_PATCH +# define CMPFS_VER_AB CMPFS_VER_ALPHABETA #endif /* !CMPFS_DOCUMENTATION_SKIP_SECTION */ diff --git a/test/scratch/CMakeLists.txt b/test/scratch/CMakeLists.txt index 17608a6..afeea9d 100644 --- a/test/scratch/CMakeLists.txt +++ b/test/scratch/CMakeLists.txt @@ -1,4 +1,5 @@ add_subdirectory(test.scratch.compare) +add_subdirectory(versions) # ############################## end of file ############################# # diff --git a/test/scratch/versions/CMakeLists.txt b/test/scratch/versions/CMakeLists.txt new file mode 100644 index 0000000..8db359b --- /dev/null +++ b/test/scratch/versions/CMakeLists.txt @@ -0,0 +1 @@ +define_example_program(versions main.c) diff --git a/test/scratch/versions/main.c b/test/scratch/versions/main.c new file mode 100644 index 0000000..c4bab42 --- /dev/null +++ b/test/scratch/versions/main.c @@ -0,0 +1,60 @@ +/* ///////////////////////////////////////////////////////////////////////// + * File: test/scratch/versions/main.c + * + * Purpose: Prints cmpfs composite version. + * + * Created: 17th September 2026 + * Updated: 17th September 2026 + * + * ////////////////////////////////////////////////////////////////////// */ + + +#include + +#include +#include + + +#define PROGRAM_NAME "versions" + + +static void +version( + FILE* stm +, char const* prefix +, char const* libname +, char const* macroname +, unsigned libver +) +{ + fprintf( + stm + , "%s%s: v%u.%u.%u.%u (%s = 0x%08x)\n" + , prefix + , libname + , (libver >> 24) & 0xff + , (libver >> 16) & 0xff + , (libver >> 8) & 0xff + , (libver >> 0) & 0xff + , macroname + , libver + ); +} + + +int main(int argc, char* argv[]) +{ + ((void)&argc); + ((void)&argv); + + { + unsigned const libver = (unsigned)CMPFS_VER; + + version(stdout, "", "cmpfs", "CMPFS_VER", libver); + } + + return EXIT_SUCCESS; +} + + +/* ///////////////////////////// end of file //////////////////////////// */ From b28675b707e68668bcbc168f4326483fdf91a24f Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Tue, 22 Sep 2026 05:09:54 +1000 Subject: [PATCH 6/9] .gitattributes --- .gitattributes | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.gitattributes b/.gitattributes index 76a2f86..1ad0590 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,11 @@ # Sources: GitHub Docs (line endings), git-scm gitattributes (diff=cpp), # gitattributes/gitattributes C++.gitattributes + Common.gitattributes, # github-linguist overrides. +# +# Linguist language-bar policy (Synesis): classify public C API headers as C +# and *.cmake as CMake scripts; keep helper scripts, IDE project files, and +# CMakeLists.txt config out of the advertised language mix. Prefer +# -linguist-detectable over linguist-detectable=false. # Default: detect text, normalize to LF in the repository * text=auto @@ -97,3 +102,25 @@ TODO text # --- GitHub Linguist --- **/build/** linguist-generated **/cmake-build-*/** linguist-generated + +# Classification (C-primary / C API with C++ tests; *.cmake as CMake scripts) +*.c linguist-language=C +*.cmake linguist-language=CMake +*.cpp linguist-language=C++ +*.cxx linguist-language=C++ +*.h linguist-language=C +*.hpp linguist-language=C++ +*.hxx linguist-language=C++ + +# Keep the bar on library languages (helpers / legacy IDE / docs / +# CMakeLists.txt config; leave *.cmake detectable as CMake) +*.cmd -linguist-detectable +*.dsp -linguist-detectable +*.dsw -linguist-detectable +*.html -linguist-detectable +*.sh -linguist-detectable +*.sln -linguist-detectable +*.vcxproj -linguist-detectable +*.vimrc -linguist-detectable +CMakeLists.txt -linguist-detectable +makefile -linguist-detectable From 171774407f6f9b89dc30fdcfef2677fe1fa17315 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Tue, 22 Sep 2026 09:02:34 +1000 Subject: [PATCH 7/9] fix(c-cpp): quote Dir resolution in CMake helper scripts Use Dir=$(cd "$(dirname "$ScriptPath")" && pwd) so paths with spaces resolve reliably; apply the same one-line fix across in-wave helper scripts (prepare/build/clean/ctest/remove and run_all_*). --- build_cmake.sh | 2 +- clean_cmake.sh | 2 +- ctest_cmake.sh | 2 +- prepare_cmake.sh | 2 +- remove_cmake_artefacts.sh | 2 +- run_all_examples.sh | 2 +- run_all_scratch_tests.sh | 2 +- run_all_unit_tests.sh | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/build_cmake.sh b/build_cmake.sh index 1f6b55d..5e2e513 100755 --- a/build_cmake.sh +++ b/build_cmake.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Basename=$(basename "$ScriptPath") diff --git a/clean_cmake.sh b/clean_cmake.sh index 87b42eb..2741f3b 100755 --- a/clean_cmake.sh +++ b/clean_cmake.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Basename=$(basename "$ScriptPath") diff --git a/ctest_cmake.sh b/ctest_cmake.sh index 24c2172..4c5c569 100755 --- a/ctest_cmake.sh +++ b/ctest_cmake.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) Basename=$(basename "$ScriptPath") CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} [[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make diff --git a/prepare_cmake.sh b/prepare_cmake.sh index cd236f2..3c0c255 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Basename=$(basename "$ScriptPath") diff --git a/remove_cmake_artefacts.sh b/remove_cmake_artefacts.sh index 076a84a..8a60908 100755 --- a/remove_cmake_artefacts.sh +++ b/remove_cmake_artefacts.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Basename=$(basename "$ScriptPath") diff --git a/run_all_examples.sh b/run_all_examples.sh index bb7ef70..ed97ca8 100755 --- a/run_all_examples.sh +++ b/run_all_examples.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Basename=$(basename "$ScriptPath") diff --git a/run_all_scratch_tests.sh b/run_all_scratch_tests.sh index 25aa4c1..19b2921 100755 --- a/run_all_scratch_tests.sh +++ b/run_all_scratch_tests.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Basename=$(basename "$ScriptPath") diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index 22efd84..8c22a3a 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -1,7 +1,7 @@ #! /bin/bash ScriptPath=$0 -Dir=$(cd $(dirname "$ScriptPath"); pwd) +Dir=$(cd "$(dirname "$ScriptPath")" && pwd) ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") Basename=$(basename "$ScriptPath") From bc1e65ec66924a06f9fc486b4cf8e7634980782b Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Fri, 9 Oct 2026 11:59:11 +1100 Subject: [PATCH 8/9] chore(cmpfs): land Phase 4b helpers and 4c versions target Bring cmpfs to the misc-dev-scripts cmake-helpers gold tip and lock the scratch reporter name: - Replace MakeCmd / MSYSTEM-default helpers with the 11 gold Bash scripts (SisClr colours, sis_cmake_build, cmake --build only); - Keep **--stlsoft-root-dir** / **-s** in the PROJECT-SPECIFIC block of **prepare_cmake.sh**, passed as **-DSTLSOFT=** on the single cmake line; - Add the six native **run_all_*.cmd** runners and drop the bash wraps; - Rename scratch target **versions** to **test.scratch.versions**; - Record the changes in **CHANGES.md** and tick the **MSYSTEM** item in **TODO.md**; --- CHANGES.md | 3 + TODO.md | 2 +- build_cmake.sh | 190 ++++++++++++----- clean_cmake.sh | 162 ++++++++++++--- ctest_cmake.sh | 171 +++++++++++++-- prepare_cmake.sh | 239 ++++++++++++++++----- remove_cmake_artefacts.sh | 146 +++++++++---- run_all_automated_tests.cmd | 106 ++++++++++ run_all_automated_tests.sh | 180 ++++++++++++++++ run_all_component_tests.cmd | 94 +++++++++ run_all_component_tests.sh | 300 +++++++++++++++++++++++++++ run_all_examples.cmd | 89 ++++++++ run_all_examples.sh | 204 +++++++++++++++--- run_all_performance_tests.cmd | 85 ++++++++ run_all_performance_tests.sh | 276 ++++++++++++++++++++++++ run_all_scratch_tests.cmd | 85 ++++++++ run_all_scratch_tests.sh | 191 ++++++++++++++--- run_all_unit_tests.cmd | 144 +++---------- run_all_unit_tests.sh | 224 ++++++++++++++------ test/scratch/versions/CMakeLists.txt | 2 +- 20 files changed, 2453 insertions(+), 440 deletions(-) create mode 100644 run_all_automated_tests.cmd create mode 100755 run_all_automated_tests.sh create mode 100644 run_all_component_tests.cmd create mode 100755 run_all_component_tests.sh create mode 100644 run_all_examples.cmd create mode 100644 run_all_performance_tests.cmd create mode 100755 run_all_performance_tests.sh create mode 100644 run_all_scratch_tests.cmd diff --git a/CHANGES.md b/CHANGES.md index cb66909..0cbcc17 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -8,6 +8,9 @@ * Added C example **example.c.1** and **xTests** unit coverage for version macros and the stub compare API; * Applied **misc-dev-scripts** **0.6.0** editor/Git/`.sis` drop-in templates on **boilerplate**; * Restored historical **.gitignore** patterns as a sorted union with **misc-dev-scripts** gold section layout; +* Modernised CMake helpers to the Phase 4b dialect (`SisClr_*` / `-A`, `sis_cmake_build`, no MinGW-from-`MSYSTEM`), retaining **`--stlsoft-root-dir`** in **prepare_cmake.sh**; +* Native Windows **`run_all_*.cmd`** runners (no Bash wrap); aggregate **`run_all_automated_tests.*`**; added **run_all_component_tests.sh** and **run_all_performance_tests.sh**; +* Renamed scratch versions reporter target to **test.scratch.versions** (formerly **versions**); diff --git a/TODO.md b/TODO.md index 321bfe0..23ddd23 100644 --- a/TODO.md +++ b/TODO.md @@ -42,7 +42,7 @@ ## Packaging improvements -* [ ] Defer rewriting helper `MSYSTEM` → `mingw32-make` / MinGW-generator detection until the **HELPER-SCRIPTS-C-CXX.md** contract is frozen (same defect class as other Synesis C/C++ helpers); +* [x] ~~~Defer rewriting helper `MSYSTEM` → `mingw32-make` / MinGW-generator detection until the **HELPER-SCRIPTS-C-CXX.md** contract is frozen (same defect class as other Synesis C/C++ helpers)~~~ - ✅; diff --git a/build_cmake.sh b/build_cmake.sh index 5e2e513..a675a9d 100755 --- a/build_cmake.sh +++ b/build_cmake.sh @@ -1,22 +1,119 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} IgnoreRemainingFlagsAndOptions=0 +SisUseColours=0 Targets=() # ########################################################## -# functions +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 -function join_by { local IFS="$1"; shift; echo "$*"; } +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -26,21 +123,16 @@ while [[ $# -gt 0 ]]; do if [ $IgnoreRemainingFlagsAndOptions -ne 0 ]; then - Targets+=($1) - + Targets+=("$1") shift - continue - else - - if [ ! ${1:0:1} = '-' ]; then - - Targets+=($1) + fi - shift + if [ "${1:0:1}" != '-' ]; then - continue - fi + Targets+=("$1") + shift + continue fi case $1 in @@ -48,18 +140,33 @@ while [[ $# -gt 0 ]]; do IgnoreRemainingFlagsAndOptions=1 ;; + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF Executes CMake-generated artefacts to (re)build project -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + (no arguments) + builds all default targets + + ... + builds one or more specific targets + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + standard flags: @@ -72,7 +179,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -85,41 +192,26 @@ done # ########################################################## # main() -if [ ! -d "$CMakeDir" ]; then +if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + >&2 echo "${ScriptPathClr}: CMake build directory '${CMakeDirClr}' not found or not configured; use script 'prepare_cmake.sh' first" exit 1 -else - - cd $CMakeDir - - if [ ! -f "$CMakeDir/Makefile" ]; then - - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" - - cd ->/dev/null - - exit 1 - else - - if [ -z "$Targets" ]; then - - echo "Executing build (via command \`$MakeCmd\`)" - else - - echo "Executing build (via command \`$MakeCmd\`) with specific target(s) $(join_by , "${Targets[@]}")" - fi +fi - $MakeCmd ${Targets[*]} - status=$? +if [ ${#Targets[@]} -eq 0 ]; then - cd ->/dev/null + echo "Executing build of ${ProjectNameClr} (via cmake --build)" + sis_cmake_build + status=$? +else - exit $status - fi + echo "Executing build of ${ProjectNameClr} (via cmake --build) with specific target(s): ${Targets[*]}" + sis_cmake_build "${Targets[@]}" + status=$? fi +exit $status -# ############################## end of file ############################# # +# ############################## end of file ############################# # diff --git a/clean_cmake.sh b/clean_cmake.sh index 2741f3b..733afbd 100755 --- a/clean_cmake.sh +++ b/clean_cmake.sh @@ -1,13 +1,117 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -16,18 +120,27 @@ MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF -Executes CMake-generated artefacts to clean project +Cleans CMake-generated build artefacts via cmake --build --target clean -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + standard flags: @@ -40,7 +153,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -53,35 +166,16 @@ done # ########################################################## # main() -if [ ! -d "$CMakeDir" ]; then +if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + >&2 echo "${ScriptPathClr}: CMake build directory '${CMakeDirClr}' not found or not configured; nothing to clean" exit 1 -else - - cd $CMakeDir - - if [ ! -f "$CMakeDir/Makefile" ]; then - - >&2 echo "$ScriptPath: CMake build directory '$CMakeDir' does not contain expected file 'Makefile', so a clean cannot be performed. It is recommended that you remove all CMake artefacts using script 'remove_cmake_artefacts.sh' followed by regeneration via 'prepare_cmake.sh'" - - cd ->/dev/null - - exit 1 - else - - echo "Cleaning build (via command \`$MakeCmd clean\`)" - - $MakeCmd clean - status=$? - - cd ->/dev/null - - exit $status - fi fi +echo "Executing clean of ${ProjectNameClr} (via cmake --build --target clean)" +sis_cmake_build clean +exit $? -# ############################## end of file ############################# # +# ############################## end of file ############################# # diff --git a/ctest_cmake.sh b/ctest_cmake.sh index 4c5c569..4e09ee2 100755 --- a/ctest_cmake.sh +++ b/ctest_cmake.sh @@ -1,16 +1,119 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) -Basename=$(basename "$ScriptPath") +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 -CMakeVerbose= +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +CTestVerbose= RunMake=1 +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -19,13 +122,17 @@ RunMake=1 while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --no-make|-M) RunMake=0 ;; --verbose|-V) - CMakeVerbose=--verbose + CTestVerbose=--verbose ;; --help) @@ -33,15 +140,20 @@ while [[ $# -gt 0 ]]; do cat << EOF Runs CMake's CTest test program(s) -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -M --no-make - does not execute CMake and make before running tests + does not execute a build before running tests -V --verbose @@ -59,7 +171,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -76,29 +188,48 @@ status=0 if [ $RunMake -ne 0 ]; then - echo "Executing build for ${ProjectName} (via command \`$MakeCmd\`) and then running all component and unit test programs" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running CTest" - mkdir -p $CMakeDir || exit 1 + mkdir -p "$CMakeDir" || exit 1 - cd $CMakeDir + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - $MakeCmd - status=$? + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi - cd ->/dev/null + sis_cmake_build + status=$? else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + exit 1 fi fi if [ $status -eq 0 ]; then - echo "Running CMake tests" + echo + echo "Running ${ProjectNameClr} CMake tests" + + # Multi-config generators (e.g. Visual Studio) need -C ; + # mirror sis_cmake_build's CMAKE_CONFIGURATION_TYPES detection. + ctest_args=(--test-dir "$CMakeDir" --output-on-failure) + if [ -n "$CTestVerbose" ]; then + + ctest_args+=("$CTestVerbose") + fi + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + ctest_args+=(-C "${SIS_CMAKE_CONFIG:-Release}") + fi - ctest --test-dir $CMakeDir $CMakeVerbose + ctest "${ctest_args[@]}" status=$? fi diff --git a/prepare_cmake.sh b/prepare_cmake.sh index 3c0c255..de6262e 100755 --- a/prepare_cmake.sh +++ b/prepare_cmake.sh @@ -1,23 +1,135 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +BuildSharedLibs=0 Configuration=Release ExamplesDisabled=0 +MinGW=$(sis_cmake_is_truey "${SIS_CMAKE_MINGW:-}" && echo 1 || echo 0) MSVC_MT=0 -MinGW=0 RunMake=0 -STLSoftDirGiven= +SisUseColours=0 TestingDisabled=0 VerboseMakefile=0 +# ########################################################## +# PROJECT-SPECIFIC FLAGS (customise per library; keep marker) +# +# Add project-only options here (e.g. --no-cpp, --stlsoft-root-dir, +# --no-shwild). The common body below must stay aligned with +# misc-dev-scripts/shell-scripts/cmake-helpers/prepare_cmake.sh. + +STLSoftDirGiven= + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + # ########################################################## # command-line handling @@ -25,6 +137,14 @@ VerboseMakefile=0 while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; + --build-shared-libs) + + BuildSharedLibs=1 + ;; --cmake-verbose-makefile|-v) VerboseMakefile=1 @@ -60,46 +180,49 @@ while [[ $# -gt 0 ]]; do ;; --help) - [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" - cat << EOF -Creates/reinitialises the CMake build script(s) for ${ProjectName} + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Creates/reinitialises the CMake build script(s) -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + --build-shared-libs + builds ${ProjectName} as a shared library (BUILD_SHARED_LIBS=ON) + -v --cmake-verbose-makefile - configures CMake to run verbosely (by setting CMAKE_VERBOSE_MAKEFILE - to be ON) + configures CMake to run verbosely (CMAKE_VERBOSE_MAKEFILE=ON) -d --debug-configuration - use Debug configuration (by setting CMAKE_BUILD_TYPE=Debug). Default - is to use Release + use Debug configuration (CMAKE_BUILD_TYPE=Debug). Default is Release -E --disable-examples - disables building of examples (by setting BUILD_EXAMPLES=OFF) + disables building of examples (BUILD_EXAMPLES=OFF) -T --disable-testing - disables building of tests (by setting BUILD_TESTING=OFF). Unless - testing is disabled the STLSoft and xTests libraries will be - required to be available to CMake + disables building of tests (BUILD_TESTING=OFF) --mingw uses explicitly the "MinGW Makefiles" generator --msvc-mt - when using Visual C++ (MSVC), the static runtime library will be - selected; the default is the dynamic runtime library + when using Visual C++ (MSVC), select the static runtime library -m --run-make - executes make after a successful running of CMake + executes a build via cmake --build after a successful configure -s --stlsoft-root-dir @@ -119,7 +242,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -132,59 +255,63 @@ done # ########################################################## # main() -mkdir -p $CMakeDir || exit 1 - -cd $CMakeDir +mkdir -p "$CMakeDir" || exit 1 -echo "Executing CMake (in ${CMakeDir})" +echo +echo "Executing CMake for ${ProjectNameClr} (in ${CMakeDirClr})" +if [ $BuildSharedLibs -eq 0 ]; then CMakeBuildSharedLibsFlag="OFF" ; else CMakeBuildSharedLibsFlag="ON" ; fi if [ $ExamplesDisabled -eq 0 ]; then CMakeBuildExamplesFlag="ON" ; else CMakeBuildExamplesFlag="OFF" ; fi if [ $MSVC_MT -eq 0 ]; then CMakeMsvcMtFlag="OFF" ; else CMakeMsvcMtFlag="ON" ; fi -if [ -z $STLSoftDirGiven ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi +if [ -z "$STLSoftDirGiven" ]; then CMakeSTLSoftVariable="" ; else CMakeSTLSoftVariable="-DSTLSOFT=$STLSoftDirGiven/" ; fi if [ $TestingDisabled -eq 0 ]; then CMakeBuildTestingFlag="ON" ; else CMakeBuildTestingFlag="OFF" ; fi if [ $VerboseMakefile -eq 0 ]; then CMakeVerboseMakefileFlag="OFF" ; else CMakeVerboseMakefileFlag="ON" ; fi +# NOTE: the generator is the *only* thing that may differ between the MinGW +# and the default paths; every -D option is passed in both cases, so that no +# flag can be silently ignored according to the generator selected. + +CMakeGeneratorArgs=() + +if [ -n "${SIS_CMAKE_GENERATOR:-}" ] && [ $MinGW -eq 0 ]; then + + CMakeGeneratorArgs=(-G "$SIS_CMAKE_GENERATOR") +fi + if [ $MinGW -ne 0 ]; then - cmake \ - $CMakeSTLSoftVariable \ - -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ - -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ - -DCMAKE_BUILD_TYPE=$Configuration \ - -G "MinGW Makefiles" \ - -S $Dir \ - -B $CMakeDir \ - || (cd ->/dev/null ; exit 1) -else - - cmake \ - $CMakeSTLSoftVariable \ - -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ - -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ - -DCMAKE_BUILD_TYPE=$Configuration \ - -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ - -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ - -S $Dir \ - -B $CMakeDir \ - || (cd ->/dev/null ; exit 1) + CMakeGeneratorArgs=(-G "MinGW Makefiles") fi +cmake \ + -DBUILD_EXAMPLES:BOOL=$CMakeBuildExamplesFlag \ + -DBUILD_SHARED_LIBS:BOOL=$CMakeBuildSharedLibsFlag \ + -DBUILD_TESTING:BOOL=$CMakeBuildTestingFlag \ + -DCMAKE_BUILD_TYPE=$Configuration \ + -DCMAKE_VERBOSE_MAKEFILE:BOOL=$CMakeVerboseMakefileFlag \ + -DMSVC_USE_MT:BOOL=$CMakeMsvcMtFlag \ + $CMakeSTLSoftVariable \ + "${CMakeGeneratorArgs[@]}" \ + -B "$CMakeDir" \ + -S "$Dir" \ + || exit 1 + status=0 if [ $RunMake -ne 0 ]; then - echo "Executing build (via command \`$MakeCmd\`)" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build)" - $MakeCmd + sis_cmake_build status=$? fi -cd ->/dev/null - if [ $VerboseMakefile -ne 0 ]; then - echo -e "contents of $CMakeDir:" - ls -al $CMakeDir + echo + echo -e "contents of ${CMakeDirClr}:" + ls -al "$CMakeDir" fi exit $status diff --git a/remove_cmake_artefacts.sh b/remove_cmake_artefacts.sh index 8a60908..377d3ab 100755 --- a/remove_cmake_artefacts.sh +++ b/remove_cmake_artefacts.sh @@ -1,12 +1,16 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} Directories=( CMakeFiles Testing @@ -24,14 +28,73 @@ Files=( cmake_install.cmake install_manifest.txt ) +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" # ########################################################## # operating environment detection -OsName="$(uname -s)" +OsName="$(uname -s 2>/dev/null || echo Unknown)" case "${OsName}" in - CYGWIN*|MINGW*|MSYS_NT*) + CYGWIN*|MINGW*|MSYS_NT*|Windows_NT) Directories+=( ARM64 @@ -43,9 +106,6 @@ case "${OsName}" in "*.sln" "*.vcxproj" ) - ;; - *) - ;; esac @@ -56,18 +116,27 @@ esac while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --help) [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF Removes all known CMake artefacts -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + standard flags: @@ -80,7 +149,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -95,59 +164,50 @@ done if [ ! -d "$CMakeDir" ]; then - echo "$ScriptPath: CMake build directory '$CMakeDir' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" + echo "${ScriptPathClr}: CMake build directory '${CMakeDirClr}' not found so nothing to do; use script 'prepare_cmake.sh' if you wish to prepare CMake artefacts" exit 0 -else - - echo "Removing all cmake artefacts in '$CMakeDir'" +fi - num_dirs_removed=0 - num_files_removed=0 +echo "Removing all ${ProjectNameClr} cmake artefacts in '${CMakeDirClr}'" - for d in ${Directories[@]} - do +num_dirs_removed=0 +num_files_removed=0 - fq_dir_path="$CMakeDir/$d" +for d in "${Directories[@]}"; do - [ -d "$fq_dir_path" ] || continue + fq_dir_path="$CMakeDir/$d" - echo "removing directory '$d'" + [ -d "$fq_dir_path" ] || continue - rm -dfr "$fq_dir_path" + echo "removing directory '$d'" - num_dirs_removed=$((num_dirs_removed+1)) - done + rm -dfr "$fq_dir_path" - cd "$CMakeDir" + num_dirs_removed=$((num_dirs_removed+1)) +done - for f in ${Files[@]} - do +for f in "${Files[@]}"; do - for fq_file_path in $f - do + for fq_file_path in "$CMakeDir"/$f; do - [ -f "$fq_file_path" ] || continue + [ -f "$fq_file_path" ] || continue - echo "removing file '$fq_file_path'" + echo "removing file '$fq_file_path'" - rm -f "$fq_file_path" + rm -f "$fq_file_path" - num_files_removed=$((num_files_removed+1)) - done + num_files_removed=$((num_files_removed+1)) done +done - cd ->/dev/null - - if [ 0 -eq $num_dirs_removed ] && [ 0 -eq $num_files_removed ]; then +if [ 0 -eq $num_dirs_removed ] && [ 0 -eq $num_files_removed ]; then - echo "nothing to do" - else + echo "nothing to do" +else - echo "removed $num_dirs_removed directories and $num_files_removed files" - fi + echo "removed $num_dirs_removed directories and $num_files_removed files" fi # ############################## end of file ############################# # - diff --git a/run_all_automated_tests.cmd b/run_all_automated_tests.cmd new file mode 100644 index 0000000..b6dd937 --- /dev/null +++ b/run_all_automated_tests.cmd @@ -0,0 +1,106 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +SET UnitOnly=0 +SET ComponentOnly=0 + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) automated test programs ^(unit and component^) ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + --unit-only ^ + + runs only unit-test programs ^ + +^ + + --component-only ^ + + runs only component-test programs ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {--unit-only}=={%%a} ( + + SET UnitOnly=1 + ) ELSE IF /I {--component-only}=={%%a} ( + + SET ComponentOnly=1 + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +IF %UnitOnly% NEQ 0 IF %ComponentOnly% NEQ 0 ( + + ECHO %SCRIPT_PATH_DOC%: --unit-only and --component-only are mutually exclusive 1>&2 + + EXIT /B 1 +) + +IF %UnitOnly% NEQ 0 ( + CALL "%SCRIPT_DIRECTORY%run_all_unit_tests.cmd" + EXIT /B %ERRORLEVEL% +) + +IF %ComponentOnly% NEQ 0 ( + CALL "%SCRIPT_DIRECTORY%run_all_component_tests.cmd" + EXIT /B %ERRORLEVEL% +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +ECHO Running all %ProjectName% automated test programs ^(unit and component^) + +CALL "%SCRIPT_DIRECTORY%run_all_unit_tests.cmd" +IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% + +CALL "%SCRIPT_DIRECTORY%run_all_component_tests.cmd" +EXIT /B %ERRORLEVEL% + +ENDLOCAL diff --git a/run_all_automated_tests.sh b/run_all_automated_tests.sh new file mode 100755 index 0000000..2c13b16 --- /dev/null +++ b/run_all_automated_tests.sh @@ -0,0 +1,180 @@ +#! /bin/bash + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +ComponentOnly=0 +ForwardedArgs=() +SisUseColours=0 +UnitOnly=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - handled above; forward so category runners see it + ForwardedArgs+=("$1") + ;; + --unit-only) + + UnitOnly=1 + ;; + --component-only) + + ComponentOnly=1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) automated test programs (unit and component) + +${ScriptPath} [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + --component-only + runs only component-test programs + + --unit-only + runs only unit-test programs + + (all other flags are forwarded to the category runner script) + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + ForwardedArgs+=("$1") + ;; + esac + + shift +done + +if [ $UnitOnly -ne 0 ] && [ $ComponentOnly -ne 0 ]; then + + >&2 echo "${ScriptPathClr}: ${SisClr_Red}${SisClr_Bold}--unit-only${SisClr_None} and ${SisClr_Red}${SisClr_Bold}--component-only${SisClr_None} are mutually exclusive" + + exit 1 +fi + + +# ########################################################## +# main() + +status=0 + +if [ $UnitOnly -ne 0 ]; then + + "$Dir/run_all_unit_tests.sh" "${ForwardedArgs[@]}" + exit $? +fi + +if [ $ComponentOnly -ne 0 ]; then + + "$Dir/run_all_component_tests.sh" "${ForwardedArgs[@]}" + exit $? +fi + +echo +echo "Running all ${ProjectNameClr} automated test programs (unit and component)" + +"$Dir/run_all_unit_tests.sh" "${ForwardedArgs[@]}" +status=$? + +if [ $status -eq 0 ]; then + + "$Dir/run_all_component_tests.sh" "${ForwardedArgs[@]}" + status=$? +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/run_all_component_tests.cmd b/run_all_component_tests.cmd new file mode 100644 index 0000000..970c9ba --- /dev/null +++ b/run_all_component_tests.cmd @@ -0,0 +1,94 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% +) ELSE ( + + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build +) + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) component-test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + --component-only ^ + + accepted for compatibility; this script always runs component tests only ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE IF /I {--component-only}=={%%a} ( + + REM Benign: this script is already component-only + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +ECHO Running all %ProjectName% component-test programs + +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*component.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% +) + +ENDLOCAL diff --git a/run_all_component_tests.sh b/run_all_component_tests.sh new file mode 100755 index 0000000..c0bd27e --- /dev/null +++ b/run_all_component_tests.sh @@ -0,0 +1,300 @@ +#! /bin/bash + +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +ListOnly=0 +RunMake=1 +SisUseColours=0 +Verbosity=${XTESTS_VERBOSITY:-${TEST_VERBOSITY:-3}} + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; + --component-only) + + # Benign: this script is already component-only (aggregate / CI may + # pass it) + ;; + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --verbosity) + + shift + Verbosity=$1 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) component-test programs + +${ScriptPath} [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + --component-only + accepted for compatibility; this script always runs component tests + only + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute a build before running programs + + --verbosity + specifies an explicit verbosity, forwarded to each program + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +status=0 + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all component-test programs" + + mkdir -p "$CMakeDir" || exit 1 + + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi + + sis_cmake_build + status=$? + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" + + exit 1 + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo + echo "Listing all ${ProjectNameClr} component-test programs" + else + + echo + echo "Running all ${ProjectNameClr} component-test programs" + fi + + NumPrograms=0 + + while IFS= read -r -d '' f; do + + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac + + NumPrograms=$((NumPrograms + 1)) + + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" + + if [ $ListOnly -ne 0 ]; then + + echo "would execute ${fClr}:" + + continue + fi + + if [ $Verbosity -ge 3 ]; then + + echo + fi + if [ $Verbosity -ge 2 ]; then + + echo "executing ${fClr}:" + fi + + if "$f" --verbosity="$Verbosity"; then + + : + else + + status=$? + + break 1 + fi + done < <(find "$CMakeDir" -type f \( -name 'test_component*' -o -name 'test.component.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no component-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/run_all_examples.cmd b/run_all_examples.cmd new file mode 100644 index 0000000..11273cb --- /dev/null +++ b/run_all_examples.cmd @@ -0,0 +1,89 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% +) ELSE ( + + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build +) + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) example programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +REM Examples that require human input may honour SIS_EXAMPLE_SMOKE for a +REM no-arg built-in tmpfile demo (see example.c.cstring_vector). +SET SIS_EXAMPLE_SMOKE=1 + +ECHO Running all %ProjectName% example programs + +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I example.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% +) + +ENDLOCAL diff --git a/run_all_examples.sh b/run_all_examples.sh index ed97ca8..967f82c 100755 --- a/run_all_examples.sh +++ b/run_all_examples.sh @@ -1,16 +1,119 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 RunMake=1 +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -19,6 +122,10 @@ RunMake=1 while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --list-only|-l) ListOnly=1 @@ -31,21 +138,26 @@ while [[ $# -gt 0 ]]; do [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF -Runs all example programs +Runs all (matching) example programs -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -l --list-only lists the target programs but does not execute them -M --no-make - does not execute CMake and make before running tests + does not execute a build before running programs standard flags: @@ -59,7 +171,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -78,22 +190,28 @@ if [ $RunMake -ne 0 ]; then if [ $ListOnly -eq 0 ]; then - echo "Executing build (via command \`$MakeCmd\`) and then running all example programs" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all example programs" - mkdir -p $CMakeDir || exit 1 + mkdir -p "$CMakeDir" || exit 1 - cd $CMakeDir + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - $MakeCmd - status=$? + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi - cd ->/dev/null + sis_cmake_build + status=$? fi else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + exit 1 fi fi @@ -101,32 +219,62 @@ if [ $status -eq 0 ]; then if [ $ListOnly -ne 0 ]; then - echo "Listing all example programs" + echo + echo "Listing all ${ProjectNameClr} example programs" else - echo "Running all example programs" + echo + echo "Running all ${ProjectNameClr} example programs" fi - for f in $(find $CMakeDir -type f '(' -name 'example.c.*' -o -name 'example.cpp.*' ')' -exec test -x {} \; -print) - do + # Examples that require human input may honour SIS_EXAMPLE_SMOKE for a + # no-arg built-in tmpfile demo (see example.c.cstring_vector). + export SIS_EXAMPLE_SMOKE=1 + + NumPrograms=0 + + while IFS= read -r -d '' f; do + + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac + + NumPrograms=$((NumPrograms + 1)) + + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" if [ $ListOnly -ne 0 ]; then - echo "would execute $f:" + echo "would execute ${fClr}:" continue fi echo - echo "executing $f:" + echo "executing ${fClr}:" - # NOTE: we do not break on fail, because, this being a unit-testing library, the scratch-tests actually fail - $f - done + if "$f"; then + + : + else + + status=$? + + break 1 + fi + done < <(find "$CMakeDir" -type f \( -name 'example*' ! -name '*.md' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no example programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi fi exit $status # ############################## end of file ############################# # - diff --git a/run_all_performance_tests.cmd b/run_all_performance_tests.cmd new file mode 100644 index 0000000..ae97766 --- /dev/null +++ b/run_all_performance_tests.cmd @@ -0,0 +1,85 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% +) ELSE ( + + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build +) + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) performance-test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +ECHO Running all %ProjectName% performance-test programs + +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*performance.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% +) + +ENDLOCAL diff --git a/run_all_performance_tests.sh b/run_all_performance_tests.sh new file mode 100755 index 0000000..3feaaff --- /dev/null +++ b/run_all_performance_tests.sh @@ -0,0 +1,276 @@ +#! /bin/bash + +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} +ProjectNameFile="$Dir/.sis/project_name.txt" +ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") +ScriptPath=$0 + +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} +ListOnly=0 +RunMake=1 +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + + +# ########################################################## +# command-line handling + +while [[ $# -gt 0 ]]; do + + case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; + --list-only|-l) + + ListOnly=1 + ;; + --no-make|-M) + + RunMake=0 + ;; + --help) + + [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" + cat << EOF +Runs all (matching) performance-test programs + +${ScriptPath} [ ... flags/options ... ] + +Flags/options: + + behaviour: + + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + + -l + --list-only + lists the target programs but does not execute them + + -M + --no-make + does not execute a build before running programs + + + standard flags: + + --help + displays this help and terminates + +EOF + + exit 0 + ;; + *) + + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" + + exit 1 + ;; + esac + + shift +done + + +# ########################################################## +# main() + +status=0 + +if [ $RunMake -ne 0 ]; then + + if [ $ListOnly -eq 0 ]; then + + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all performance-test programs" + + mkdir -p "$CMakeDir" || exit 1 + + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi + + sis_cmake_build + status=$? + fi +else + + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" + + exit 1 + fi +fi + +if [ $status -eq 0 ]; then + + if [ $ListOnly -ne 0 ]; then + + echo + echo "Listing all ${ProjectNameClr} performance-test programs" + else + + echo + echo "Running all ${ProjectNameClr} performance-test programs" + fi + + NumPrograms=0 + + while IFS= read -r -d '' f; do + + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac + + NumPrograms=$((NumPrograms + 1)) + + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" + + if [ $ListOnly -ne 0 ]; then + + echo "would execute ${fClr}:" + + continue + fi + + echo + echo "executing ${fClr}:" + + if "$f"; then + + : + else + + status=$? + + break 1 + fi + done < <(find "$CMakeDir" -type f \( -name 'test_performance*' -o -name 'test.performance.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no performance-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi +fi + +exit $status + + +# ############################## end of file ############################# # diff --git a/run_all_scratch_tests.cmd b/run_all_scratch_tests.cmd new file mode 100644 index 0000000..9b05623 --- /dev/null +++ b/run_all_scratch_tests.cmd @@ -0,0 +1,85 @@ +@echo off + +SETLOCAL + +SET SCRIPT_DIRECTORY=%~dp0 +SET SCRIPT_PATH_DOC=%~n0[%~x0] + +IF DEFINED SIS_CMAKE_BUILD_DIR ( + + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% +) ELSE ( + + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build +) + +FOR %%a IN (%*) DO ( + + IF /I {--help}=={%%a} ( + + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( + + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + ) + ECHO ^ + +Runs all ^(matching^) scratch-test programs ^ + +^ + +%SCRIPT_PATH_DOC% [ ... flags/options ... ] ^ + +^ + +Flags/options: ^ + + behaviour: ^ + +^ + + standard flags: ^ + +^ + + --help ^ + + displays this help and terminates ^ + + + EXIT /B 0 + ) ELSE ( + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 + + EXIT /B 1 + ) +) + +if NOT EXIST "%CMAKE_DIR%" ( + + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" + + EXIT /B 1 +) + +SET "ProjectName=" +FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO SET "ProjectName=%%p" + +IF NOT DEFINED ProjectName ( + + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 + + EXIT /B 1 +) + +ECHO Running all %ProjectName% scratch-test programs + +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*scratch.*\.exe$`) DO ( + + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% +) + +ENDLOCAL diff --git a/run_all_scratch_tests.sh b/run_all_scratch_tests.sh index 19b2921..5e6659a 100755 --- a/run_all_scratch_tests.sh +++ b/run_all_scratch_tests.sh @@ -1,16 +1,119 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 RunMake=1 +SisUseColours=0 + + +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} # ########################################################## @@ -19,6 +122,10 @@ RunMake=1 while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --list-only|-l) ListOnly=1 @@ -33,19 +140,24 @@ while [[ $# -gt 0 ]]; do cat << EOF Runs all (matching) scratch-test programs -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -l --list-only lists the target programs but does not execute them -M --no-make - does not execute CMake and make before running tests + does not execute a build before running programs standard flags: @@ -59,7 +171,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -78,22 +190,28 @@ if [ $RunMake -ne 0 ]; then if [ $ListOnly -eq 0 ]; then - echo "Executing build (via command \`$MakeCmd\`) and then running all scratch test programs" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all scratch-test programs" - mkdir -p $CMakeDir || exit 1 + mkdir -p "$CMakeDir" || exit 1 - cd $CMakeDir + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - $MakeCmd - status=$? + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" - cd ->/dev/null + exit 1 + fi + + sis_cmake_build + status=$? fi else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then + + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + exit 1 fi fi @@ -101,37 +219,58 @@ if [ $status -eq 0 ]; then if [ $ListOnly -ne 0 ]; then - echo "Listing all scratch (and performance) test programs" + echo + echo "Listing all ${ProjectNameClr} scratch-test programs" else - echo "Running all scratch (and performance) test programs" + echo + echo "Running all ${ProjectNameClr} scratch-test programs" fi - for f in $(find $CMakeDir -type f '(' -name 'test_scratch*' -o -name 'test.scratch.*' -o -name 'test_performance*' -o -name 'test.performance.*' ')' -exec test -x {} \; -print) - do + NumPrograms=0 + + while IFS= read -r -d '' f; do + + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac + + NumPrograms=$((NumPrograms + 1)) + + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" if [ $ListOnly -ne 0 ]; then - echo "would execute $f:" + echo "would execute ${fClr}:" continue fi echo - echo "executing $f:" + echo "executing ${fClr}:" - if $f; then + if "$f"; then : else status=$? + + break 1 fi - done + done < <(find "$CMakeDir" -type f \( -name 'test_scratch*' -o -name 'test.scratch.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no scratch-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi fi exit $status # ############################## end of file ############################# # - diff --git a/run_all_unit_tests.cmd b/run_all_unit_tests.cmd index b68c97e..18b040a 100755 --- a/run_all_unit_tests.cmd +++ b/run_all_unit_tests.cmd @@ -1,32 +1,29 @@ @echo off -SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION +SETLOCAL SET SCRIPT_DIRECTORY=%~dp0 SET SCRIPT_PATH_DOC=%~n0[%~x0] + IF DEFINED SIS_CMAKE_BUILD_DIR ( - SET "CMAKE_DIR=%SIS_CMAKE_BUILD_DIR%" + SET CMAKE_DIR=%SIS_CMAKE_BUILD_DIR% ) ELSE ( - SET "CMAKE_DIR=%SCRIPT_DIRECTORY%_build" + SET CMAKE_DIR=%SCRIPT_DIRECTORY%_build ) -SET ListOnly=0 -SET Verbose=0 -SET UnitOnly=0 -SET ComponentOnly=0 -SET status=0 - FOR %%a IN (%*) DO ( + IF /I {--help}=={%%a} ( + IF EXIST "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ( - type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" + type "%SCRIPT_DIRECTORY%.sis\script_info_lines.txt" ) ECHO ^ -Runs all ^(matching^) unit-test and/or component-test programs ^ +Runs all ^(matching^) unit-test programs ^ ^ @@ -38,41 +35,11 @@ Flags/options: ^ behaviour: ^ -^ - - -l ^ - - --list-only ^ - - lists the target programs but does not execute them ^ - -^ - - -M ^ - - --no-make ^ - - accepted for parity with the .sh script ^(build is not invoked^) ^ - ^ --unit-only ^ - runs only unit-test programs ^(test.unit.* / test_unit*^) ^ - -^ - - --component-only ^ - - runs only component-test programs ^(test.component.* / test_component*^) ^ - -^ - - -v ^ - - --verbose ^ - - lists each test program before executing it ^ + accepted for compatibility; this script always runs unit tests only ^ ^ @@ -86,41 +53,22 @@ Flags/options: ^ EXIT /B 0 - ) ELSE IF /I {-l}=={%%a} ( - SET ListOnly=1 - ) ELSE IF /I {--list-only}=={%%a} ( - SET ListOnly=1 - ) ELSE IF /I {-M}=={%%a} ( - REM no-op: this .cmd never invokes the build - ) ELSE IF /I {--no-make}=={%%a} ( - REM no-op: this .cmd never invokes the build ) ELSE IF /I {--unit-only}=={%%a} ( - SET UnitOnly=1 - ) ELSE IF /I {--component-only}=={%%a} ( - SET ComponentOnly=1 - ) ELSE IF /I {-v}=={%%a} ( - SET Verbose=1 - ) ELSE IF /I {--verbose}=={%%a} ( - SET Verbose=1 + + REM Benign: this script is already unit-only ) ELSE ( - ECHO %SCRIPT_PATH_DOC%: unrecognised argument '%%a'; use --help for usage 1>&2 + + ECHO "%SCRIPT_DIRECTORY%: unrecognised argument '%%a'; use --help for usage" 1>&2 EXIT /B 1 ) ) -IF !UnitOnly! EQU 1 IF !ComponentOnly! EQU 1 ( - - ECHO %SCRIPT_PATH_DOC%: --unit-only and --component-only are mutually exclusive 1>&2 - - EXIT /B 1 -) - -IF NOT EXIST "%CMAKE_DIR%" ( +if NOT EXIST "%CMAKE_DIR%" ( - ECHO %SCRIPT_PATH_DOC%: CMake build directory '%CMAKE_DIR%' does not exist 1>&2 + ECHO "CMake build directory '%CMAKE_DIR%' does not exist" - EXIT /B 1 + EXIT /B 1 ) SET "ProjectName=" @@ -128,61 +76,19 @@ FOR /F "usebackq delims=" %%p IN ("%SCRIPT_DIRECTORY%.sis\project_name.txt") DO IF NOT DEFINED ProjectName ( - ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 - - EXIT /B 1 -) - -IF !UnitOnly! EQU 1 ( - - SET "TestKindDescription=unit test" -) ELSE IF !ComponentOnly! EQU 1 ( - - SET "TestKindDescription=component test" -) ELSE ( + ECHO %SCRIPT_PATH_DOC%: could not read project name from .sis\project_name.txt 1>&2 - SET "TestKindDescription=component and unit test" + EXIT /B 1 ) -IF !ListOnly! EQU 1 ( - - ECHO Listing all !ProjectName! !TestKindDescription! programs -) ELSE ( +ECHO Running all %ProjectName% unit-test programs - ECHO Running all !ProjectName! !TestKindDescription! programs -) +FOR /F "usebackq" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%" ^| FINDSTR /I test.*unit.*\.exe$`) DO ( -IF !UnitOnly! EQU 1 ( - - SET "FindPattern=test\.unit\..*\.exe$" -) ELSE IF !ComponentOnly! EQU 1 ( - - SET "FindPattern=test\.component\..*\.exe$" -) ELSE ( - - SET "FindPattern=test\.unit\..*\.exe$ test\.component\..*\.exe$" -) - -FOR /F "usebackq delims=" %%f IN (`DIR /A:-D /B /S "%CMAKE_DIR%\*.exe" 2^>NUL ^| FINDSTR /I /R "!FindPattern!"`) DO ( - IF !ListOnly! EQU 1 ( - - ECHO would execute %%f: - ) ELSE ( - - IF !Verbose! EQU 1 ( - - ECHO executing %%f: - ) - - "%%f" - IF ERRORLEVEL 1 ( - - SET status=1 - - GOTO :done - ) - ) + ECHO . + ECHO executing %%f + %%f + IF ERRORLEVEL 1 EXIT /B %ERRORLEVEL% ) -:done -EXIT /B !status! +ENDLOCAL diff --git a/run_all_unit_tests.sh b/run_all_unit_tests.sh index 8c22a3a..301ccae 100755 --- a/run_all_unit_tests.sh +++ b/run_all_unit_tests.sh @@ -1,27 +1,132 @@ #! /bin/bash -ScriptPath=$0 -Dir=$(cd "$(dirname "$ScriptPath")" && pwd) +# ########################################################## +# functions - 1 + +sis_cmake_is_truey() { + case "$(printf '%s' "${1:-}" | tr '[:upper:]' '[:lower:]')" in + + 1|ok|on|true|yes|y) + + return 0 + ;; + *) + + return 1 + ;; + esac +} + + +# ########################################################## +# constants and variables + +Basename=$(basename "$0") +Dir=$(cd "$(dirname "$0")" && pwd) +CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} ProjectNameFile="$Dir/.sis/project_name.txt" ProjectName=$(tr -d '[:space:]' < "$ProjectNameFile") -Basename=$(basename "$ScriptPath") -CMakeDir=${SIS_CMAKE_BUILD_DIR:-$Dir/_build} -[[ -n "$MSYSTEM" ]] && DefaultMakeCmd=mingw32-make.exe || DefaultMakeCmd=make -MakeCmd=${SIS_CMAKE_MAKE_COMMAND:-${SIS_CMAKE_COMMAND:-$DefaultMakeCmd}} +ScriptPath=$0 +AlwaysUseColours=${SIS_CMAKE_ALWAYS_USE_COLOURS:-${SIS_ALWAYS_USE_COLOURS:-0}} ListOnly=0 RunMake=1 -UnitOnly=0 -ComponentOnly=0 +SisUseColours=0 Verbosity=${XTESTS_VERBOSITY:-${TEST_VERBOSITY:-3}} +# ########################################################## +# colours +# +# Enable when tput is available and either: +# - AlwaysUseColours is set (overrides NO_COLOR; may set TERM if +# empty/dumb), or +# - NO_COLOR is unset, stdout is a TTY, and TERM is not dumb (union of +# collect-c's "TERM set + TTY" and cstring's "TTY" — empty TERM on a +# TTY is OK). + +SisClr_Blue= +SisClr_Bold= +SisClr_Green= +SisClr_None= +SisClr_Red= +SisClr_Yellow= + +for arg in "$@"; do + + case $arg in + --always-use-colors|--always-use-colours|-A) + + AlwaysUseColours=1 + ;; + esac +done + +if command -v tput >/dev/null 2>&1; then + + if [ $AlwaysUseColours -ne 0 ]; then + + if [ -z "${TERM:-}" ] || [ "$TERM" = "dumb" ]; then + + TERM=xterm-256color + fi + + SisUseColours=1 + elif [ -z "${NO_COLOR:-}" ] && [ -t 1 ] && [ "${TERM:-}" != "dumb" ]; then + + SisUseColours=1 + fi +fi + +if [ $SisUseColours -ne 0 ]; then + + SisClr_Blue=${FG_BLUE:-$(tput setaf 4)} + SisClr_Bold=${FD_BOLD:-$(tput bold)} + SisClr_Green=${FG_GREEN:-$(tput setaf 2)} + SisClr_None=${FD_NONE:-$(tput sgr0)} + SisClr_Red=${FG_RED:-$(tput setaf 1)} + SisClr_Yellow=${FG_YELLOW:-$(tput setaf 3)} +fi + +CMakeDirClr="${SisClr_Blue}${SisClr_Bold}${CMakeDir}${SisClr_None}" +ProjectNameClr="${SisClr_Blue}${SisClr_Bold}${ProjectName}${SisClr_None}" +ScriptPathClr="${SisClr_Blue}${SisClr_Bold}${ScriptPath}${SisClr_None}" + + +# ########################################################## +# functions - 2 + +sis_cmake_build() { + + local config="${SIS_CMAKE_CONFIG:-Release}" + local args=(--build "$CMakeDir") + if [ -f "$CMakeDir/CMakeCache.txt" ] && grep -q '^CMAKE_CONFIGURATION_TYPES:' "$CMakeDir/CMakeCache.txt" 2>/dev/null; then + + args+=(--config "$config") + fi + if [ "$#" -gt 0 ]; then + + local t + for t in "$@"; do + + args+=(--target "$t") + done + fi + + cmake "${args[@]}" +} + + # ########################################################## # command-line handling while [[ $# -gt 0 ]]; do case $1 in + --always-use-colors|--always-use-colours|-A) + + # AlwaysUseColours=1 - this is handled by the for loop above + ;; --list-only|-l) ListOnly=1 @@ -32,11 +137,7 @@ while [[ $# -gt 0 ]]; do ;; --unit-only) - UnitOnly=1 - ;; - --component-only) - - ComponentOnly=1 + # Benign: this script is already unit-only (aggregate / CI may pass it) ;; --verbosity) @@ -47,30 +148,32 @@ while [[ $# -gt 0 ]]; do [ -f "$Dir/.sis/script_info_lines.txt" ] && cat "$Dir/.sis/script_info_lines.txt" cat << EOF -Runs all (matching) unit-test and/or component-test programs +Runs all (matching) unit-test programs -$ScriptPath [ ... flags/options ... ] +${ScriptPath} [ ... flags/options ... ] Flags/options: behaviour: + -A + --always-use-colors + --always-use-colours + forces use of colours even when stdout is not a TTY + -l --list-only lists the target programs but does not execute them -M --no-make - does not execute CMake and make before running tests + does not execute a build before running programs --unit-only - runs only unit-test programs (test.unit.* / test_unit*) - - --component-only - runs only component-test programs (test.component.* / test_component*) + accepted for compatibility; this script always runs unit tests only --verbosity - specifies an explicit verbosity for the unit-test(s) + specifies an explicit verbosity, forwarded to each program standard flags: @@ -84,7 +187,7 @@ EOF ;; *) - >&2 echo "$ScriptPath: unrecognised argument '$1'; use --help for usage" + >&2 echo "${ScriptPathClr}: unrecognised argument '${SisClr_Red}${SisClr_Bold}$1${SisClr_None}'; use --help for usage" exit 1 ;; @@ -93,50 +196,36 @@ EOF shift done -if [ $UnitOnly -ne 0 ] && [ $ComponentOnly -ne 0 ]; then - - >&2 echo "$ScriptPath: --unit-only and --component-only are mutually exclusive" - - exit 1 -fi - # ########################################################## # main() status=0 -if [ $UnitOnly -ne 0 ]; then - - TestKindDescription='unit test' -elif [ $ComponentOnly -ne 0 ]; then - - TestKindDescription='component test' -else - - TestKindDescription='component and unit test' -fi - if [ $RunMake -ne 0 ]; then if [ $ListOnly -eq 0 ]; then - echo "Executing build (via command \`$MakeCmd\`) and then running all ${TestKindDescription} programs" + echo + echo "Executing build of ${ProjectNameClr} (via cmake --build) and then running all unit-test programs" - mkdir -p $CMakeDir || exit 1 + mkdir -p "$CMakeDir" || exit 1 - cd $CMakeDir + if [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - $MakeCmd - status=$? + >&2 echo "${ScriptPathClr}: '${CMakeDirClr}' is not configured; use prepare_cmake.sh first" + + exit 1 + fi - cd ->/dev/null + sis_cmake_build + status=$? fi else - if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ] || [ ! -d "$CMakeDir/CMakeFiles" ]; then + if [ ! -d "$CMakeDir" ] || [ ! -f "$CMakeDir/CMakeCache.txt" ]; then - >&2 echo "$ScriptPath: cannot run in '--no-make' mode without a previous successful build step" + >&2 echo "${ScriptPathClr}: cannot run in '--no-make' mode without a previous successful configure/build" exit 1 fi @@ -146,29 +235,31 @@ if [ $status -eq 0 ]; then if [ $ListOnly -ne 0 ]; then - echo "Listing all ${TestKindDescription} programs" + echo + echo "Listing all ${ProjectNameClr} unit-test programs" else - echo "Running all ${TestKindDescription} programs" + echo + echo "Running all ${ProjectNameClr} unit-test programs" fi - if [ $UnitOnly -ne 0 ]; then + NumPrograms=0 - find_name_expr=( \( -name 'test_unit*' -o -name 'test.unit.*' \) ) - elif [ $ComponentOnly -ne 0 ]; then + while IFS= read -r -d '' f; do - find_name_expr=( \( -name 'test_component*' -o -name 'test.component.*' \) ) - else + case "$f" in + *.pdb|*.ilk|*.log|*.obj|*.o) + continue + ;; + esac - find_name_expr=( \( -name 'test_unit*' -o -name 'test.unit.*' -o -name 'test_component*' -o -name 'test.component.*' \) ) - fi + NumPrograms=$((NumPrograms + 1)) - for f in $(find "$CMakeDir" -type f "${find_name_expr[@]}" -exec test -x {} \; -print | sort) - do + fClr="${SisClr_Blue}${SisClr_Bold}${f}${SisClr_None}" if [ $ListOnly -ne 0 ]; then - echo "would execute $f:" + echo "would execute ${fClr}:" continue fi @@ -179,10 +270,10 @@ if [ $status -eq 0 ]; then fi if [ $Verbosity -ge 2 ]; then - echo "executing $f:" + echo "executing ${fClr}:" fi - if $f --verbosity=$Verbosity; then + if "$f" --verbosity="$Verbosity"; then : else @@ -191,7 +282,14 @@ if [ $status -eq 0 ]; then break 1 fi - done + done < <(find "$CMakeDir" -type f \( -name 'test_unit*' -o -name 'test.unit.*' \) \( -perm -100 -o -name '*.exe' \) -print0 2>/dev/null | sort -z) + + if [ $NumPrograms -eq 0 ]; then + + echo "${ScriptPathClr}: found no unit-test programs under '${CMakeDirClr}' (none found)" + + exit 0 + fi fi exit $status diff --git a/test/scratch/versions/CMakeLists.txt b/test/scratch/versions/CMakeLists.txt index 8db359b..5b5ed67 100644 --- a/test/scratch/versions/CMakeLists.txt +++ b/test/scratch/versions/CMakeLists.txt @@ -1 +1 @@ -define_example_program(versions main.c) +define_example_program(test.scratch.versions main.c) From a6f274a0c8c0d84b1df12a3146c75c7d5406f3f0 Mon Sep 17 00:00:00 2001 From: Matt Wilson Date: Sat, 10 Oct 2026 09:01:07 +1100 Subject: [PATCH 9/9] ci(cmpfs): run component tests via run_all_component_tests.sh - replace run_all_unit_tests.sh -M --component-only, which is not an accepted option, with run_all_component_tests.sh -M; --- .github/workflows/ci-cell.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci-cell.yml b/.github/workflows/ci-cell.yml index dc1f587..cd836e4 100644 --- a/.github/workflows/ci-cell.yml +++ b/.github/workflows/ci-cell.yml @@ -297,7 +297,7 @@ jobs: if [ "${{ inputs.c-compiler }}" = "mingw" ]; then export PATH="/mingw64/bin:$PATH" fi - SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_unit_tests.sh -M --component-only + SIS_CMAKE_BUILD_DIR="${{ github.workspace }}/build" ./run_all_component_tests.sh -M test-scratch: name: Scratch tests (${{ inputs.cell-id }})