FindMPI

查找消息传递接口 (MPI) 实现

find_package(MPI [<version>] [COMPONENTS <langs>...] [...])

消息传递接口 (MPI) 是一个用于编写高性能分布式内存并行应用程序的库,通常部署在集群上。MPI 是一个标准接口(由 MPI 论坛定义),有许多可用实现。

版本 3.10 中添加: 模块重大改版:新增许多变量、按语言划分的组件以及对更多样化运行时环境的支持。

组件

此模块支持可选组件,可以使用 find_package() 命令指定,以控制要搜索的 MPI 语言。

find_package(MPI [COMPONENTS <langs>...])

支持的组件包括

C

3.10 版本新增。

查找 MPI C API。

CXX

3.10 版本新增。

查找可从 C++ 使用的 MPI C API。

MPICXX

3.10 版本新增。

查找 MPI-2 C++ API,该 API 在 MPI-3 中已移除。

Fortran

3.10 版本新增。

查找 MPI Fortran API。

如果未指定任何组件,模块将自动搜索 CCXXFortran 组件,具体取决于项目中启用的语言。

导入的目标

此模块提供以下 导入目标

MPI::MPI_<lang>

版本 3.9 中添加。

封装了使用语言 <lang> 中的 MPI 所需的依赖项的 Target,如果找到 MPI 则可用。<lang> 是上述组件名称之一。

结果变量

此模块定义了以下变量

MPI_FOUND

布尔值,指示是否找到了所有请求组件(语言)的 MPI 设置。如果未指定任何组件,则当检测到所有启用语言的 MPI 设置时,此变量设置为布尔 true。请注意,MPICXX 组件不会影响此变量。

MPI_VERSION

检测到的请求语言的最低 MPI 版本,或在未指定组件时检测到的所有启用语言的最低 MPI 版本。

此模块将在 CMake 项目中为每种语言设置以下变量,其中 <lang> 是 C、CXX 或 Fortran 之一。

MPI_<lang>_FOUND

布尔值,指示是否找到了 <lang> 的 MPI 设置,并且简单的 MPI 测试程序可以使用提供的设置进行编译。

MPI_<lang>_COMPILER

如果存在 MPI <lang> 编译器,则为该语言的 MPI 编译器。

MPI_<lang>_COMPILE_OPTIONS

MPI <lang> 程序的编译选项,以分号分隔的列表形式给出(参见 cmake-language-lists)。

MPI_<lang>_COMPILE_DEFINITIONS

MPI <lang> 程序的编译定义,以分号分隔的列表形式给出(参见 cmake-language-lists)。

MPI_<lang>_INCLUDE_DIRS

MPI 头文件的包含路径。

MPI_<lang>_LINK_FLAGS

MPI 程序的链接器标志。

MPI_<lang>_LIBRARIES

链接 MPI 程序所需的所有库。

将定义以下指示存在哪些绑定的变量:

MPI_MPICXX_FOUND

布尔值,指示 MPI-2 C++ 绑定是否存在(在 MPI-2 中引入,在 MPI-3 中移除)。

MPI_Fortran_HAVE_F77_HEADER

如果 Fortran 77 头文件 <mpif.h> 可用,则为 true。

MPI_Fortran_HAVE_F90_MODULE

如果 Fortran 90 模块 mpi 可用于访问 MPI(仅限 MPI-2 及更高版本),则为 true。

MPI_Fortran_HAVE_F08_MODULE

如果 Fortran 2008 模块 mpi_f08 可用于 MPI 程序(仅限 MPI-3 及更高版本),则为 true。

如果可能,MPI 版本将由此模块确定。检测 MPI 版本的功能是在 MPI-1.2 中引入的,因此无法为旧版 MPI 找到。

MPI_<lang>_VERSION

MPI 发行版为 <lang> 实现的 MPI 版本。

MPI_<lang>_VERSION_MAJOR

MPI 发行版为 <lang> 实现的 MPI 的主版本。

MPI_<lang>_VERSION_MINOR

MPI 发行版为 <lang> 实现的 MPI 的次版本。

请注意,没有关于 C 绑定可通过 <mpi.h> 访问的变量,因为 MPI 标准始终要求此绑定在 C 和 C++ 代码中都能正常工作。

为了运行 MPI 程序,模块设置了以下变量:

MPIEXEC_EXECUTABLE

用于运行 MPI 程序的执行文件,如果存在的话。

MPIEXEC_NUMPROC_FLAG

在将处理器数量传递给 mpiexec 之前,要传递给它的标志。

MPIEXEC_MAX_NUMPROCS

