Skip to content

Commit 86ae025

Browse files
[toolchain] Harden installation failure handling and RapidJSON CMake support (#7583)
* test: cover toolchain wrapper failure propagation * fix: preserve toolchain wrapper installer failures * test: cover toolchain argument failure exits * fix: propagate toolchain argument parsing failures * test: cover RapidJSON CMake package compatibility * fix: support installed RapidJSON CMake packages * fix: require RapidJSON exported CMake target * test: harden RapidJSON CMake coverage * fix: disable default OpenMPI binding in setup * test: trim redundant toolchain checks * test: keep RapidJSON coverage focused --------- Co-authored-by: Mohan Chen <mohanchen@pku.edu.cn>
1 parent c43b14e commit 86ae025

15 files changed

Lines changed: 472 additions & 33 deletions

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ endfunction()
9393
# enable json support
9494
if(ENABLE_RAPIDJSON)
9595
find_package(RapidJSON CONFIG REQUIRED)
96+
if(NOT TARGET RapidJSON)
97+
message(
98+
FATAL_ERROR
99+
"RapidJSON was found, but target RapidJSON is missing. Check if your RapidJSON installation provides a complete exported CMake configuration."
100+
)
101+
endif()
96102
abacus_add_feature_definitions(__RAPIDJSON)
97103
endif()
98104

toolchain/build_abacus_aocc-aocl.sh

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ rm -rf $BUILD_DIR
2424
PREFIX=$ABACUS_DIR
2525
ELPA=${ELPA_ROOT}
2626
CEREAL=${CEREAL_ROOT}/include
27-
RAPIDJSON=${RAPIDJSON_ROOT}
2827
LAPACK=$AOCLhome/lib
2928
SCALAPACK=$AOCLhome/lib
3029
FFTW3=$AOCLhome
@@ -75,7 +74,6 @@ cmake -B $BUILD_DIR -DCMAKE_INSTALL_PREFIX=$PREFIX \
7574
-DUSE_OPENMP=ON \
7675
-DUSE_ELPA=ON \
7776
-DENABLE_RAPIDJSON=ON \
78-
-DRapidJSON_DIR=$RAPIDJSON \
7977
-DENABLE_LIBRI=ON \
8078
-DLIBRI_DIR=$LIBRI \
8179
-DLIBCOMM_DIR=$LIBCOMM \

toolchain/install_abacus_toolchain_new.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ main() {
5050
# Initialize configuration with command line arguments
5151
if ! config_init "${args[@]}"; then
5252
show_help
53-
exit 0
53+
exit 1
5454
fi
5555

5656
# Handle special version-related requests

toolchain/scripts/lib/config_manager.sh

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -456,13 +456,13 @@ config_validate() {
456456
if [[ -n "${CONFIG_CACHE[NPROCS_OVERWRITE]}" ]]; then
457457
if ! [[ "${CONFIG_CACHE[NPROCS_OVERWRITE]}" =~ ^[0-9]+$ ]]; then
458458
report_error ${LINENO} "Invalid number of processes: ${CONFIG_CACHE[NPROCS_OVERWRITE]}"
459-
exit 1
459+
return 1
460460
fi
461461
fi
462462

463463
if ! [[ "${CONFIG_CACHE[LOG_LINES]}" =~ ^[0-9]+$ ]]; then
464464
report_error ${LINENO} "Invalid log lines value: ${CONFIG_CACHE[LOG_LINES]}"
465-
exit 1
465+
return 1
466466
fi
467467

468468
# Validate GPU version - support only numeric formats
@@ -476,7 +476,7 @@ config_validate() {
476476
CONFIG_CACHE["ARCH_NUM"]="$arch_num"
477477
else
478478
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.)"
479-
exit 1
479+
return 1
480480
fi
481481
else
482482
CONFIG_CACHE["ARCH_NUM"]="no"
@@ -1166,27 +1166,37 @@ config_parse_arguments() {
11661166
config_init() {
11671167
# Set defaults first
11681168
config_set_defaults
1169-
1169+
11701170
# Initialize version helper to ensure VERSION_STRATEGY defaults are set
11711171
if command -v version_helper_init > /dev/null 2>&1; then
11721172
version_helper_init
11731173
fi
1174-
1174+
11751175
# Load configuration from file (if available) - this will override defaults
1176-
config_load_from_file
1177-
1176+
if ! config_load_from_file; then
1177+
return 1
1178+
fi
1179+
11781180
# Apply mode-based configurations from file - this will override defaults
1179-
config_apply_modes_from_file
1180-
1181+
if ! config_apply_modes_from_file; then
1182+
return 1
1183+
fi
1184+
11811185
# Parse command line arguments - this will override file settings
1182-
config_parse_arguments "$@"
1183-
1186+
if ! config_parse_arguments "$@"; then
1187+
return 1
1188+
fi
1189+
11841190
# Apply mode-based configurations from command line
1185-
config_apply_modes
1186-
1191+
if ! config_apply_modes; then
1192+
return 1
1193+
fi
1194+
11871195
# Validate configuration
1188-
config_validate
1189-
1196+
if ! config_validate; then
1197+
return 1
1198+
fi
1199+
11901200
return 0
11911201
}
11921202

@@ -1262,4 +1272,6 @@ config_apply_modes() {
12621272
;;
12631273
esac
12641274
fi
1275+
1276+
return 0
12651277
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/usr/bin/env bash
2+
3+
run_toolchain_with_log() {
4+
local log_file="$1"
5+
shift
6+
7+
"$@" | tee "$log_file"
8+
local installer_status=${PIPESTATUS[0]}
9+
10+
return "$installer_status"
11+
}

toolchain/scripts/stage1/install_openmpi.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ else
167167
grep "(Open MPI)" | awk '{print $4}')
168168
major_version=$(echo ${raw_version} | cut -d '.' -f 1)
169169
minor_version=$(echo ${raw_version} | cut -d '.' -f 2)
170+
OPENMPI_BINDING_POLICY_ENV="export OMPI_MCA_hwloc_base_binding_policy=none"
171+
if [[ "${major_version}" =~ ^[0-9]+$ && "${major_version}" -ge 5 ]]; then
172+
OPENMPI_BINDING_POLICY_ENV="export PRTE_MCA_hwloc_default_binding_policy=none"
173+
fi
170174
OPENMPI_LIBS=""
171175
# grab additional runtime libs (for C/C++) from the mpicxx wrapper,
172176
# and remove them from the LDFLAGS if present
@@ -182,6 +186,7 @@ export MPICXX="${MPICXX}"
182186
export MPIFC="${MPIFC}"
183187
export MPIFORT="${MPIFORT}"
184188
export MPIF77="${MPIF77}"
189+
${OPENMPI_BINDING_POLICY_ENV}
185190
export OPENMPI_CFLAGS="${OPENMPI_CFLAGS}"
186191
export OPENMPI_LDFLAGS="${OPENMPI_LDFLAGS}"
187192
export OPENMPI_LIBS="${OPENMPI_LIBS}"
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env bash
2+
set -u
3+
4+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)"
5+
TOOLCHAIN_DIR="${REPO_ROOT}/toolchain"
6+
FAILURES=0
7+
8+
fail() {
9+
printf 'FAIL: %s\n' "$*" >&2
10+
FAILURES=$((FAILURES + 1))
11+
}
12+
13+
copy_toolchain() {
14+
local tmpdir="$1"
15+
local entry name
16+
mkdir -p "${tmpdir}/toolchain"
17+
while IFS= read -r -d '' entry; do
18+
name="${entry##*/}"
19+
case "$name" in
20+
build|install) continue ;;
21+
esac
22+
cp -a "$entry" "${tmpdir}/toolchain/"
23+
done < <(find "${TOOLCHAIN_DIR}" -mindepth 1 -maxdepth 1 -print0)
24+
}
25+
26+
run_installer_in_copy() {
27+
local tmpdir="$1"
28+
shift
29+
(cd "${tmpdir}/toolchain" && ./install_abacus_toolchain_new.sh "$@") >"${tmpdir}/output.log" 2>&1
30+
}
31+
32+
assert_invalid_input_fails() {
33+
local name="$1"
34+
local expected_text="$2"
35+
shift 2
36+
37+
local tmpdir status
38+
tmpdir="$(mktemp -d)"
39+
copy_toolchain "$tmpdir"
40+
41+
run_installer_in_copy "$tmpdir" "$@"
42+
status=$?
43+
44+
if [[ "$status" -eq 0 ]]; then
45+
cat "${tmpdir}/output.log" >&2
46+
fail "${name} exited 0; expected nonzero"
47+
fi
48+
49+
if ! grep -Fq -- "$expected_text" "${tmpdir}/output.log"; then
50+
cat "${tmpdir}/output.log" >&2
51+
fail "${name} did not report expected error: ${expected_text}"
52+
fi
53+
54+
if ! grep -Fq "install_abacus_toolchain_new.sh [OPTIONS]" "${tmpdir}/output.log"; then
55+
cat "${tmpdir}/output.log" >&2
56+
fail "${name} output did not contain usage text"
57+
fi
58+
59+
if [[ -e "${tmpdir}/toolchain/install/setup" ]]; then
60+
fail "${name} wrote install/setup even though argument parsing failed"
61+
fi
62+
63+
rm -rf "$tmpdir"
64+
}
65+
66+
assert_invalid_input_fails "invalid package version" "Invalid package version format" --dry-run --package-version bad:wrong
67+
assert_invalid_input_fails "invalid gpu version" "Invalid GPU version" --dry-run --gpu-ver bad
68+
69+
if [[ "$FAILURES" -ne 0 ]]; then
70+
printf '%s installer argument failure test(s) failed\n' "$FAILURES" >&2
71+
exit 1
72+
fi
73+
74+
printf 'installer argument failure tests passed\n'
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#!/usr/bin/env bash
2+
set -u
3+
4+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd -P)"
5+
TOOLCHAIN_DIR="${REPO_ROOT}/toolchain"
6+
FAILURES=0
7+
8+
fail() {
9+
printf 'FAIL: %s\n' "$*" >&2
10+
FAILURES=$((FAILURES + 1))
11+
}
12+
13+
write_fake_openmpi_commands() {
14+
local bindir="$1"
15+
local version="$2"
16+
17+
mkdir -p "$bindir"
18+
cat >"${bindir}/mpiexec" <<EOF
19+
#!/usr/bin/env bash
20+
if [[ "\$1" == "--version" ]]; then
21+
printf 'mpiexec (Open MPI) ${version}\n'
22+
exit 0
23+
fi
24+
exit 0
25+
EOF
26+
cat >"${bindir}/mpicxx" <<'EOF'
27+
#!/usr/bin/env bash
28+
if [[ "$1" == "--showme:libs" ]]; then
29+
printf 'mpi\n'
30+
exit 0
31+
fi
32+
exit 0
33+
EOF
34+
cp "${bindir}/mpicxx" "${bindir}/mpicc"
35+
cp "${bindir}/mpicxx" "${bindir}/mpifort"
36+
chmod +x "${bindir}/mpiexec" "${bindir}/mpicc" "${bindir}/mpicxx" "${bindir}/mpifort"
37+
}
38+
39+
run_openmpi_system_setup() {
40+
local tmpdir="$1"
41+
local version="$2"
42+
43+
mkdir -p "${tmpdir}/install" "${tmpdir}/build"
44+
: >"${tmpdir}/install/setup"
45+
: >"${tmpdir}/install/toolchain.env"
46+
cat >"${tmpdir}/install/toolchain.conf" <<'EOF'
47+
MPI_MODE="openmpi"
48+
with_openmpi="__SYSTEM__"
49+
PACK_RUN="__FALSE__"
50+
EOF
51+
52+
write_fake_openmpi_commands "${tmpdir}/fake-bin" "$version"
53+
PATH="${tmpdir}/fake-bin:${PATH}" \
54+
ROOTDIR="$tmpdir" \
55+
SCRIPTDIR="${TOOLCHAIN_DIR}/scripts" \
56+
INSTALLDIR="${tmpdir}/install" \
57+
BUILDDIR="${tmpdir}/build" \
58+
SETUPFILE="${tmpdir}/install/setup" \
59+
bash "${TOOLCHAIN_DIR}/scripts/stage1/install_openmpi.sh" \
60+
>"${tmpdir}/openmpi.log" 2>&1
61+
}
62+
63+
assert_setup_contains() {
64+
local file="$1"
65+
local expected="$2"
66+
67+
if ! grep -Fq "$expected" "$file"; then
68+
cat "$file" >&2
69+
fail "${file} does not contain expected text: ${expected}"
70+
fi
71+
}
72+
73+
assert_setup_not_contains() {
74+
local file="$1"
75+
local unexpected="$2"
76+
77+
if grep -Fq "$unexpected" "$file"; then
78+
cat "$file" >&2
79+
fail "${file} contains unexpected text: ${unexpected}"
80+
fi
81+
}
82+
83+
test_openmpi5_setup_disables_prte_binding() {
84+
local tmpdir status
85+
tmpdir="$(mktemp -d)"
86+
87+
run_openmpi_system_setup "$tmpdir" "5.0.10"
88+
status=$?
89+
90+
if [[ "$status" -ne 0 ]]; then
91+
cat "${tmpdir}/openmpi.log" >&2
92+
fail "OpenMPI 5 setup generation failed with status ${status}"
93+
else
94+
assert_setup_contains "${tmpdir}/install/setup" "export PRTE_MCA_hwloc_default_binding_policy=none"
95+
assert_setup_not_contains "${tmpdir}/install/setup" "export OMPI_MCA_hwloc_base_binding_policy=none"
96+
fi
97+
98+
rm -rf "$tmpdir"
99+
}
100+
101+
test_openmpi4_setup_disables_ompi_binding() {
102+
local tmpdir status
103+
tmpdir="$(mktemp -d)"
104+
105+
run_openmpi_system_setup "$tmpdir" "4.1.8"
106+
status=$?
107+
108+
if [[ "$status" -ne 0 ]]; then
109+
cat "${tmpdir}/openmpi.log" >&2
110+
fail "OpenMPI 4 setup generation failed with status ${status}"
111+
else
112+
assert_setup_contains "${tmpdir}/install/setup" "export OMPI_MCA_hwloc_base_binding_policy=none"
113+
assert_setup_not_contains "${tmpdir}/install/setup" "export PRTE_MCA_hwloc_default_binding_policy=none"
114+
fi
115+
116+
rm -rf "$tmpdir"
117+
}
118+
119+
test_openmpi5_setup_disables_prte_binding
120+
test_openmpi4_setup_disables_ompi_binding
121+
122+
if [[ "$FAILURES" -ne 0 ]]; then
123+
printf '%s OpenMPI binding policy setup test(s) failed\n' "$FAILURES" >&2
124+
exit 1
125+
fi
126+
127+
printf 'OpenMPI binding policy setup tests passed\n'

0 commit comments

Comments
 (0)