Skip to content

Commit ac1b607

Browse files
committed
Require mpi-extensions prefix for MPI builds
1 parent 579e0af commit ac1b607

10 files changed

Lines changed: 142 additions & 45 deletions

File tree

.github/actions/setup-mpi-extensions/action.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,4 @@ runs:
2424
--platform "${{ inputs.platform }}"
2525
--purge-system-mpi "${{ inputs.purge-system-mpi }}"
2626
--github-env "$GITHUB_ENV"
27-
--github-path "$GITHUB_PATH"
2827
--runner-temp "${{ runner.temp }}"

.github/actions/setup-mpi-extensions/setup_mpi_extensions.py

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import sys
1111
from pathlib import Path
1212

13-
1413
MPI_PACKAGES_LINUX = [
1514
"mpich",
1615
"libmpich-dev",
@@ -32,7 +31,6 @@ def parse_args() -> argparse.Namespace:
3231
parser.add_argument("--platform", required=True)
3332
parser.add_argument("--purge-system-mpi", choices=["true", "false"], required=True)
3433
parser.add_argument("--github-env", required=True, type=Path)
35-
parser.add_argument("--github-path", required=True, type=Path)
3634
parser.add_argument("--runner-temp", required=True, type=Path)
3735
return parser.parse_args()
3836

@@ -140,23 +138,9 @@ def install_openmpi(args: argparse.Namespace, python_bin: Path) -> None:
140138
)
141139

142140

143-
def append_github_environment(
144-
prefix: Path, github_env: Path, github_path: Path
145-
) -> None:
146-
lib_path = prefix / "lib"
147-
env_lines = [
148-
f"MPI_EXTENSIONS_HOME={prefix}",
149-
f"MPI_HOME={prefix}",
150-
f"OPAL_PREFIX={prefix}",
151-
"OMPI_MCA_shmem=mmap",
152-
f"LD_LIBRARY_PATH={lib_path}:{os.environ.get('LD_LIBRARY_PATH', '')}",
153-
f"DYLD_LIBRARY_PATH={lib_path}:{os.environ.get('DYLD_LIBRARY_PATH', '')}",
154-
]
141+
def append_github_environment(prefix: Path, github_env: Path) -> None:
155142
with github_env.open("a", encoding="utf-8") as output:
156-
for line in env_lines:
157-
output.write(line + "\n")
158-
with github_path.open("a", encoding="utf-8") as output:
159-
output.write(str(prefix / "bin") + "\n")
143+
output.write(f"PPC_MPI_EXTENSIONS_HOME={prefix}\n")
160144

161145

162146
def validate_openmpi(prefix: Path) -> None:
@@ -186,7 +170,7 @@ def main() -> int:
186170
purge_system_mpi(args.purge_system_mpi == "true")
187171
python_bin = prepare_python(args.runner_temp)
188172
install_openmpi(args, python_bin)
189-
append_github_environment(prefix, args.github_env, args.github_path)
173+
append_github_environment(prefix, args.github_env)
190174
validate_openmpi(prefix)
191175
return 0
192176

.github/workflows/codeql.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ jobs:
5353
run: >
5454
cmake -S . -B build -G Ninja
5555
-D CMAKE_BUILD_TYPE=RELEASE
56+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
5657
env:
5758
CC: gcc-15
5859
CXX: g++-15

.github/workflows/mac.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ jobs:
4141
-DCMAKE_C_FLAGS="-I$(brew --prefix)/opt/libomp/include"
4242
-DCMAKE_CXX_FLAGS="-I$(brew --prefix)/opt/libomp/include"
4343
-D CMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_INSTALL_PREFIX=install
44+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
4445
-D PPC_TASKS="${{ inputs.ppc_tasks }}"
4546
- name: Build project
4647
run: |

.github/workflows/static-analysis-pr.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ jobs:
7676
run: >
7777
cmake -S . -B build -G Ninja
7878
-D CMAKE_BUILD_TYPE=RELEASE -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON
79+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
7980
-D PPC_TASKS="${{ needs.ci-scope.outputs.ppc_tasks || 'all' }}"
8081
env:
8182
CC: clang-22
@@ -133,6 +134,7 @@ jobs:
133134
run: >
134135
cmake -S . -B build -G Ninja
135136
-D CMAKE_BUILD_TYPE=RELEASE -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_COMPILE_WARNING_AS_ERROR=ON
137+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
136138
-D PPC_TASKS="${{ needs.ci-scope.outputs.ppc_tasks || 'all' }}"
137139
env:
138140
CC: gcc-15