要使用的 MPI 处理器数量。默认为主机系统检测到的处理器数量。

MPIEXEC_PREFLAGS

在要运行的可执行文件之前直接传递给 mpiexec 的标志。

MPIEXEC_POSTFLAGS

在其他标志之后传递给 mpiexec 的标志。

用于定位 MPI 的变量

此模块执行四步搜索 MPI 实现:

  1. 搜索 MPIEXEC_EXECUTABLE,如果找到,则使用其基目录。

  2. 检查编译器是否内置了 MPI 支持。当用户将编译器包装器作为 CMAKE_<LANG>_COMPILER 传递,或者使用 Cray 系统编译器包装器时,就是这种情况。

  3. 尝试查找 MPI 编译器包装器并从中确定编译器信息。

  4. 尝试查找不附带此类包装器的 MPI 实现,并猜测其设置。目前仅支持 Windows 上的 Microsoft MPI 和 MPICH2。

为了控制 MPIEXEC_EXECUTABLE 步骤,可以设置以下变量:

MPIEXEC_EXECUTABLE

手动指定 mpiexec 的位置。

MPI_HOME

指定 MPI 安装的基目录。

ENV{MPI_HOME}

环境变量,用于指定 MPI 安装的基目录。

ENV{I_MPI_ROOT}

环境变量,用于指定 MPI 安装的基目录。

为了控制编译器包装器步骤,可以设置以下变量:

MPI_<lang>_COMPILER

搜索指定的编译器包装器并使用它。

MPI_<lang>_COMPILER_FLAGS

在探测期间传递给 MPI 编译器包装器的标志。某些编译器包装器支持链接调试或跟踪库,如果传递了特定标志,则可以使用此变量获取它们。

MPI_COMPILER_FLAGS

如果未提供特定于语言的标志,则用于初始化 MPI_<lang>_COMPILER_FLAGS。默认为空。

MPI_EXECUTABLE_SUFFIX

将添加到所有正在查找的名称的后缀。例如,它可以设置为 .mpich.openmpi,以便在 Debian 及其衍生版本上优先选择其中一个。

为了控制猜测步骤,可以设置以下变量:

MPI_GUESS_LIBRARY_NAME

有效值为 MSMPIMPICH2。如果设置,则只会搜索指定的库。默认情况下,如果 MSMPIMPICH2 都可用,则 MSMPI 将优先于 MPICH2。这也会将 MPI_SKIP_COMPILER_WRAPPER 变量设置为 true,但这可以被覆盖。

可以通过以下控制变量跳过每个搜索步骤:

MPI_ASSUME_NO_BUILTIN_MPI

如果为 true,则模块假定编译器本身不提供 MPI 实现,并跳到第 2 步。

MPI_SKIP_COMPILER_WRAPPER

如果为 true,则不会搜索编译器包装器。

MPI_SKIP_GUESSING

如果为 true,则跳过猜测步骤。

此外,还有以下控制变量可用于更改搜索行为:

MPI_CXX_SKIP_MPICXX

添加一些定义,将禁用 MPI-2 C++ 绑定。目前支持 MPICH、Open MPI、Platform MPI 及其衍生版本,例如 MVAPICH 或 Intel MPI。

如果模块的内部变量 MPI_<lang>_WORKS 的查找过程失败,则表示检测到或传递给模块的设置无效,甚至一个简单的 MPI 测试程序也无法编译。

如果以上所有参数都不足以找到正确的 MPI 实现,用户可以通过在 MPI_<lang>_LIBRARIES 中指定库列表和在 MPI_<lang>_ADDITIONAL_INCLUDE_DIRS 中指定包含目录来禁用整个自动检测过程。任何其他变量都可以与这两个变量一起设置。然后模块将验证 MPI 设置并将其存储在缓存中。

缓存变量

变量 MPI_<lang>_INCLUDE_DIRS 将由以下变量组合而成:

对于 C 和 CXX

MPI_<lang>_HEADER_DIR

磁盘上 <mpi.h> 头文件的位置。

对于 Fortran

MPI_Fortran_F77_HEADER_DIR

Fortran 77 头文件 <mpif.h> 的位置(如果存在)。

MPI_Fortran_MODULE_DIR

模块 mpimpi_f08 的位置(如果可用)。

对于所有语言,还将考虑以下变量:

MPI_<lang>_ADDITIONAL_INCLUDE_DIRS

一个分号分隔的列表,包含正常包含目录之外所需的其他路径(参见 cmake-language-lists)。

MPI_<include-name>_INCLUDE_DIR

