PAYATHON 2026

OS X 上如何配置 Open MPI 与 Fortran 运行 ExoPlaSim

排障赵师傅

结论

应先解决最早出现的错误:ld: library not found for -lm。这说明链接器找不到 macOS 数学库 libm,导致 plasim.x 未能生成。随后出现的 cp: plasim.x: No such file or directory、MPI 返回 134 和 ExoPlaSim 崩溃,基本都是编译失败带来的连锁错误。

问题通常出在工具链:macOS SDK、GNU Fortran 和 Open MPI 可能来自不同环境,或者 GCC 没有找到当前 SDK。macOS Big Sur 已不再依赖 /usr/lib/libm.dylib 这样的独立文件,-lm 一般通过 macOS SDK 中的 libm.tbd 解析。

先检查 macOS SDK

先确认 Xcode Command Line Tools 是否已经安装:

xcode-select -p
xcrun --sdk macosx --show-sdk-path

第二条命令应返回有效的 SDK 路径。然后检查该路径中是否有 libm.tbd:

SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
ls "$SDKROOT/usr/lib/libm.tbd"

如果 xcode-select 或 xcrun 报错,安装 Command Line Tools:

xcode-select --install

如果工具已经安装,但当前选中的开发目录无效,可切换到 Command Line Tools:

sudo xcode-select --switch /Library/Developer/CommandLineTools

如果使用的是完整 Xcode,则切换到对应路径:

sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer

切换完成后,再次执行 xcrun --sdk macosx --show-sdk-path。

检查是否混用了不同工具链

Homebrew 在 Intel Mac 上通常安装在 /usr/local,在 Apple Silicon Mac 上通常安装在 /opt/homebrew。如果路径中同时出现这两个前缀,或者混入了从其他网站下载的 GCC,SDK 或程序架构可能会不一致。

运行以下命令检查环境:

uname -m
brew --prefix

which -a gcc
which -a gfortran
which -a mpifort
which -a mpiexec

gfortran --version
mpifort --showme:command
mpifort --showme:compile
mpifort --showme:link

检查这些结果:

  • gfortran、mpifort 和 mpiexec 是否来自同一个 Homebrew 前缀。
  • mpifort --showme:command 是否指向实际安装的 GNU Fortran。
  • 路径中是否还残留 MacPorts、手动安装的 Open MPI 或旧版 Homebrew。
  • Apple Silicon 机器上是否混用了 arm64 和 x86_64 程序。

还可以检查程序架构:

file "$(command -v gfortran)"
file "$(command -v mpiexec)"

mpifort 是 Open MPI 的编译包装器。即使系统能够找到 mpiexec,Fortran 编译包装器也可能没有正确配置。

单独测试 GNU Fortran 与 -lm

暂时不要运行 ExoPlaSim,先创建一个最小程序:

program test_math
  implicit none
  print *, sqrt(4.0)
end program test_math

保存为 test_math.f90,然后编译并运行:

gfortran test_math.f90 -lm -o test_math
./test_math

如果这里也出现:

ld: library not found for -lm

就可以把问题定位到 GCC、SDK 或链接环境,暂时不用检查 ExoPlaSim 和 MPI。

接下来可在当前终端中显式指定 SDK,再测试一次:

export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
gfortran test_math.f90 -Wl,-syslibroot,"$SDKROOT" -lm -o test_math
./test_math

也可以暂时将 SDK 的库目录加入 GCC 的链接搜索路径:

export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
export LIBRARY_PATH="$SDKROOT/usr/lib${LIBRARY_PATH:+:$LIBRARY_PATH}"

gfortran test_math.f90 -lm -o test_math

如果显式指定 SDK 后可以编译,说明当前 GCC 没有自动获取正确的 macOS sysroot。这些环境变量适合用来诊断问题。在确认原因之前,不建议将它们永久写入 shell 配置。

不要使用 DYLD_LIBRARY_PATH 处理这个错误。该变量主要影响程序运行时加载动态库,而这里的问题发生在链接阶段。

用同一套 Homebrew 工具链重新安装

如果 SDK 正常,但 Homebrew 和编译器路径混乱,可以先重装 GCC,再重装 Open MPI。Open MPI 的 Fortran 包装器随后会采用当前可用的编译器配置:

brew update
brew reinstall gcc
brew reinstall open-mpi
hash -r

安装完成后重新检查:

command -v gfortran
command -v mpifort
command -v mpiexec

gfortran --version
mpifort --showme:command

Homebrew 对旧版 macOS 的支持范围会随时间调整。如果当前 Homebrew 已经不支持 Big Sur,brew update 或重装公式时可能直接显示系统版本警告。此时应先保留现有环境,根据报错选择兼容 Big Sur 的 Homebrew 和 GCC 版本,不要直接升级到最新工具链。

验证 Open MPI 的 Fortran 支持

普通 Fortran 链接测试通过后,再测试 MPI:

program mpi_hello
  use mpi
  implicit none

  integer :: ierr, rank, size

  call MPI_Init(ierr)
  call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierr)
  call MPI_Comm_size(MPI_COMM_WORLD, size, ierr)

  print *, "rank", rank, "of", size

  call MPI_Finalize(ierr)
end program mpi_hello

将程序保存为 mpi_hello.f90,然后运行:

mpifort mpi_hello.f90 -o mpi_hello
mpiexec -n 2 ./mpi_hello

这两条命令都成功后,才能确认 Open MPI、Fortran 编译器和运行时组成了一套可用的工具链。

如果没有 mpifort,或者 mpifort --showme:command 指向已经删除的编译器,说明当前 Open MPI 缺少可用的 Fortran 包装配置。先安装好 GCC,再重新安装 Open MPI。

重新运行 ExoPlaSim

重新触发 ExoPlaSim 编译前,确认以下检查均已通过:

  1. xcrun --sdk macosx --show-sdk-path 返回有效路径。
  2. gfortran test_math.f90 -lm 能成功链接。
  3. mpifort mpi_hello.f90 能成功编译。
  4. mpiexec -n 2 ./mpi_hello 能正常运行。

之前失败的工作目录中可能留有未完成的构建文件。先查看 ExoPlaSim 报告的 mymodel_crashed 和原工作目录,只清理本次失败产生的文件,再重新运行基础案例。

如果最小 Fortran 测试已经通过,ExoPlaSim 却仍在 -lm 处失败,应查看构建日志,确认 makefile 实际调用了哪个编译器。终端中的 gfortran 可能已经正常,但 makefile 仍硬编码了其他版本,如 gfortran-9、gcc-11,也可能调用了另一套 mpifort。这种情况下,应调整构建环境中的 PATH、FC 或 makefile 编译器变量,无需修改 Python 案例的模型参数。

例如,可在启动 Python 前明确指定当前工具链:

export PATH="$(brew --prefix)/bin:$PATH"
export FC="$(command -v gfortran)"
export MPIFC="$(command -v mpifort)"
export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"

python3 testing_exoplasim.py

ExoPlaSim 是否采用 FC 和 MPIFC,取决于其 makefile 的写法。如果构建命令仍调用其他编译器,应以完整编译日志中的实际命令为准。

暂时不用处理 cp、plasim_restart 或 Python 的 CalledProcessError。只要 plasim.x 没有成功链接,这些错误就会继续出现。先让最小 gfortran -lm 测试通过,再验证 mpifort,通常就能确定问题出在哪一层。

备注:内容仅供参考。