.github/workflows/ubuntu.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ jobs:
4444
run: >
4545
cmake -S . -B build -G Ninja
4646
-D CMAKE_BUILD_TYPE=${{ matrix.build_type }} -DCMAKE_INSTALL_PREFIX=install
47+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
4748
-D PPC_TASKS="${{ inputs.ppc_tasks }}"
4849
env:
4950
CC: gcc-15
@@ -163,6 +164,7 @@ jobs:
163164
run: >
164165
cmake -S . -B build -G Ninja
165166
-D CMAKE_BUILD_TYPE=RELEASE -DCMAKE_INSTALL_PREFIX=install
167+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
166168
-D PPC_TASKS="${{ inputs.ppc_tasks }}"
167169
env:
168170
CC: clang-22
@@ -278,6 +280,7 @@ jobs:
278280
-D CMAKE_BUILD_TYPE=RelWithDebInfo
279281
-D ENABLE_ADDRESS_SANITIZER=ON -D ENABLE_UB_SANITIZER=ON -D ENABLE_LEAK_SANITIZER=ON
280282
-D CMAKE_INSTALL_PREFIX=install
283+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
281284
-D PPC_TASKS="${{ inputs.ppc_tasks }}"
282285
env:
283286
CC: clang-22
@@ -403,6 +406,7 @@ jobs:
403406
-D CMAKE_BUILD_TYPE=RELEASE
404407
-D CMAKE_VERBOSE_MAKEFILE=ON -D USE_COVERAGE=ON
405408
-DCMAKE_INSTALL_PREFIX=install
409+
-D PPC_MPI_EXTENSIONS_HOME="$PPC_MPI_EXTENSIONS_HOME"
406410
-D PPC_TASKS="${{ inputs.ppc_tasks }}"
407411
- name: Build project
408412
run: |

cmake/mpi.cmake

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,77 @@
11
include_guard()
22