用于由 <include-name> 引用的包含文件夹的路径变量。

MPI_<lang>_ADDITIONAL_INCLUDE_VARS

一个分号分隔的列表,包含将添加到 <lang> 的包含位置的 <include-name>(参见 cmake-language-lists)。

变量 MPI_<lang>_LIBRARIES 将由以下变量组合而成:

MPI_<lib-name>_LIBRARY

用于 MPI 的名为 <lib-name> 的库的位置。

MPI_<lang>_LIB_NAMES

一个分号分隔的列表,包含将添加到 <lang> 的包含位置的 <lib-name>(参见 cmake-language-lists)。

用于使用 MPI 的高级变量

该模块可以根据显式请求执行一些高级功能检测。

注意

以下检查无法在*不执行* MPI 测试程序的情况下进行。请考虑 try_run() 在交叉编译期间的行为的特殊注意事项。此外,运行 MPI 程序可能会引起额外问题,例如某些系统上的防火墙通知。这些检测应仅在绝对需要信息时启用。

如果以下变量设置为 true,则将执行相应的搜索:

MPI_DETERMINE_Fortran_CAPABILITIES

确定所有可用 Fortran 绑定的 MPI_SUBARRAYS_SUPPORTEDMPI_ASYNC_PROTECTS_NONBLOCKING 的值,并将它们的值作为 MPI_Fortran_<binding>_SUBARRAYSMPI_Fortran_<binding>_ASYNCPROT 提供,其中 <binding> 是 F77_HEADERF90_MODULEF08_MODULE 之一。

MPI_DETERMINE_LIBRARY_VERSION

对于每种语言,查找 MPI_Get_library_version 的输出,并将其作为 MPI_<lang>_LIBRARY_VERSION_STRING 提供。此信息通常与 MPI 实现的运行时组件相关,并且可能因 <lang> 而异。请注意,返回值完全由实现定义。此信息可能用于识别 MPI 供应商,例如,选择多个第三方二进制文件中与 MPI 供应商匹配的正确二进制文件。

已弃用变量

以下变量提供用于向后兼容性

MPI_COMPILER

版本 2.8.5 中已弃用: 请改用 MPI_<lang>_COMPILER

MPI_LIBRARY

版本 2.8.5 中已弃用: 请改用 MPI_<lang>_LIBRARIES

MPI_EXTRA_LIBRARY

版本 2.8.5 中已弃用: 请改用 MPI_<lang>_LIBRARIES

MPI_COMPILE_FLAGS

版本 2.8.5 中已弃用: 请改用 MPI_<lang>_COMPILE_OPTIONSMPI_<lang>_COMPILE_DEFINITIONS

MPI_INCLUDE_PATH

版本 2.8.5 中已弃用: 请改用 MPI_<lang>_INCLUDE_DIRS

MPI_LINK_FLAGS

版本 2.8.5 中已弃用: 请改用 MPI_<lang>_LINK_FLAGS

MPI_LIBRARIES

版本 2.8.5 中已弃用: 请改用 MPI_<lang>_LIBRARIES

MPI_<lang>_COMPILE_FLAGS

版本 3.10 中已弃用: 请改用 MPI_<lang>_COMPILE_OPTIONSMPI_<lang>_COMPILE_DEFINITIONS

MPI_<lang>_INCLUDE_PATH

版本 3.10 中已弃用: 用于消费时,请使用 MPI_<lang>_INCLUDE_DIRS;用于指定文件夹时,请使用 MPI_<lang>_ADDITIONAL_INCLUDE_DIRS

MPIEXEC

版本 3.10 中已弃用: 请改用 MPIEXEC_EXECUTABLE

示例

示例:基本用法

查找 MPI 并将导入的目标链接到项目目标

find_package(MPI)
target_link_libraries(example PRIVATE MPI::MPI_C)

示例:mpiexec 的用法

使用 MPIEXEC_EXECUTABLE 执行 MPI 应用程序时,通常应如下使用所有 MPIEXEC_EXECUTABLE 标志。

在以下示例中,命令在一个进程中执行。<executable> 应替换为 MPI 程序,<args> 应替换为传递给 MPI 程序的参数。

find_package(MPI)

if(MPI_FOUND)
  execute_process(
    COMMAND
      ${MPIEXEC_EXECUTABLE}
      ${MPIEXEC_NUMPROC_FLAG}
      ${MPIEXEC_MAX_NUMPROCS}
      ${MPIEXEC_PREFLAGS}
      <executable>
      ${MPIEXEC_POSTFLAGS}
      <args>
  )
endif()