From e39e2843be3b6956bf21c1295502a7abf673f60d Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Thu, 2 Jul 2026 19:15:28 +0800 Subject: [PATCH 01/11] test: cover toolchain wrapper failure propagation --- .../tests/test_wrapper_failure_propagation.sh | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100755 toolchain/tests/test_wrapper_failure_propagation.sh diff --git a/toolchain/tests/test_wrapper_failure_propagation.sh b/toolchain/tests/test_wrapper_failure_propagation.sh new file mode 100755 index 0000000000..5e33ebb243 --- /dev/null +++ b/toolchain/tests/test_wrapper_failure_propagation.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" +TOOLCHAIN_DIR="${REPO_ROOT}/toolchain" +FAILURES=0 + +fail() { + printf 'FAIL: %s\n' "$*" >&2 + FAILURES=$((FAILURES + 1)) +} + +assert_file_contains() { + local file="$1" + local text="$2" + if ! grep -Fq "$text" "$file"; then + fail "${file} does not contain expected text: ${text}" + fi +} + +test_runner_preserves_command_failure() { + # shellcheck source=/dev/null + source "${TOOLCHAIN_DIR}/scripts/lib/wrapper_runner.sh" + + local tmpdir log status + tmpdir="$(mktemp -d)" + log="${tmpdir}/compile.log" + + run_toolchain_with_log "$log" bash -c 'printf "installer stdout\n"; exit 37' + status=$? + + if [[ "$status" -ne 37 ]]; then + fail "run_toolchain_with_log returned ${status}; expected 37" + fi + assert_file_contains "$log" "installer stdout" + + rm -rf "$tmpdir" +} + +test_wrappers_use_runner() { + local wrappers=( + "${TOOLCHAIN_DIR}/toolchain_gnu.sh" + "${TOOLCHAIN_DIR}/toolchain_intel.sh" + "${TOOLCHAIN_DIR}/toolchain_gcc-mkl.sh" + "${TOOLCHAIN_DIR}/toolchain_gcc-aocl.sh" + "${TOOLCHAIN_DIR}/toolchain_aocc-aocl.sh" + ) + + local wrapper + for wrapper in "${wrappers[@]}"; do + assert_file_contains "$wrapper" 'source "${SCRIPT_DIR}/scripts/lib/wrapper_runner.sh"' + assert_file_contains "$wrapper" 'run_toolchain_with_log compile.log ./install_abacus_toolchain_new.sh' + + if grep -Eq '\|\s*tee[[:space:]]+compile\.log' "$wrapper"; then + fail "${wrapper} still contains a raw pipe to tee compile.log" + fi + + if grep -Eq '^exec[[:space:]]+\./install_abacus_toolchain_new\.sh' "$wrapper"; then + fail "${wrapper} still execs the installer directly" + fi + done +} + +test_runner_preserves_command_failure +test_wrappers_use_runner + +if [[ "$FAILURES" -ne 0 ]]; then + printf '%s wrapper failure propagation test(s) failed\n' "$FAILURES" >&2 + exit 1 +fi + +printf 'wrapper failure propagation tests passed\n' From 934515fd646e5e5a8020239d72a8ae0548f39d04 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Thu, 2 Jul 2026 19:37:20 +0800 Subject: [PATCH 02/11] fix: preserve toolchain wrapper installer failures --- toolchain/scripts/lib/wrapper_runner.sh | 11 +++++++++++ toolchain/toolchain_aocc-aocl.sh | 8 +++++--- toolchain/toolchain_gcc-aocl.sh | 8 +++++--- toolchain/toolchain_gcc-mkl.sh | 8 +++++--- toolchain/toolchain_gnu.sh | 9 ++++++--- toolchain/toolchain_intel.sh | 8 +++++--- 6 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 toolchain/scripts/lib/wrapper_runner.sh diff --git a/toolchain/scripts/lib/wrapper_runner.sh b/toolchain/scripts/lib/wrapper_runner.sh new file mode 100644 index 0000000000..81adb56c1a --- /dev/null +++ b/toolchain/scripts/lib/wrapper_runner.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash + +run_toolchain_with_log() { + local log_file="$1" + shift + + "$@" | tee "$log_file" + local installer_status=${PIPESTATUS[0]} + + return "$installer_status" +} diff --git a/toolchain/toolchain_aocc-aocl.sh b/toolchain/toolchain_aocc-aocl.sh index bfc4b4bc1a..83ad0a1c84 100755 --- a/toolchain/toolchain_aocc-aocl.sh +++ b/toolchain/toolchain_aocc-aocl.sh @@ -5,6 +5,9 @@ #SBATCH -o compile.log #SBATCH -e compile.err +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +source "${SCRIPT_DIR}/scripts/lib/wrapper_runner.sh" + # Users can easily modify these parameters to customize the build # Before running this script, ensure you have loaded your system packages @@ -84,7 +87,7 @@ LIBTORCH_VERSION="main" # main=2.1.2, alt=1.12.1 (use alt for older GLIBC) # ============================================================================ # Call the main installation script with configured parameters -exec ./install_abacus_toolchain_new.sh \ +run_toolchain_with_log compile.log ./install_abacus_toolchain_new.sh \ --with-amd="$WITH_AMD" \ --with-gcc="$WITH_GCC" \ --math-mode="$MATH_MODE" \ @@ -115,5 +118,4 @@ exec ./install_abacus_toolchain_new.sh \ ${PACK_RUN_MODE:+$([ "$PACK_RUN_MODE" = "yes" ] && echo "--pack-run")} \ ${ENABLE_CUDA:+--enable-cuda} \ ${GPU_VERSION:+--gpu-ver="$GPU_VERSION"} \ - "$@" \ - | tee compile.log + "$@" diff --git a/toolchain/toolchain_gcc-aocl.sh b/toolchain/toolchain_gcc-aocl.sh index f77b533989..1238defd36 100755 --- a/toolchain/toolchain_gcc-aocl.sh +++ b/toolchain/toolchain_gcc-aocl.sh @@ -5,6 +5,9 @@ #SBATCH -o compile.log #SBATCH -e compile.err +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +source "${SCRIPT_DIR}/scripts/lib/wrapper_runner.sh" + # Users can easily modify these parameters to customize the build # Before running this script, ensure you have loaded your system packages @@ -81,7 +84,7 @@ LIBTORCH_VERSION="main" # main=2.1.2, alt=1.12.1 (use alt for older GLIBC) # ============================================================================ # Call the main installation script with configured parameters -exec ./install_abacus_toolchain_new.sh \ +run_toolchain_with_log compile.log ./install_abacus_toolchain_new.sh \ --with-gcc="$WITH_GCC" \ --with-amd="$WITH_AMD" \ --math-mode="$MATH_MODE" \ @@ -111,5 +114,4 @@ exec ./install_abacus_toolchain_new.sh \ ${PACK_RUN_MODE:+$([ "$PACK_RUN_MODE" = "yes" ] && echo "--pack-run")} \ ${ENABLE_CUDA:+--enable-cuda} \ ${GPU_VERSION:+--gpu-ver="$GPU_VERSION"} \ - "$@" \ - | tee compile.log + "$@" diff --git a/toolchain/toolchain_gcc-mkl.sh b/toolchain/toolchain_gcc-mkl.sh index bac479c38f..df0fc04d10 100755 --- a/toolchain/toolchain_gcc-mkl.sh +++ b/toolchain/toolchain_gcc-mkl.sh @@ -5,6 +5,9 @@ #SBATCH -o compile.log #SBATCH -e compile.err +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +source "${SCRIPT_DIR}/scripts/lib/wrapper_runner.sh" + # Users can easily modify these parameters to customize the build # Before running this script, ensure you have loaded your system packages @@ -84,7 +87,7 @@ LIBTORCH_VERSION="main" # main=2.1.2, alt=1.12.1 (use alt for older GLIBC) # ============================================================================ # Call the main installation script with configured parameters -exec ./install_abacus_toolchain_new.sh \ +run_toolchain_with_log compile.log ./install_abacus_toolchain_new.sh \ --with-gcc="$WITH_GCC" \ --math-mode="$MATH_MODE" \ --mpi-mode="$MPI_MODE" \ @@ -114,5 +117,4 @@ exec ./install_abacus_toolchain_new.sh \ ${PACK_RUN_MODE:+$([ "$PACK_RUN_MODE" = "yes" ] && echo "--pack-run")} \ ${ENABLE_CUDA:+--enable-cuda} \ ${GPU_VERSION:+--gpu-ver="$GPU_VERSION"} \ - "$@" \ - | tee compile.log + "$@" diff --git a/toolchain/toolchain_gnu.sh b/toolchain/toolchain_gnu.sh index a934fed018..e297c0e453 100755 --- a/toolchain/toolchain_gnu.sh +++ b/toolchain/toolchain_gnu.sh @@ -4,6 +4,10 @@ #SBATCH -n 16 #SBATCH -o compile.log #SBATCH -e compile.err + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +source "${SCRIPT_DIR}/scripts/lib/wrapper_runner.sh" + # Users can easily modify these parameters to customize the build # Before running this script, ensure you have loaded your system packages @@ -84,7 +88,7 @@ LIBTORCH_VERSION="main" # main=2.1.2, alt=1.12.1 (use alt for older GLIBC) # ============================================================================ # Call the main installation script with configured parameters -exec ./install_abacus_toolchain_new.sh \ +run_toolchain_with_log compile.log ./install_abacus_toolchain_new.sh \ --with-gcc="$WITH_GCC" \ --with-intel="$WITH_INTEL" \ --with-amd="$WITH_AMD" \ @@ -119,5 +123,4 @@ exec ./install_abacus_toolchain_new.sh \ ${PACK_RUN_MODE:+$([ "$PACK_RUN_MODE" = "yes" ] && echo "--pack-run")} \ ${ENABLE_CUDA:+--enable-cuda} \ ${GPU_VERSION:+--gpu-ver="$GPU_VERSION"} \ - "$@" \ - | tee compile.log + "$@" diff --git a/toolchain/toolchain_intel.sh b/toolchain/toolchain_intel.sh index ab40cf55b2..9f854a0b4a 100755 --- a/toolchain/toolchain_intel.sh +++ b/toolchain/toolchain_intel.sh @@ -5,6 +5,9 @@ #SBATCH -o compile.log #SBATCH -e compile.err +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +source "${SCRIPT_DIR}/scripts/lib/wrapper_runner.sh" + # Users can easily modify these parameters to customize the build # Before running this script, ensure you have loaded your system packages @@ -103,7 +106,7 @@ LIBTORCH_VERSION="main" # main=2.1.2, alt=1.12.1 (use alt for older GLIBC) # ============================================================================ # Call the main installation script with configured parameters -exec ./install_abacus_toolchain_new.sh \ +run_toolchain_with_log compile.log ./install_abacus_toolchain_new.sh \ --with-intel="$WITH_INTEL" \ --with-gcc="$WITH_GCC" \ --math-mode="$MATH_MODE" \ @@ -136,5 +139,4 @@ exec ./install_abacus_toolchain_new.sh \ ${PACK_RUN_MODE:+$([ "$PACK_RUN_MODE" = "yes" ] && echo "--pack-run")} \ ${ENABLE_CUDA:+--enable-cuda} \ ${GPU_VERSION:+--gpu-ver="$GPU_VERSION"} \ - "$@" \ - | tee compile.log + "$@" From b65c3180e5f00fa35046e87d593da904e1e90f89 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Thu, 2 Jul 2026 19:59:39 +0800 Subject: [PATCH 03/11] test: cover toolchain argument failure exits --- .../tests/test_installer_argument_failures.sh | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100755 toolchain/tests/test_installer_argument_failures.sh diff --git a/toolchain/tests/test_installer_argument_failures.sh b/toolchain/tests/test_installer_argument_failures.sh new file mode 100755 index 0000000000..2ffd89e016 --- /dev/null +++ b/toolchain/tests/test_installer_argument_failures.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env bash +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" +TOOLCHAIN_DIR="${REPO_ROOT}/toolchain" +FAILURES=0 + +fail() { + printf 'FAIL: %s\n' "$*" >&2 + FAILURES=$((FAILURES + 1)) +} + +copy_toolchain() { + local tmpdir="$1" + local entry name + mkdir -p "${tmpdir}/toolchain" + while IFS= read -r -d '' entry; do + name="${entry##*/}" + case "$name" in + build|install) continue ;; + esac + cp -a "$entry" "${tmpdir}/toolchain/" + done < <(find "${TOOLCHAIN_DIR}" -mindepth 1 -maxdepth 1 -print0) +} + +run_installer_in_copy() { + local tmpdir="$1" + shift + (cd "${tmpdir}/toolchain" && ./install_abacus_toolchain_new.sh "$@") >"${tmpdir}/output.log" 2>&1 +} + +assert_invalid_input_fails() { + local name="$1" + local expected_text="$2" + shift 2 + + local tmpdir status + tmpdir="$(mktemp -d)" + copy_toolchain "$tmpdir" + + run_installer_in_copy "$tmpdir" "$@" + status=$? + + if [[ "$status" -eq 0 ]]; then + cat "${tmpdir}/output.log" >&2 + fail "${name} exited 0; expected nonzero" + fi + + if ! grep -Fq -- "$expected_text" "${tmpdir}/output.log"; then + cat "${tmpdir}/output.log" >&2 + fail "${name} did not report expected error: ${expected_text}" + fi + + if [[ -e "${tmpdir}/toolchain/install/setup" ]]; then + fail "${name} wrote install/setup even though argument parsing failed" + fi + + rm -rf "$tmpdir" +} + +assert_valid_help_succeeds() { + local tmpdir status + tmpdir="$(mktemp -d)" + copy_toolchain "$tmpdir" + + run_installer_in_copy "$tmpdir" --help + status=$? + + if [[ "$status" -ne 0 ]]; then + cat "${tmpdir}/output.log" >&2 + fail "--help exited ${status}; expected 0" + fi + + if ! grep -Fq "install_abacus_toolchain_new.sh [OPTIONS]" "${tmpdir}/output.log"; then + cat "${tmpdir}/output.log" >&2 + fail "--help output did not contain usage text" + fi + + rm -rf "$tmpdir" +} + +assert_invalid_input_fails "invalid package version" "Invalid package version format" --dry-run --package-version bad:wrong +assert_invalid_input_fails "missing package version value" "--package-version requires at least one package:version argument" --dry-run --package-version +assert_invalid_input_fails "invalid mpi mode" "Invalid MPI mode: invalid" --dry-run --mpi-mode invalid +assert_valid_help_succeeds + +if [[ "$FAILURES" -ne 0 ]]; then + printf '%s installer argument failure test(s) failed\n' "$FAILURES" >&2 + exit 1 +fi + +printf 'installer argument failure tests passed\n' From 53d1f77ea0728a43ea5229252b1680172ab22bc1 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Thu, 2 Jul 2026 20:49:15 +0800 Subject: [PATCH 04/11] fix: propagate toolchain argument parsing failures --- toolchain/install_abacus_toolchain_new.sh | 2 +- toolchain/scripts/lib/config_manager.sh | 42 ++++++++++++------- .../tests/test_installer_argument_failures.sh | 36 ++++++++++++++++ 3 files changed, 64 insertions(+), 16 deletions(-) diff --git a/toolchain/install_abacus_toolchain_new.sh b/toolchain/install_abacus_toolchain_new.sh index 0f0d85d42e..cbcd438558 100755 --- a/toolchain/install_abacus_toolchain_new.sh +++ b/toolchain/install_abacus_toolchain_new.sh @@ -50,7 +50,7 @@ main() { # Initialize configuration with command line arguments if ! config_init "${args[@]}"; then show_help - exit 0 + exit 1 fi # Handle special version-related requests diff --git a/toolchain/scripts/lib/config_manager.sh b/toolchain/scripts/lib/config_manager.sh index fc7ca30683..249e651556 100644 --- a/toolchain/scripts/lib/config_manager.sh +++ b/toolchain/scripts/lib/config_manager.sh @@ -456,13 +456,13 @@ config_validate() { if [[ -n "${CONFIG_CACHE[NPROCS_OVERWRITE]}" ]]; then if ! [[ "${CONFIG_CACHE[NPROCS_OVERWRITE]}" =~ ^[0-9]+$ ]]; then report_error ${LINENO} "Invalid number of processes: ${CONFIG_CACHE[NPROCS_OVERWRITE]}" - exit 1 + return 1 fi fi if ! [[ "${CONFIG_CACHE[LOG_LINES]}" =~ ^[0-9]+$ ]]; then report_error ${LINENO} "Invalid log lines value: ${CONFIG_CACHE[LOG_LINES]}" - exit 1 + return 1 fi # Validate GPU version - support only numeric formats @@ -476,7 +476,7 @@ config_validate() { CONFIG_CACHE["ARCH_NUM"]="$arch_num" else report_error ${LINENO} "Invalid GPU version: $gpu_ver. Supported formats: numeric with decimal (6.0, 7.0, 8.0, 8.9, etc.) or numeric without decimal (60, 70, 80, 89, etc.)" - exit 1 + return 1 fi else CONFIG_CACHE["ARCH_NUM"]="no" @@ -1166,27 +1166,37 @@ config_parse_arguments() { config_init() { # Set defaults first config_set_defaults - + # Initialize version helper to ensure VERSION_STRATEGY defaults are set if command -v version_helper_init > /dev/null 2>&1; then version_helper_init fi - + # Load configuration from file (if available) - this will override defaults - config_load_from_file - + if ! config_load_from_file; then + return 1 + fi + # Apply mode-based configurations from file - this will override defaults - config_apply_modes_from_file - + if ! config_apply_modes_from_file; then + return 1 + fi + # Parse command line arguments - this will override file settings - config_parse_arguments "$@" - + if ! config_parse_arguments "$@"; then + return 1 + fi + # Apply mode-based configurations from command line - config_apply_modes - + if ! config_apply_modes; then + return 1 + fi + # Validate configuration - config_validate - + if ! config_validate; then + return 1 + fi + return 0 } @@ -1262,4 +1272,6 @@ config_apply_modes() { ;; esac fi + + return 0 } diff --git a/toolchain/tests/test_installer_argument_failures.sh b/toolchain/tests/test_installer_argument_failures.sh index 2ffd89e016..48c153dad8 100755 --- a/toolchain/tests/test_installer_argument_failures.sh +++ b/toolchain/tests/test_installer_argument_failures.sh @@ -51,6 +51,11 @@ assert_invalid_input_fails() { fail "${name} did not report expected error: ${expected_text}" fi + if ! grep -Fq "install_abacus_toolchain_new.sh [OPTIONS]" "${tmpdir}/output.log"; then + cat "${tmpdir}/output.log" >&2 + fail "${name} output did not contain usage text" + fi + if [[ -e "${tmpdir}/toolchain/install/setup" ]]; then fail "${name} wrote install/setup even though argument parsing failed" fi @@ -58,6 +63,35 @@ assert_invalid_input_fails() { rm -rf "$tmpdir" } +assert_valid_dry_run_succeeds() { + local name="$1" + shift + + local tmpdir status + tmpdir="$(mktemp -d)" + copy_toolchain "$tmpdir" + + run_installer_in_copy "$tmpdir" "$@" + status=$? + + if [[ "$status" -ne 0 ]]; then + cat "${tmpdir}/output.log" >&2 + fail "${name} exited ${status}; expected 0" + fi + + if ! grep -Fq "Configuration files generated successfully (dry-run mode)" "${tmpdir}/output.log"; then + cat "${tmpdir}/output.log" >&2 + fail "${name} output did not contain dry-run success text" + fi + + if grep -Fq "Attempting secure download" "${tmpdir}/output.log"; then + cat "${tmpdir}/output.log" >&2 + fail "${name} attempted a package download during dry-run" + fi + + rm -rf "$tmpdir" +} + assert_valid_help_succeeds() { local tmpdir status tmpdir="$(mktemp -d)" @@ -82,6 +116,8 @@ assert_valid_help_succeeds() { assert_invalid_input_fails "invalid package version" "Invalid package version format" --dry-run --package-version bad:wrong assert_invalid_input_fails "missing package version value" "--package-version requires at least one package:version argument" --dry-run --package-version assert_invalid_input_fails "invalid mpi mode" "Invalid MPI mode: invalid" --dry-run --mpi-mode invalid +assert_invalid_input_fails "invalid gpu version" "Invalid GPU version" --dry-run --gpu-ver bad +assert_valid_dry_run_succeeds "explicit system openblas dry-run" --dry-run --with-openblas=system assert_valid_help_succeeds if [[ "$FAILURES" -ne 0 ]]; then From 077ed5be4ec04f55dffe4e3c4d08b14c3e2fbd18 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Thu, 2 Jul 2026 21:48:46 +0800 Subject: [PATCH 05/11] test: cover RapidJSON CMake package compatibility --- toolchain/tests/test_rapidjson_cmake.sh | 165 ++++++++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100755 toolchain/tests/test_rapidjson_cmake.sh diff --git a/toolchain/tests/test_rapidjson_cmake.sh b/toolchain/tests/test_rapidjson_cmake.sh new file mode 100755 index 0000000000..0c68fa38c2 --- /dev/null +++ b/toolchain/tests/test_rapidjson_cmake.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" +FAILURES=0 + +fail() { + printf 'FAIL: %s\n' "$*" >&2 + FAILURES=$((FAILURES + 1)) +} + +write_lowercase_target_package() { + local prefix="$1" + mkdir -p "${prefix}/include/rapidjson" "${prefix}/lib/cmake/RapidJSON" + printf '#pragma once\n' >"${prefix}/include/rapidjson/document.h" + cat >"${prefix}/lib/cmake/RapidJSON/RapidJSONConfig.cmake" <<'EOF' +get_filename_component(RapidJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_rapidjson_prefix "${RapidJSON_CMAKE_DIR}/../../.." ABSOLUTE) +set(RapidJSON_INCLUDE_DIR "${_rapidjson_prefix}/include") +set(RapidJSON_INCLUDE_DIRS "${RapidJSON_INCLUDE_DIR}") +if(NOT TARGET rapidjson) + add_library(rapidjson INTERFACE IMPORTED) + set_property(TARGET rapidjson PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${RapidJSON_INCLUDE_DIRS}") +endif() +EOF +} + +write_variable_only_package() { + local prefix="$1" + mkdir -p "${prefix}/include/rapidjson" "${prefix}/lib/cmake/RapidJSON" + printf '#pragma once\n' >"${prefix}/include/rapidjson/document.h" + cat >"${prefix}/lib/cmake/RapidJSON/RapidJSONConfig.cmake" <<'EOF' +get_filename_component(RapidJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_rapidjson_prefix "${RapidJSON_CMAKE_DIR}/../../.." ABSOLUTE) +set(RapidJSON_INCLUDE_DIR "${_rapidjson_prefix}/include") +set(RapidJSON_INCLUDE_DIRS "${RapidJSON_INCLUDE_DIR}") +EOF +} + +write_target_test_project() { + local project_dir="$1" + mkdir -p "$project_dir" + cat >"${project_dir}/CMakeLists.txt" <<'EOF' +cmake_minimum_required(VERSION 3.16) +project(check_rapidjson_target LANGUAGES CXX) + +function(abacus_add_feature_definitions) + set_property(GLOBAL APPEND PROPERTY ABACUS_FEATURE_DEFINITIONS ${ARGN}) +endfunction() + +include("${ABACUS_SOURCE_DIR}/cmake/AbacusRapidJSON.cmake") + +add_library(deps INTERFACE) +abacus_configure_rapidjson(deps) + +get_target_property(_links deps INTERFACE_LINK_LIBRARIES) +if(NOT _links MATCHES "(^|;)rapidjson($|;)") + message(FATAL_ERROR "Expected deps to link to rapidjson target, got '${_links}'") +endif() + +get_property(_defs GLOBAL PROPERTY ABACUS_FEATURE_DEFINITIONS) +if(NOT "__RAPIDJSON" IN_LIST _defs) + message(FATAL_ERROR "Expected __RAPIDJSON feature definition") +endif() +EOF +} + +write_variable_test_project() { + local project_dir="$1" + mkdir -p "$project_dir" + cat >"${project_dir}/CMakeLists.txt" <<'EOF' +cmake_minimum_required(VERSION 3.16) +project(check_rapidjson_variables LANGUAGES CXX) + +function(abacus_add_feature_definitions) + set_property(GLOBAL APPEND PROPERTY ABACUS_FEATURE_DEFINITIONS ${ARGN}) +endfunction() + +include("${ABACUS_SOURCE_DIR}/cmake/AbacusRapidJSON.cmake") + +add_library(deps INTERFACE) +abacus_configure_rapidjson(deps) + +get_target_property(_includes deps INTERFACE_INCLUDE_DIRECTORIES) +if(NOT _includes STREQUAL "${EXPECTED_RAPIDJSON_INCLUDE}") + message(FATAL_ERROR "Expected include '${EXPECTED_RAPIDJSON_INCLUDE}', got '${_includes}'") +endif() + +get_property(_defs GLOBAL PROPERTY ABACUS_FEATURE_DEFINITIONS) +if(NOT "__RAPIDJSON" IN_LIST _defs) + message(FATAL_ERROR "Expected __RAPIDJSON feature definition") +endif() +EOF +} + +run_cmake_configure() { + local source_dir="$1" + local build_dir="$2" + local prefix="$3" + local expected_include="$4" + + cmake -S "$source_dir" -B "$build_dir" \ + -DABACUS_SOURCE_DIR="${REPO_ROOT}" \ + -DCMAKE_PREFIX_PATH="$prefix" \ + -DEXPECTED_RAPIDJSON_INCLUDE="$expected_include" \ + >"${build_dir}.log" 2>&1 +} + +test_lowercase_target_package() { + local tmpdir prefix source_dir build_dir status + tmpdir="$(mktemp -d)" + prefix="${tmpdir}/prefix" + source_dir="${tmpdir}/target-project" + build_dir="${tmpdir}/target-build" + + write_lowercase_target_package "$prefix" + write_target_test_project "$source_dir" + run_cmake_configure "$source_dir" "$build_dir" "$prefix" "${prefix}/include" + status=$? + + if [[ "$status" -ne 0 ]]; then + cat "${build_dir}.log" >&2 + fail "lowercase RapidJSON target package did not configure" + fi + + rm -rf "$tmpdir" +} + +test_variable_only_package() { + local tmpdir prefix source_dir build_dir status + tmpdir="$(mktemp -d)" + prefix="${tmpdir}/prefix" + source_dir="${tmpdir}/variable-project" + build_dir="${tmpdir}/variable-build" + + write_variable_only_package "$prefix" + write_variable_test_project "$source_dir" + run_cmake_configure "$source_dir" "$build_dir" "$prefix" "${prefix}/include" + status=$? + + if [[ "$status" -ne 0 ]]; then + cat "${build_dir}.log" >&2 + fail "variable-only RapidJSON package did not configure" + fi + + rm -rf "$tmpdir" +} + +test_aocc_build_script_does_not_override_rapidjson_dir() { + local script="${REPO_ROOT}/toolchain/build_abacus_aocc-aocl.sh" + if grep -Fq -- '-DRapidJSON_DIR=$RAPIDJSON' "$script"; then + fail "${script} still passes RapidJSON_DIR as the package prefix" + fi +} + +test_lowercase_target_package +test_variable_only_package +test_aocc_build_script_does_not_override_rapidjson_dir + +if [[ "$FAILURES" -ne 0 ]]; then + printf '%s RapidJSON CMake test(s) failed\n' "$FAILURES" >&2 + exit 1 +fi + +printf 'RapidJSON CMake tests passed\n' From 583c5dc668a7216e70393b99f881c57a63fd7772 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Thu, 2 Jul 2026 22:16:00 +0800 Subject: [PATCH 06/11] fix: support installed RapidJSON CMake packages --- CMakeLists.txt | 5 ++--- cmake/AbacusRapidJSON.cmake | 23 +++++++++++++++++++++++ toolchain/build_abacus_aocc-aocl.sh | 2 -- 3 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 cmake/AbacusRapidJSON.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 23583375bb..7a0fa3f081 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,9 +160,8 @@ endfunction() # enable json support if(ENABLE_RAPIDJSON) - find_package(RapidJSON CONFIG REQUIRED) - abacus_add_feature_definitions(__RAPIDJSON) - target_link_libraries(abacus_external_deps INTERFACE RapidJSON) + include(cmake/AbacusRapidJSON.cmake) + abacus_configure_rapidjson(abacus_external_deps) endif() # get commit info diff --git a/cmake/AbacusRapidJSON.cmake b/cmake/AbacusRapidJSON.cmake new file mode 100644 index 0000000000..0c8e9c4af9 --- /dev/null +++ b/cmake/AbacusRapidJSON.cmake @@ -0,0 +1,23 @@ +function(abacus_configure_rapidjson target_name) + find_package(RapidJSON CONFIG REQUIRED) + + if(TARGET RapidJSON::RapidJSON) + target_link_libraries("${target_name}" INTERFACE RapidJSON::RapidJSON) + elseif(TARGET rapidjson) + target_link_libraries("${target_name}" INTERFACE rapidjson) + elseif(TARGET RapidJSON) + target_link_libraries("${target_name}" INTERFACE RapidJSON) + elseif(DEFINED RapidJSON_INCLUDE_DIRS AND NOT "${RapidJSON_INCLUDE_DIRS}" STREQUAL "") + target_include_directories("${target_name}" INTERFACE ${RapidJSON_INCLUDE_DIRS}) + elseif(DEFINED RapidJSON_INCLUDE_DIR AND NOT "${RapidJSON_INCLUDE_DIR}" STREQUAL "") + target_include_directories("${target_name}" INTERFACE "${RapidJSON_INCLUDE_DIR}") + else() + message( + FATAL_ERROR + "RapidJSON was found, but it did not provide a usable target or include directory. " + "Expected one of RapidJSON::RapidJSON, rapidjson, RapidJSON, RapidJSON_INCLUDE_DIRS, or RapidJSON_INCLUDE_DIR." + ) + endif() + + abacus_add_feature_definitions(__RAPIDJSON) +endfunction() diff --git a/toolchain/build_abacus_aocc-aocl.sh b/toolchain/build_abacus_aocc-aocl.sh index b32295bf11..c8a991f17d 100755 --- a/toolchain/build_abacus_aocc-aocl.sh +++ b/toolchain/build_abacus_aocc-aocl.sh @@ -24,7 +24,6 @@ rm -rf $BUILD_DIR PREFIX=$ABACUS_DIR ELPA=${ELPA_ROOT} CEREAL=${CEREAL_ROOT}/include -RAPIDJSON=${RAPIDJSON_ROOT} LAPACK=$AOCLhome/lib SCALAPACK=$AOCLhome/lib FFTW3=$AOCLhome @@ -75,7 +74,6 @@ cmake -B $BUILD_DIR -DCMAKE_INSTALL_PREFIX=$PREFIX \ -DUSE_OPENMP=ON \ -DUSE_ELPA=ON \ -DENABLE_RAPIDJSON=ON \ - -DRapidJSON_DIR=$RAPIDJSON \ -DENABLE_LIBRI=ON \ -DLIBRI_DIR=$LIBRI \ -DLIBCOMM_DIR=$LIBCOMM \ From 1a1763596b11d67ce78de1fd28a594189da7b236 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Fri, 3 Jul 2026 23:23:12 +0800 Subject: [PATCH 07/11] fix: require RapidJSON exported CMake target --- CMakeLists.txt | 8 +- cmake/AbacusRapidJSON.cmake | 23 ---- toolchain/tests/test_rapidjson_cmake.sh | 135 ++++++++++++++---------- 3 files changed, 87 insertions(+), 79 deletions(-) delete mode 100644 cmake/AbacusRapidJSON.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 7a0fa3f081..871f913a8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -160,8 +160,12 @@ endfunction() # enable json support if(ENABLE_RAPIDJSON) - include(cmake/AbacusRapidJSON.cmake) - abacus_configure_rapidjson(abacus_external_deps) + find_package(RapidJSON CONFIG REQUIRED) + if(NOT TARGET RapidJSON) + message(FATAL_ERROR "RapidJSON package configuration did not define the RapidJSON target") + endif() + abacus_add_feature_definitions(__RAPIDJSON) + target_link_libraries(abacus_external_deps INTERFACE RapidJSON) endif() # get commit info diff --git a/cmake/AbacusRapidJSON.cmake b/cmake/AbacusRapidJSON.cmake deleted file mode 100644 index 0c8e9c4af9..0000000000 --- a/cmake/AbacusRapidJSON.cmake +++ /dev/null @@ -1,23 +0,0 @@ -function(abacus_configure_rapidjson target_name) - find_package(RapidJSON CONFIG REQUIRED) - - if(TARGET RapidJSON::RapidJSON) - target_link_libraries("${target_name}" INTERFACE RapidJSON::RapidJSON) - elseif(TARGET rapidjson) - target_link_libraries("${target_name}" INTERFACE rapidjson) - elseif(TARGET RapidJSON) - target_link_libraries("${target_name}" INTERFACE RapidJSON) - elseif(DEFINED RapidJSON_INCLUDE_DIRS AND NOT "${RapidJSON_INCLUDE_DIRS}" STREQUAL "") - target_include_directories("${target_name}" INTERFACE ${RapidJSON_INCLUDE_DIRS}) - elseif(DEFINED RapidJSON_INCLUDE_DIR AND NOT "${RapidJSON_INCLUDE_DIR}" STREQUAL "") - target_include_directories("${target_name}" INTERFACE "${RapidJSON_INCLUDE_DIR}") - else() - message( - FATAL_ERROR - "RapidJSON was found, but it did not provide a usable target or include directory. " - "Expected one of RapidJSON::RapidJSON, rapidjson, RapidJSON, RapidJSON_INCLUDE_DIRS, or RapidJSON_INCLUDE_DIR." - ) - endif() - - abacus_add_feature_definitions(__RAPIDJSON) -endfunction() diff --git a/toolchain/tests/test_rapidjson_cmake.sh b/toolchain/tests/test_rapidjson_cmake.sh index 0c68fa38c2..bd3089d99c 100755 --- a/toolchain/tests/test_rapidjson_cmake.sh +++ b/toolchain/tests/test_rapidjson_cmake.sh @@ -9,18 +9,16 @@ fail() { FAILURES=$((FAILURES + 1)) } -write_lowercase_target_package() { +write_target_package() { local prefix="$1" mkdir -p "${prefix}/include/rapidjson" "${prefix}/lib/cmake/RapidJSON" printf '#pragma once\n' >"${prefix}/include/rapidjson/document.h" cat >"${prefix}/lib/cmake/RapidJSON/RapidJSONConfig.cmake" <<'EOF' get_filename_component(RapidJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(_rapidjson_prefix "${RapidJSON_CMAKE_DIR}/../../.." ABSOLUTE) -set(RapidJSON_INCLUDE_DIR "${_rapidjson_prefix}/include") -set(RapidJSON_INCLUDE_DIRS "${RapidJSON_INCLUDE_DIR}") -if(NOT TARGET rapidjson) - add_library(rapidjson INTERFACE IMPORTED) - set_property(TARGET rapidjson PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${RapidJSON_INCLUDE_DIRS}") +if(NOT TARGET RapidJSON) + add_library(RapidJSON INTERFACE IMPORTED) + set_property(TARGET RapidJSON PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${_rapidjson_prefix}/include") endif() EOF } @@ -37,7 +35,7 @@ set(RapidJSON_INCLUDE_DIRS "${RapidJSON_INCLUDE_DIR}") EOF } -write_target_test_project() { +write_test_project() { local project_dir="$1" mkdir -p "$project_dir" cat >"${project_dir}/CMakeLists.txt" <<'EOF' @@ -48,42 +46,18 @@ function(abacus_add_feature_definitions) set_property(GLOBAL APPEND PROPERTY ABACUS_FEATURE_DEFINITIONS ${ARGN}) endfunction() -include("${ABACUS_SOURCE_DIR}/cmake/AbacusRapidJSON.cmake") - -add_library(deps INTERFACE) -abacus_configure_rapidjson(deps) - -get_target_property(_links deps INTERFACE_LINK_LIBRARIES) -if(NOT _links MATCHES "(^|;)rapidjson($|;)") - message(FATAL_ERROR "Expected deps to link to rapidjson target, got '${_links}'") -endif() - -get_property(_defs GLOBAL PROPERTY ABACUS_FEATURE_DEFINITIONS) -if(NOT "__RAPIDJSON" IN_LIST _defs) - message(FATAL_ERROR "Expected __RAPIDJSON feature definition") +find_package(RapidJSON CONFIG REQUIRED) +if(NOT TARGET RapidJSON) + message(FATAL_ERROR "RapidJSON package configuration did not define the RapidJSON target") endif() -EOF -} - -write_variable_test_project() { - local project_dir="$1" - mkdir -p "$project_dir" - cat >"${project_dir}/CMakeLists.txt" <<'EOF' -cmake_minimum_required(VERSION 3.16) -project(check_rapidjson_variables LANGUAGES CXX) - -function(abacus_add_feature_definitions) - set_property(GLOBAL APPEND PROPERTY ABACUS_FEATURE_DEFINITIONS ${ARGN}) -endfunction() - -include("${ABACUS_SOURCE_DIR}/cmake/AbacusRapidJSON.cmake") add_library(deps INTERFACE) -abacus_configure_rapidjson(deps) +target_link_libraries(deps INTERFACE RapidJSON) +abacus_add_feature_definitions(__RAPIDJSON) -get_target_property(_includes deps INTERFACE_INCLUDE_DIRECTORIES) -if(NOT _includes STREQUAL "${EXPECTED_RAPIDJSON_INCLUDE}") - message(FATAL_ERROR "Expected include '${EXPECTED_RAPIDJSON_INCLUDE}', got '${_includes}'") +get_target_property(_links deps INTERFACE_LINK_LIBRARIES) +if(NOT "RapidJSON" IN_LIST _links) + message(FATAL_ERROR "Expected deps to link to RapidJSON target, got '${_links}'") endif() get_property(_defs GLOBAL PROPERTY ABACUS_FEATURE_DEFINITIONS) @@ -97,36 +71,43 @@ run_cmake_configure() { local source_dir="$1" local build_dir="$2" local prefix="$3" - local expected_include="$4" cmake -S "$source_dir" -B "$build_dir" \ - -DABACUS_SOURCE_DIR="${REPO_ROOT}" \ -DCMAKE_PREFIX_PATH="$prefix" \ - -DEXPECTED_RAPIDJSON_INCLUDE="$expected_include" \ >"${build_dir}.log" 2>&1 } -test_lowercase_target_package() { +run_top_level_configure() { + local build_dir="$1" + local prefix="$2" + + cmake -S "$REPO_ROOT" -B "$build_dir" \ + -DENABLE_RAPIDJSON=ON \ + -DCMAKE_PREFIX_PATH="$prefix" \ + >"${build_dir}.log" 2>&1 +} + +test_rapidjson_target_package_configures() { local tmpdir prefix source_dir build_dir status tmpdir="$(mktemp -d)" prefix="${tmpdir}/prefix" source_dir="${tmpdir}/target-project" build_dir="${tmpdir}/target-build" - write_lowercase_target_package "$prefix" - write_target_test_project "$source_dir" - run_cmake_configure "$source_dir" "$build_dir" "$prefix" "${prefix}/include" + write_target_package "$prefix" + write_test_project "$source_dir" + run_cmake_configure "$source_dir" "$build_dir" "$prefix" status=$? if [[ "$status" -ne 0 ]]; then cat "${build_dir}.log" >&2 - fail "lowercase RapidJSON target package did not configure" + fail "RapidJSON target package did not configure" fi rm -rf "$tmpdir" } -test_variable_only_package() { +test_variable_only_package_fails() { local tmpdir prefix source_dir build_dir status tmpdir="$(mktemp -d)" prefix="${tmpdir}/prefix" @@ -134,18 +115,62 @@ test_variable_only_package() { build_dir="${tmpdir}/variable-build" write_variable_only_package "$prefix" - write_variable_test_project "$source_dir" - run_cmake_configure "$source_dir" "$build_dir" "$prefix" "${prefix}/include" + write_test_project "$source_dir" + run_cmake_configure "$source_dir" "$build_dir" "$prefix" status=$? - if [[ "$status" -ne 0 ]]; then + if [[ "$status" -eq 0 ]]; then + cat "${build_dir}.log" >&2 + fail "variable-only RapidJSON package configured; expected target-missing failure" + elif ! grep -Fq "RapidJSON package configuration did not define the RapidJSON target" "${build_dir}.log"; then cat "${build_dir}.log" >&2 - fail "variable-only RapidJSON package did not configure" + fail "variable-only RapidJSON package failed for the wrong reason" fi rm -rf "$tmpdir" } +test_top_level_rejects_variable_only_package() { + local tmpdir prefix build_dir status + tmpdir="$(mktemp -d)" + prefix="${tmpdir}/prefix" + build_dir="${tmpdir}/top-level-build" + + write_variable_only_package "$prefix" + run_top_level_configure "$build_dir" "$prefix" + status=$? + + if [[ "$status" -eq 0 ]]; then + cat "${build_dir}.log" >&2 + fail "top-level CMake configured with variable-only RapidJSON package; expected target-missing failure" + elif ! grep -Fq "RapidJSON package configuration did not define the RapidJSON target" "${build_dir}.log"; then + cat "${build_dir}.log" >&2 + fail "top-level CMake failed for the wrong reason with variable-only RapidJSON package" + fi + + rm -rf "$tmpdir" +} + +test_top_level_uses_rapidjson_target_directly() { + local cmakelists="${REPO_ROOT}/CMakeLists.txt" + + if [[ -e "${REPO_ROOT}/cmake/AbacusRapidJSON.cmake" ]]; then + fail "cmake/AbacusRapidJSON.cmake still exists; RapidJSON config should provide the target" + fi + + if ! grep -Fq "find_package(RapidJSON CONFIG REQUIRED)" "$cmakelists"; then + fail "top-level CMakeLists.txt does not call find_package(RapidJSON CONFIG REQUIRED)" + fi + + if ! grep -Fq "target_link_libraries(abacus_external_deps INTERFACE RapidJSON)" "$cmakelists"; then + fail "top-level CMakeLists.txt does not link abacus_external_deps to RapidJSON target" + fi + + if grep -Fq "include(cmake/AbacusRapidJSON.cmake)" "$cmakelists"; then + fail "top-level CMakeLists.txt still includes the RapidJSON compatibility helper" + fi +} + test_aocc_build_script_does_not_override_rapidjson_dir() { local script="${REPO_ROOT}/toolchain/build_abacus_aocc-aocl.sh" if grep -Fq -- '-DRapidJSON_DIR=$RAPIDJSON' "$script"; then @@ -153,8 +178,10 @@ test_aocc_build_script_does_not_override_rapidjson_dir() { fi } -test_lowercase_target_package -test_variable_only_package +test_rapidjson_target_package_configures +test_variable_only_package_fails +test_top_level_rejects_variable_only_package +test_top_level_uses_rapidjson_target_directly test_aocc_build_script_does_not_override_rapidjson_dir if [[ "$FAILURES" -ne 0 ]]; then From 10f35c5613c4d30199f928de9c6ecb217f033626 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Sun, 5 Jul 2026 10:30:24 +0800 Subject: [PATCH 08/11] test: harden RapidJSON CMake coverage --- CMakeLists.txt | 5 +- toolchain/tests/test_rapidjson_cmake.sh | 192 ++++++++++++------------ 2 files changed, 99 insertions(+), 98 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 871f913a8c..d0a76e9a21 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,7 +162,10 @@ endfunction() if(ENABLE_RAPIDJSON) find_package(RapidJSON CONFIG REQUIRED) if(NOT TARGET RapidJSON) - message(FATAL_ERROR "RapidJSON package configuration did not define the RapidJSON target") + message( + FATAL_ERROR + "RapidJSON was found, but target RapidJSON is missing. Check if your RapidJSON installation provides a complete exported CMake configuration." + ) endif() abacus_add_feature_definitions(__RAPIDJSON) target_link_libraries(abacus_external_deps INTERFACE RapidJSON) diff --git a/toolchain/tests/test_rapidjson_cmake.sh b/toolchain/tests/test_rapidjson_cmake.sh index bd3089d99c..b138967563 100755 --- a/toolchain/tests/test_rapidjson_cmake.sh +++ b/toolchain/tests/test_rapidjson_cmake.sh @@ -14,15 +14,26 @@ write_target_package() { mkdir -p "${prefix}/include/rapidjson" "${prefix}/lib/cmake/RapidJSON" printf '#pragma once\n' >"${prefix}/include/rapidjson/document.h" cat >"${prefix}/lib/cmake/RapidJSON/RapidJSONConfig.cmake" <<'EOF' +message(STATUS "Loaded fake RapidJSON target package") get_filename_component(RapidJSON_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(_rapidjson_prefix "${RapidJSON_CMAKE_DIR}/../../.." ABSOLUTE) if(NOT TARGET RapidJSON) add_library(RapidJSON INTERFACE IMPORTED) set_property(TARGET RapidJSON PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${_rapidjson_prefix}/include") + set_property(TARGET RapidJSON PROPERTY INTERFACE_COMPILE_DEFINITIONS ABACUS_TEST_RAPIDJSON_TARGET_USAGE) endif() EOF } +write_fake_mkl() { + local prefix="$1" + mkdir -p "${prefix}/include" "${prefix}/lib" + printf '#pragma once\n' >"${prefix}/include/mkl_service.h" + : >"${prefix}/lib/libmkl_core.so" + : >"${prefix}/lib/libmkl_gf_lp64.so" + : >"${prefix}/lib/libmkl_gnu_thread.so" +} + write_variable_only_package() { local prefix="$1" mkdir -p "${prefix}/include/rapidjson" "${prefix}/lib/cmake/RapidJSON" @@ -35,115 +46,124 @@ set(RapidJSON_INCLUDE_DIRS "${RapidJSON_INCLUDE_DIR}") EOF } -write_test_project() { - local project_dir="$1" - mkdir -p "$project_dir" - cat >"${project_dir}/CMakeLists.txt" <<'EOF' -cmake_minimum_required(VERSION 3.16) -project(check_rapidjson_target LANGUAGES CXX) - -function(abacus_add_feature_definitions) - set_property(GLOBAL APPEND PROPERTY ABACUS_FEATURE_DEFINITIONS ${ARGN}) -endfunction() - -find_package(RapidJSON CONFIG REQUIRED) -if(NOT TARGET RapidJSON) - message(FATAL_ERROR "RapidJSON package configuration did not define the RapidJSON target") -endif() - -add_library(deps INTERFACE) -target_link_libraries(deps INTERFACE RapidJSON) -abacus_add_feature_definitions(__RAPIDJSON) - -get_target_property(_links deps INTERFACE_LINK_LIBRARIES) -if(NOT "RapidJSON" IN_LIST _links) - message(FATAL_ERROR "Expected deps to link to RapidJSON target, got '${_links}'") -endif() - -get_property(_defs GLOBAL PROPERTY ABACUS_FEATURE_DEFINITIONS) -if(NOT "__RAPIDJSON" IN_LIST _defs) - message(FATAL_ERROR "Expected __RAPIDJSON feature definition") -endif() -EOF -} - -run_cmake_configure() { - local source_dir="$1" - local build_dir="$2" - local prefix="$3" - - cmake -S "$source_dir" -B "$build_dir" \ - -DCMAKE_PREFIX_PATH="$prefix" \ - >"${build_dir}.log" 2>&1 -} - run_top_level_configure() { local build_dir="$1" local prefix="$2" + local mkl_root="$3" + + mkdir -p "${build_dir}/.cmake/api/v1/query" + touch "${build_dir}/.cmake/api/v1/query/codemodel-v2" cmake -S "$REPO_ROOT" -B "$build_dir" \ -DENABLE_RAPIDJSON=ON \ + -DENABLE_LCAO=OFF \ + -DENABLE_MPI=OFF \ + -DUSE_OPENMP=OFF \ + -DMKLROOT="$mkl_root" \ -DCMAKE_PREFIX_PATH="$prefix" \ >"${build_dir}.log" 2>&1 } -test_rapidjson_target_package_configures() { - local tmpdir prefix source_dir build_dir status - tmpdir="$(mktemp -d)" - prefix="${tmpdir}/prefix" - source_dir="${tmpdir}/target-project" - build_dir="${tmpdir}/target-build" - - write_target_package "$prefix" - write_test_project "$source_dir" - run_cmake_configure "$source_dir" "$build_dir" "$prefix" - status=$? - - if [[ "$status" -ne 0 ]]; then - cat "${build_dir}.log" >&2 - fail "RapidJSON target package did not configure" - fi +assert_abacus_target_has_rapidjson_usage() { + local build_dir="$1" - rm -rf "$tmpdir" + python3 - "$build_dir" <<'PY' +import json +import pathlib +import sys + +build_dir = pathlib.Path(sys.argv[1]) +reply_dir = build_dir / ".cmake" / "api" / "v1" / "reply" + +try: + index_file = next(reply_dir.glob("index-*.json")) + index = json.loads(index_file.read_text()) + codemodel_file = reply_dir / index["reply"]["codemodel-v2"]["jsonFile"] + codemodel = json.loads(codemodel_file.read_text()) + target_refs = [ + target + for target in codemodel["configurations"][0]["targets"] + if target["name"].startswith("abacus_") + ] +except (KeyError, StopIteration, FileNotFoundError, json.JSONDecodeError) as exc: + print(f"failed to read CMake File API codemodel: {exc}", file=sys.stderr) + sys.exit(1) + +if len(target_refs) != 1: + names = ", ".join(sorted(target["name"] for target in target_refs)) or "" + print(f"expected exactly one ABACUS executable target, got: {names}", file=sys.stderr) + sys.exit(1) + +target_ref = target_refs[0] +target = json.loads((reply_dir / target_ref["jsonFile"]).read_text()) +definitions = { + definition["define"] + for group in target.get("compileGroups", []) + for definition in group.get("defines", []) + if "define" in definition +} +required = {"__RAPIDJSON", "ABACUS_TEST_RAPIDJSON_TARGET_USAGE"} +missing = sorted(required - definitions) + +if missing: + observed = ", ".join(sorted(definitions)) or "" + print( + f"{target_ref['name']} is missing RapidJSON definitions: {', '.join(missing)}", + file=sys.stderr, + ) + print(f"observed definitions: {observed}", file=sys.stderr) + sys.exit(1) +PY } -test_variable_only_package_fails() { - local tmpdir prefix source_dir build_dir status +test_top_level_accepts_rapidjson_target_package() { + local tmpdir prefix mkl_root build_dir status tmpdir="$(mktemp -d)" prefix="${tmpdir}/prefix" - source_dir="${tmpdir}/variable-project" - build_dir="${tmpdir}/variable-build" + mkl_root="${tmpdir}/mkl" + build_dir="${tmpdir}/target-build" - write_variable_only_package "$prefix" - write_test_project "$source_dir" - run_cmake_configure "$source_dir" "$build_dir" "$prefix" + write_target_package "$prefix" + write_fake_mkl "$mkl_root" + run_top_level_configure "$build_dir" "$prefix" "$mkl_root" status=$? - if [[ "$status" -eq 0 ]]; then + if ! grep -Fq "Loaded fake RapidJSON target package" "${build_dir}.log"; then + cat "${build_dir}.log" >&2 + fail "top-level CMake did not load the fake RapidJSON target package" + elif grep -Fq "RapidJSON was found, but target RapidJSON is missing" "${build_dir}.log"; then cat "${build_dir}.log" >&2 - fail "variable-only RapidJSON package configured; expected target-missing failure" - elif ! grep -Fq "RapidJSON package configuration did not define the RapidJSON target" "${build_dir}.log"; then + fail "top-level CMake rejected RapidJSON target package as target-missing" + elif grep -Fq 'Could not find a package configuration file provided by "RapidJSON"' "${build_dir}.log"; then cat "${build_dir}.log" >&2 - fail "variable-only RapidJSON package failed for the wrong reason" + fail "top-level CMake did not find the fake RapidJSON target package" + elif [[ "$status" -ne 0 ]]; then + cat "${build_dir}.log" >&2 + fail "top-level CMake failed with a RapidJSON target package" + elif ! assert_abacus_target_has_rapidjson_usage "$build_dir"; then + cat "${build_dir}.log" >&2 + fail "top-level CMake did not propagate RapidJSON feature and target usage" fi rm -rf "$tmpdir" } test_top_level_rejects_variable_only_package() { - local tmpdir prefix build_dir status + local tmpdir prefix mkl_root build_dir status tmpdir="$(mktemp -d)" prefix="${tmpdir}/prefix" - build_dir="${tmpdir}/top-level-build" + mkl_root="${tmpdir}/mkl" + build_dir="${tmpdir}/variable-build" write_variable_only_package "$prefix" - run_top_level_configure "$build_dir" "$prefix" + write_fake_mkl "$mkl_root" + run_top_level_configure "$build_dir" "$prefix" "$mkl_root" status=$? if [[ "$status" -eq 0 ]]; then cat "${build_dir}.log" >&2 fail "top-level CMake configured with variable-only RapidJSON package; expected target-missing failure" - elif ! grep -Fq "RapidJSON package configuration did not define the RapidJSON target" "${build_dir}.log"; then + elif ! grep -Fq "RapidJSON was found, but target RapidJSON is missing." "${build_dir}.log"; then cat "${build_dir}.log" >&2 fail "top-level CMake failed for the wrong reason with variable-only RapidJSON package" fi @@ -151,26 +171,6 @@ test_top_level_rejects_variable_only_package() { rm -rf "$tmpdir" } -test_top_level_uses_rapidjson_target_directly() { - local cmakelists="${REPO_ROOT}/CMakeLists.txt" - - if [[ -e "${REPO_ROOT}/cmake/AbacusRapidJSON.cmake" ]]; then - fail "cmake/AbacusRapidJSON.cmake still exists; RapidJSON config should provide the target" - fi - - if ! grep -Fq "find_package(RapidJSON CONFIG REQUIRED)" "$cmakelists"; then - fail "top-level CMakeLists.txt does not call find_package(RapidJSON CONFIG REQUIRED)" - fi - - if ! grep -Fq "target_link_libraries(abacus_external_deps INTERFACE RapidJSON)" "$cmakelists"; then - fail "top-level CMakeLists.txt does not link abacus_external_deps to RapidJSON target" - fi - - if grep -Fq "include(cmake/AbacusRapidJSON.cmake)" "$cmakelists"; then - fail "top-level CMakeLists.txt still includes the RapidJSON compatibility helper" - fi -} - test_aocc_build_script_does_not_override_rapidjson_dir() { local script="${REPO_ROOT}/toolchain/build_abacus_aocc-aocl.sh" if grep -Fq -- '-DRapidJSON_DIR=$RAPIDJSON' "$script"; then @@ -178,10 +178,8 @@ test_aocc_build_script_does_not_override_rapidjson_dir() { fi } -test_rapidjson_target_package_configures -test_variable_only_package_fails +test_top_level_accepts_rapidjson_target_package test_top_level_rejects_variable_only_package -test_top_level_uses_rapidjson_target_directly test_aocc_build_script_does_not_override_rapidjson_dir if [[ "$FAILURES" -ne 0 ]]; then From b98ffe434ee180cf4a262d42659c064779dc46c3 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Sun, 5 Jul 2026 14:56:12 +0800 Subject: [PATCH 09/11] fix: disable default OpenMPI binding in setup --- toolchain/scripts/stage1/install_openmpi.sh | 5 + .../test_openmpi_binding_policy_setup.sh | 127 ++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100755 toolchain/tests/test_openmpi_binding_policy_setup.sh diff --git a/toolchain/scripts/stage1/install_openmpi.sh b/toolchain/scripts/stage1/install_openmpi.sh index 423e6943d1..e798cc7325 100755 --- a/toolchain/scripts/stage1/install_openmpi.sh +++ b/toolchain/scripts/stage1/install_openmpi.sh @@ -167,6 +167,10 @@ else grep "(Open MPI)" | awk '{print $4}') major_version=$(echo ${raw_version} | cut -d '.' -f 1) minor_version=$(echo ${raw_version} | cut -d '.' -f 2) + OPENMPI_BINDING_POLICY_ENV="export OMPI_MCA_hwloc_base_binding_policy=none" + if [[ "${major_version}" =~ ^[0-9]+$ && "${major_version}" -ge 5 ]]; then + OPENMPI_BINDING_POLICY_ENV="export PRTE_MCA_hwloc_default_binding_policy=none" + fi OPENMPI_LIBS="" # grab additional runtime libs (for C/C++) from the mpicxx wrapper, # and remove them from the LDFLAGS if present @@ -182,6 +186,7 @@ export MPICXX="${MPICXX}" export MPIFC="${MPIFC}" export MPIFORT="${MPIFORT}" export MPIF77="${MPIF77}" +${OPENMPI_BINDING_POLICY_ENV} export OPENMPI_CFLAGS="${OPENMPI_CFLAGS}" export OPENMPI_LDFLAGS="${OPENMPI_LDFLAGS}" export OPENMPI_LIBS="${OPENMPI_LIBS}" diff --git a/toolchain/tests/test_openmpi_binding_policy_setup.sh b/toolchain/tests/test_openmpi_binding_policy_setup.sh new file mode 100755 index 0000000000..5ae0bfb9c6 --- /dev/null +++ b/toolchain/tests/test_openmpi_binding_policy_setup.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +set -u + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)" +TOOLCHAIN_DIR="${REPO_ROOT}/toolchain" +FAILURES=0 + +fail() { + printf 'FAIL: %s\n' "$*" >&2 + FAILURES=$((FAILURES + 1)) +} + +write_fake_openmpi_commands() { + local bindir="$1" + local version="$2" + + mkdir -p "$bindir" + cat >"${bindir}/mpiexec" <"${bindir}/mpicxx" <<'EOF' +#!/usr/bin/env bash +if [[ "$1" == "--showme:libs" ]]; then + printf 'mpi\n' + exit 0 +fi +exit 0 +EOF + cp "${bindir}/mpicxx" "${bindir}/mpicc" + cp "${bindir}/mpicxx" "${bindir}/mpifort" + chmod +x "${bindir}/mpiexec" "${bindir}/mpicc" "${bindir}/mpicxx" "${bindir}/mpifort" +} + +run_openmpi_system_setup() { + local tmpdir="$1" + local version="$2" + + mkdir -p "${tmpdir}/install" "${tmpdir}/build" + : >"${tmpdir}/install/setup" + : >"${tmpdir}/install/toolchain.env" + cat >"${tmpdir}/install/toolchain.conf" <<'EOF' +MPI_MODE="openmpi" +with_openmpi="__SYSTEM__" +PACK_RUN="__FALSE__" +EOF + + write_fake_openmpi_commands "${tmpdir}/fake-bin" "$version" + PATH="${tmpdir}/fake-bin:${PATH}" \ + ROOTDIR="$tmpdir" \ + SCRIPTDIR="${TOOLCHAIN_DIR}/scripts" \ + INSTALLDIR="${tmpdir}/install" \ + BUILDDIR="${tmpdir}/build" \ + SETUPFILE="${tmpdir}/install/setup" \ + bash "${TOOLCHAIN_DIR}/scripts/stage1/install_openmpi.sh" \ + >"${tmpdir}/openmpi.log" 2>&1 +} + +assert_setup_contains() { + local file="$1" + local expected="$2" + + if ! grep -Fq "$expected" "$file"; then + cat "$file" >&2 + fail "${file} does not contain expected text: ${expected}" + fi +} + +assert_setup_not_contains() { + local file="$1" + local unexpected="$2" + + if grep -Fq "$unexpected" "$file"; then + cat "$file" >&2 + fail "${file} contains unexpected text: ${unexpected}" + fi +} + +test_openmpi5_setup_disables_prte_binding() { + local tmpdir status + tmpdir="$(mktemp -d)" + + run_openmpi_system_setup "$tmpdir" "5.0.10" + status=$? + + if [[ "$status" -ne 0 ]]; then + cat "${tmpdir}/openmpi.log" >&2 + fail "OpenMPI 5 setup generation failed with status ${status}" + else + assert_setup_contains "${tmpdir}/install/setup" "export PRTE_MCA_hwloc_default_binding_policy=none" + assert_setup_not_contains "${tmpdir}/install/setup" "export OMPI_MCA_hwloc_base_binding_policy=none" + fi + + rm -rf "$tmpdir" +} + +test_openmpi4_setup_disables_ompi_binding() { + local tmpdir status + tmpdir="$(mktemp -d)" + + run_openmpi_system_setup "$tmpdir" "4.1.8" + status=$? + + if [[ "$status" -ne 0 ]]; then + cat "${tmpdir}/openmpi.log" >&2 + fail "OpenMPI 4 setup generation failed with status ${status}" + else + assert_setup_contains "${tmpdir}/install/setup" "export OMPI_MCA_hwloc_base_binding_policy=none" + assert_setup_not_contains "${tmpdir}/install/setup" "export PRTE_MCA_hwloc_default_binding_policy=none" + fi + + rm -rf "$tmpdir" +} + +test_openmpi5_setup_disables_prte_binding +test_openmpi4_setup_disables_ompi_binding + +if [[ "$FAILURES" -ne 0 ]]; then + printf '%s OpenMPI binding policy setup test(s) failed\n' "$FAILURES" >&2 + exit 1 +fi + +printf 'OpenMPI binding policy setup tests passed\n' From c46918a36f45ebb173f8039bda2527f3c1dd046f Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Sun, 5 Jul 2026 15:38:41 +0800 Subject: [PATCH 10/11] test: trim redundant toolchain checks --- .../tests/test_installer_argument_failures.sh | 54 ------------------- toolchain/tests/test_rapidjson_cmake.sh | 8 --- 2 files changed, 62 deletions(-) diff --git a/toolchain/tests/test_installer_argument_failures.sh b/toolchain/tests/test_installer_argument_failures.sh index 48c153dad8..0bdb1d8534 100755 --- a/toolchain/tests/test_installer_argument_failures.sh +++ b/toolchain/tests/test_installer_argument_failures.sh @@ -63,62 +63,8 @@ assert_invalid_input_fails() { rm -rf "$tmpdir" } -assert_valid_dry_run_succeeds() { - local name="$1" - shift - - local tmpdir status - tmpdir="$(mktemp -d)" - copy_toolchain "$tmpdir" - - run_installer_in_copy "$tmpdir" "$@" - status=$? - - if [[ "$status" -ne 0 ]]; then - cat "${tmpdir}/output.log" >&2 - fail "${name} exited ${status}; expected 0" - fi - - if ! grep -Fq "Configuration files generated successfully (dry-run mode)" "${tmpdir}/output.log"; then - cat "${tmpdir}/output.log" >&2 - fail "${name} output did not contain dry-run success text" - fi - - if grep -Fq "Attempting secure download" "${tmpdir}/output.log"; then - cat "${tmpdir}/output.log" >&2 - fail "${name} attempted a package download during dry-run" - fi - - rm -rf "$tmpdir" -} - -assert_valid_help_succeeds() { - local tmpdir status - tmpdir="$(mktemp -d)" - copy_toolchain "$tmpdir" - - run_installer_in_copy "$tmpdir" --help - status=$? - - if [[ "$status" -ne 0 ]]; then - cat "${tmpdir}/output.log" >&2 - fail "--help exited ${status}; expected 0" - fi - - if ! grep -Fq "install_abacus_toolchain_new.sh [OPTIONS]" "${tmpdir}/output.log"; then - cat "${tmpdir}/output.log" >&2 - fail "--help output did not contain usage text" - fi - - rm -rf "$tmpdir" -} - assert_invalid_input_fails "invalid package version" "Invalid package version format" --dry-run --package-version bad:wrong -assert_invalid_input_fails "missing package version value" "--package-version requires at least one package:version argument" --dry-run --package-version -assert_invalid_input_fails "invalid mpi mode" "Invalid MPI mode: invalid" --dry-run --mpi-mode invalid assert_invalid_input_fails "invalid gpu version" "Invalid GPU version" --dry-run --gpu-ver bad -assert_valid_dry_run_succeeds "explicit system openblas dry-run" --dry-run --with-openblas=system -assert_valid_help_succeeds if [[ "$FAILURES" -ne 0 ]]; then printf '%s installer argument failure test(s) failed\n' "$FAILURES" >&2 diff --git a/toolchain/tests/test_rapidjson_cmake.sh b/toolchain/tests/test_rapidjson_cmake.sh index b138967563..9454414915 100755 --- a/toolchain/tests/test_rapidjson_cmake.sh +++ b/toolchain/tests/test_rapidjson_cmake.sh @@ -171,16 +171,8 @@ test_top_level_rejects_variable_only_package() { rm -rf "$tmpdir" } -test_aocc_build_script_does_not_override_rapidjson_dir() { - local script="${REPO_ROOT}/toolchain/build_abacus_aocc-aocl.sh" - if grep -Fq -- '-DRapidJSON_DIR=$RAPIDJSON' "$script"; then - fail "${script} still passes RapidJSON_DIR as the package prefix" - fi -} - test_top_level_accepts_rapidjson_target_package test_top_level_rejects_variable_only_package -test_aocc_build_script_does_not_override_rapidjson_dir if [[ "$FAILURES" -ne 0 ]]; then printf '%s RapidJSON CMake test(s) failed\n' "$FAILURES" >&2 From a8204ba649647e9a342ac5d6e72de5277b645126 Mon Sep 17 00:00:00 2001 From: QuantumMisaka Date: Sun, 5 Jul 2026 16:25:12 +0800 Subject: [PATCH 11/11] test: keep RapidJSON coverage focused --- toolchain/tests/test_rapidjson_cmake.sh | 59 ------------------------- 1 file changed, 59 deletions(-) diff --git a/toolchain/tests/test_rapidjson_cmake.sh b/toolchain/tests/test_rapidjson_cmake.sh index 9454414915..0b3c0e689f 100755 --- a/toolchain/tests/test_rapidjson_cmake.sh +++ b/toolchain/tests/test_rapidjson_cmake.sh @@ -20,7 +20,6 @@ get_filename_component(_rapidjson_prefix "${RapidJSON_CMAKE_DIR}/../../.." ABSOL if(NOT TARGET RapidJSON) add_library(RapidJSON INTERFACE IMPORTED) set_property(TARGET RapidJSON PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${_rapidjson_prefix}/include") - set_property(TARGET RapidJSON PROPERTY INTERFACE_COMPILE_DEFINITIONS ABACUS_TEST_RAPIDJSON_TARGET_USAGE) endif() EOF } @@ -51,9 +50,6 @@ run_top_level_configure() { local prefix="$2" local mkl_root="$3" - mkdir -p "${build_dir}/.cmake/api/v1/query" - touch "${build_dir}/.cmake/api/v1/query/codemodel-v2" - cmake -S "$REPO_ROOT" -B "$build_dir" \ -DENABLE_RAPIDJSON=ON \ -DENABLE_LCAO=OFF \ @@ -64,58 +60,6 @@ run_top_level_configure() { >"${build_dir}.log" 2>&1 } -assert_abacus_target_has_rapidjson_usage() { - local build_dir="$1" - - python3 - "$build_dir" <<'PY' -import json -import pathlib -import sys - -build_dir = pathlib.Path(sys.argv[1]) -reply_dir = build_dir / ".cmake" / "api" / "v1" / "reply" - -try: - index_file = next(reply_dir.glob("index-*.json")) - index = json.loads(index_file.read_text()) - codemodel_file = reply_dir / index["reply"]["codemodel-v2"]["jsonFile"] - codemodel = json.loads(codemodel_file.read_text()) - target_refs = [ - target - for target in codemodel["configurations"][0]["targets"] - if target["name"].startswith("abacus_") - ] -except (KeyError, StopIteration, FileNotFoundError, json.JSONDecodeError) as exc: - print(f"failed to read CMake File API codemodel: {exc}", file=sys.stderr) - sys.exit(1) - -if len(target_refs) != 1: - names = ", ".join(sorted(target["name"] for target in target_refs)) or "" - print(f"expected exactly one ABACUS executable target, got: {names}", file=sys.stderr) - sys.exit(1) - -target_ref = target_refs[0] -target = json.loads((reply_dir / target_ref["jsonFile"]).read_text()) -definitions = { - definition["define"] - for group in target.get("compileGroups", []) - for definition in group.get("defines", []) - if "define" in definition -} -required = {"__RAPIDJSON", "ABACUS_TEST_RAPIDJSON_TARGET_USAGE"} -missing = sorted(required - definitions) - -if missing: - observed = ", ".join(sorted(definitions)) or "" - print( - f"{target_ref['name']} is missing RapidJSON definitions: {', '.join(missing)}", - file=sys.stderr, - ) - print(f"observed definitions: {observed}", file=sys.stderr) - sys.exit(1) -PY -} - test_top_level_accepts_rapidjson_target_package() { local tmpdir prefix mkl_root build_dir status tmpdir="$(mktemp -d)" @@ -140,9 +84,6 @@ test_top_level_accepts_rapidjson_target_package() { elif [[ "$status" -ne 0 ]]; then cat "${build_dir}.log" >&2 fail "top-level CMake failed with a RapidJSON target package" - elif ! assert_abacus_target_has_rapidjson_usage "$build_dir"; then - cat "${build_dir}.log" >&2 - fail "top-level CMake did not propagate RapidJSON feature and target usage" fi rm -rf "$tmpdir"