3+
set(PPC_MPI_EXTENSIONS_HOME
4+
""
5+
CACHE PATH "Path to an unpacked mpi-extensions Open MPI package")
6+
7+
if(NOT WIN32)
8+
if(NOT PPC_MPI_EXTENSIONS_HOME)
9+
message(
10+
FATAL_ERROR
11+
"PPC_MPI_EXTENSIONS_HOME is required on Linux and macOS. "
12+
"Install the mpi-extensions nightly Open MPI package and configure with "
13+
"-DPPC_MPI_EXTENSIONS_HOME=/path/to/mpi-extensions-openmpi")
14+
endif()
15+
16+
get_filename_component(PPC_MPI_EXTENSIONS_HOME "${PPC_MPI_EXTENSIONS_HOME}"
17+
REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
18+
set(PPC_MPI_EXTENSIONS_HOME
19+
"${PPC_MPI_EXTENSIONS_HOME}"
20+
CACHE PATH "Path to an unpacked mpi-extensions Open MPI package" FORCE)
21+
22+
set(_PPC_MPI_EXTENSIONS_BIN "${PPC_MPI_EXTENSIONS_HOME}/bin")
23+
set(_PPC_MPI_EXTENSIONS_LIB "${PPC_MPI_EXTENSIONS_HOME}/lib")
24+
25+
foreach(tool mpicc mpicxx mpirun mpiexec)
26+
if(NOT EXISTS "${_PPC_MPI_EXTENSIONS_BIN}/${tool}")
27+
message(
28+
FATAL_ERROR
29+
"PPC_MPI_EXTENSIONS_HOME does not contain required tool '${tool}': "
30+
"${_PPC_MPI_EXTENSIONS_BIN}/${tool}")
31+
endif()
32+
endforeach()
33+
34+
if(NOT IS_DIRECTORY "${_PPC_MPI_EXTENSIONS_LIB}")
35+
message(
36+
FATAL_ERROR "PPC_MPI_EXTENSIONS_HOME does not contain a lib directory: "
37+
"${_PPC_MPI_EXTENSIONS_LIB}")
38+
endif()
39+
40+
set(MPI_C_COMPILER
41+
"${_PPC_MPI_EXTENSIONS_BIN}/mpicc"
42+
CACHE FILEPATH "mpi-extensions C MPI wrapper" FORCE)
43+
set(MPI_CXX_COMPILER
44+
"${_PPC_MPI_EXTENSIONS_BIN}/mpicxx"
45+
CACHE FILEPATH "mpi-extensions CXX MPI wrapper" FORCE)
46+
set(MPIEXEC_EXECUTABLE
47+
"${_PPC_MPI_EXTENSIONS_BIN}/mpirun"
48+
CACHE FILEPATH "mpi-extensions MPI launcher" FORCE)
49+
set(MPIEXEC_NUMPROC_FLAG
50+
"-np"
51+
CACHE STRING "MPI process count flag" FORCE)
52+
53+
list(PREPEND CMAKE_PREFIX_PATH "${PPC_MPI_EXTENSIONS_HOME}")
54+
list(PREPEND CMAKE_BUILD_RPATH "${_PPC_MPI_EXTENSIONS_LIB}")
55+
list(PREPEND CMAKE_INSTALL_RPATH "${_PPC_MPI_EXTENSIONS_LIB}")
56+
57+
set(_PPC_MPI_RUNTIME_CONFIG "${CMAKE_BINARY_DIR}/ppc_mpi_runtime_env.json")
58+
file(
59+
WRITE "${_PPC_MPI_RUNTIME_CONFIG}"
60+
"{\n"
61+
" \"mpi_extensions_home\": \"${PPC_MPI_EXTENSIONS_HOME}\",\n"
62+
" \"mpi_exec\": \"${MPIEXEC_EXECUTABLE}\",\n"
63+
" \"path_prepend\": \"${_PPC_MPI_EXTENSIONS_BIN}\",\n"
64+
" \"library_path_prepend\": \"${_PPC_MPI_EXTENSIONS_LIB}\",\n"
65+
" \"env\": {\n"
66+
" \"MPI_EXTENSIONS_HOME\": \"${PPC_MPI_EXTENSIONS_HOME}\",\n"
67+
" \"MPI_HOME\": \"${PPC_MPI_EXTENSIONS_HOME}\",\n"
68+
" \"OPAL_PREFIX\": \"${PPC_MPI_EXTENSIONS_HOME}\",\n"
69+
" \"OMPI_MCA_shmem\": \"mmap\"\n"
70+
" }\n"
71+
"}\n")
72+
install(FILES "${_PPC_MPI_RUNTIME_CONFIG}" DESTINATION ".")
73+
endif()
74+
375
find_package(MPI REQUIRED COMPONENTS CXX)
476
if(NOT MPI_FOUND)
577
message(FATAL_ERROR "MPI NOT FOUND")

docs/user_guide/environment.rst

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -102,25 +102,15 @@ Parallel Programming Technologies
102102
103103
python3 -m pip install 'requests>=2.31,<3'
104104
python3 scripts/install_mpi_extensions.py --prefix "$PWD/_deps/mpi-extensions-openmpi" --force
105-
export MPI_EXTENSIONS_HOME="$PWD/_deps/mpi-extensions-openmpi"
106-
export MPI_HOME="$MPI_EXTENSIONS_HOME"
107-
export OPAL_PREFIX="$MPI_EXTENSIONS_HOME"
108-
export OMPI_MCA_shmem=mmap
109-
export PATH="$MPI_EXTENSIONS_HOME/bin:$PATH"
110-
export LD_LIBRARY_PATH="$MPI_EXTENSIONS_HOME/lib:$LD_LIBRARY_PATH"
105+
cmake -S . -B build -D PPC_MPI_EXTENSIONS_HOME="$PWD/_deps/mpi-extensions-openmpi"
111106
112107
- **MacOS (apple clang)**:
113108

114109
.. code-block:: bash
115110
116111
python3 -m pip install 'requests>=2.31,<3'
117112
python3 scripts/install_mpi_extensions.py --prefix "$PWD/_deps/mpi-extensions-openmpi" --force
118-
export MPI_EXTENSIONS_HOME="$PWD/_deps/mpi-extensions-openmpi"
119-
export MPI_HOME="$MPI_EXTENSIONS_HOME"
120-
export OPAL_PREFIX="$MPI_EXTENSIONS_HOME"
121-
export OMPI_MCA_shmem=mmap
122-
export PATH="$MPI_EXTENSIONS_HOME/bin:$PATH"
123-
export DYLD_LIBRARY_PATH="$MPI_EXTENSIONS_HOME/lib:$DYLD_LIBRARY_PATH"
113+
cmake -S . -B build -D PPC_MPI_EXTENSIONS_HOME="$PWD/_deps/mpi-extensions-openmpi"
124114
125115
``OpenMP``
126116
~~~~~~~~~~

scripts/install_mpi_extensions.py

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -276,13 +276,8 @@ def patch_macos_install_names(prefix: Path) -> None:
276276

277277
def print_environment(prefix: Path) -> None:
278278
prefix_text = str(prefix)
279-
print(f"MPI_EXTENSIONS_HOME={prefix_text}")
280-
print(f"MPI_HOME={prefix_text}")
281-
print(f"OPAL_PREFIX={prefix_text}")
282-
print("OMPI_MCA_shmem=mmap")
283-
print(f"PATH={prefix_text}/bin:$PATH")
284-
print(f"LD_LIBRARY_PATH={prefix_text}/lib:$LD_LIBRARY_PATH")
285-
print(f"DYLD_LIBRARY_PATH={prefix_text}/lib:$DYLD_LIBRARY_PATH")
279+
print(f"PPC_MPI_EXTENSIONS_HOME={prefix_text}")
280+
print(f"CMake option: -DPPC_MPI_EXTENSIONS_HOME={prefix_text}")
286281

287282

288283
def main() -> int:

scripts/run_tests.py

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
22

3+
import json
34
import os
45
import platform
56
import shlex
@@ -67,15 +68,12 @@ def __init__(self, build_dir="build", verbose=False):
6768
self.mpi_exec = "mpirun"
6869
self.platform = platform.system()
6970

70-
# Detect MPI implementation to choose compatible flags
71-
self.mpi_env_mode = "unknown" # one of: openmpi, mpich, unknown
72-
self.mpi_np_flag = "-np"
7371
if self.platform == "Windows":
74-
# MSMPI uses -env and -n
7572
self.mpi_env_mode = "mpich"
7673
self.mpi_np_flag = "-n"
7774
else:
78-
self.mpi_env_mode, self.mpi_np_flag = self.__detect_mpi_impl()
75+
self.mpi_env_mode = "unknown"
76+
self.mpi_np_flag = "-np"
7977

8078
@staticmethod
8179
def __get_project_path():
@@ -105,18 +103,68 @@ def setup_env(self, ppc_env):
105103
build_dir = project_path / build_dir
106104
self.__build_dir_path = build_dir
107105

108-
install_bin_dir = project_path / "install" / "bin"
106+
install_dir = project_path / "install"
107+
install_bin_dir = install_dir / "bin"
109108
if install_bin_dir.exists():
109+
self.__apply_mpi_runtime_config(install_dir / "ppc_mpi_runtime_env.json")
110110
self.work_dir = install_bin_dir
111+
self.__detect_configured_mpi()
111112
return
112113

114+
self.__apply_mpi_runtime_config(build_dir / "ppc_mpi_runtime_env.json")
113115
bin_dir = build_dir if build_dir.name == "bin" else build_dir / "bin"
114116
if not bin_dir.exists():
115117
raise FileNotFoundError(
116118
f"Test binaries directory not found: '{bin_dir}'. "
117119
"Build the project or pass a correct '--build-dir' (e.g. 'build', 'build_seq', or 'build/bin')."
118120
)
119121
self.work_dir = bin_dir
122+
self.__detect_configured_mpi()
123+
124+
def __prepend_env_path(self, name, value):
125+
current = self.__ppc_env.get(name)
126+
self.__ppc_env[name] = (
127+
str(value) if not current else f"{value}{os.pathsep}{current}"
128+
)
129+
130+
def __apply_mpi_runtime_config(self, config_path):
131+
if self.platform == "Windows":
132+
return
133+
134+
if not config_path.exists():
135+
raise FileNotFoundError(
136+
f"MPI runtime config not found: '{config_path}'. "
137+
"Configure CMake with -DPPC_MPI_EXTENSIONS_HOME=/path/to/mpi-extensions-openmpi."
138+
)
139+
140+
with config_path.open(encoding="utf-8") as input_file:
141+
config = json.load(input_file)
142+
143+
env_values = config.get("env", {})
144+
for name, value in env_values.items():
145+
self.__ppc_env[name] = str(value)
146+
147+
path_prepend = config.get("path_prepend")
148+
if path_prepend:
149+
self.__prepend_env_path("PATH", path_prepend)
150+
151+
library_path_prepend = config.get("library_path_prepend")
152+
if library_path_prepend:
153+
self.__prepend_env_path("LD_LIBRARY_PATH", library_path_prepend)
154+
self.__prepend_env_path("DYLD_LIBRARY_PATH", library_path_prepend)
155+
156+
mpi_exec = config.get("mpi_exec")
157+
if mpi_exec:
158+
mpi_exec_path = Path(mpi_exec)
159+
if not mpi_exec_path.exists():
160+
raise FileNotFoundError(
161+
f"Configured MPI launcher not found: '{mpi_exec_path}'"
162+
)
163+
self.mpi_exec = str(mpi_exec_path)
164+
165+
def __detect_configured_mpi(self):
166+
if self.platform != "Windows":
167+
self.mpi_env_mode, self.mpi_np_flag = self.__detect_mpi_impl()
120168

121169
def __run_exec(self, command, extra_env=None):
122170
if self.verbose:
@@ -142,6 +190,7 @@ def __detect_mpi_impl(self):
142190
stdout=subprocess.PIPE,
143191
stderr=subprocess.STDOUT,
144192
text=True,
193+
env=self.__ppc_env,
145194
)
146195
out = (proc.stdout or "").lower()
147196
if out:

0 commit comments

Comments
 (0)