使用 gfortran 和 mpifort 为 Fortran 项目编写 CMake 文件

Writing CMake file for Fortran project with both gfortran and mpifort

我有一个项目,其中一些 f90 文件需要使用常规 gfortran 编译器进行编译,一些需要使用 mpifort 包装器进行编译。我不知道如何正确编写 CMake 文件来适应这个问题。另外,我以前从未使用过 CMake,也不熟悉它,但我试图从文档和(基本上过时的)教程中理解。

我的项目目录如下所示:

├── CMakeLists.txt
├── README.md
├── bin
├── build
├── compile
├── src
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   │   ├── 3.8.1
│   │   │   ├── CMakeCCompiler.cmake
│   │   │   ├── CMakeCXXCompiler.cmake
│   │   │   ├── CMakeDetermineCompilerABI_C.bin
│   │   │   ├── CMakeDetermineCompilerABI_CXX.bin
│   │   │   ├── CMakeDetermineCompilerABI_Fortran.bin
│   │   │   ├── CMakeFortranCompiler.cmake
│   │   │   ├── CMakeSystem.cmake
│   │   │   ├── CompilerIdC
│   │   │   │   ├── CMakeCCompilerId.c
│   │   │   │   ├── a.out
│   │   │   │   └── tmp
│   │   │   ├── CompilerIdCXX
│   │   │   │   ├── CMakeCXXCompilerId.cpp
│   │   │   │   ├── a.out
│   │   │   │   └── tmp
│   │   │   └── CompilerIdFortran
│   │   │       ├── CMakeFortranCompilerId.F
│   │   │       ├── a.out
│   │   │       └── tmp
│   │   ├── CMakeDirectoryInformation.cmake
│   │   ├── CMakeOutput.log
│   │   ├── CMakeTmp
│   │   ├── Makefile.cmake
│   │   ├── Makefile2
│   │   ├── TargetDirectories.txt
│   │   ├── cmake.check_cache
│   │   ├── feature_tests.bin
│   │   ├── feature_tests.c
│   │   ├── feature_tests.cxx
│   │   ├── progress.marks
│   │   └── streetcanyon.dir
│   │       ├── DependInfo.cmake
│   │       ├── INC_BBB.f90.o
│   │       ├── INC_BBB.f90.o.provides.build
│   │       ├── INC_BC.f90.o
│   │       ├── INC_BC.f90.o.provides.build
│   │       ├── INC_BOUNDC.f90.o
│   │       ├── INC_BOUNDC.f90.o.provides.build
│   │       ├── INC_BUOY.f90.o
│   │       ├── INC_BUOY.f90.o.provides.build
│   │       ├── INC_COEF.f90.o
│   │       ├── INC_COEF.f90.o.provides.build
│   │       ├── INC_COEFB.f90.o
│   │       ├── INC_COEFB.f90.o.provides.build
│   │       ├── INC_GEO.f90.o
│   │       ├── INC_GEO.f90.o.provides.build
│   │       ├── INC_INDEX.f90.o
│   │       ├── INC_INDEX.f90.o.provides.build
│   │       ├── INC_OBSTACLE.f90.o
│   │       ├── INC_OBSTACLE.f90.o.provides.build
│   │       ├── INC_PAR.f90.o
│   │       ├── INC_PAR.f90.o.provides.build
│   │       ├── INC_PRINT.f90.o
│   │       ├── INC_PRINT.f90.o.provides.build
│   │       ├── INC_SOURCE.f90.o
│   │       ├── INC_SOURCE.f90.o.provides.build
│   │       ├── INC_STAT.f90.o
│   │       ├── INC_STAT.f90.o.provides.build
│   │       ├── INC_TIME.f90.o
│   │       ├── INC_TIME.f90.o.provides.build
│   │       ├── INC_TITLE.f90.o
│   │       ├── INC_TITLE.f90.o.provides.build
│   │       ├── INC_TREES.f90.o
│   │       ├── INC_TREES.f90.o.provides.build
│   │       ├── INC_UVW.f90.o
│   │       ├── INC_UVW.f90.o.provides.build
│   │       ├── INC_VEC.f90.o
│   │       ├── INC_VEC.f90.o.provides.build
│   │       ├── INC_WALL.f90.o
│   │       ├── INC_WALL.f90.o.provides.build
│   │       ├── build.make
│   │       ├── cmake_clean.cmake
│   │       ├── cmake_clean_Fortran.cmake
│   │       ├── depend.internal
│   │       ├── depend.make
│   │       ├── flags.make
│   │       ├── fortran.internal
│   │       ├── inc_bbb.mod.stamp
│   │       ├── inc_bc.mod.stamp
│   │       ├── inc_boundc.mod.stamp
│   │       ├── inc_buoy.mod.stamp
│   │       ├── inc_coef.mod.stamp
│   │       ├── inc_coefb.mod.stamp
│   │       ├── inc_geo.mod.stamp
│   │       ├── inc_index.mod.stamp
│   │       ├── inc_obstacle.mod.stamp
│   │       ├── inc_par.mod.stamp
│   │       ├── inc_print.mod.stamp
│   │       ├── inc_source.mod.stamp
│   │       ├── inc_stat.mod.stamp
│   │       ├── inc_time.mod.stamp
│   │       ├── inc_title.mod.stamp
│   │       ├── inc_trees.mod.stamp
│   │       ├── inc_uvw.mod.stamp
│   │       ├── inc_vec.mod.stamp
│   │       ├── inc_wall.mod.stamp
│   │       ├── link.txt
│   │       └── progress.make
│   ├── INC_BBB.f90
│   ├── INC_BC.f90
│   ├── INC_BOUNDC.f90
│   ├── INC_BUOY.f90
│   ├── INC_COEF.f90
│   ├── INC_COEFB.f90
│   ├── INC_GEO.f90
│   ├── INC_INDEX.f90
│   ├── INC_OBSTACLE.f90
│   ├── INC_PAR.f90
│   ├── INC_PAR.f90_8ob
│   ├── INC_PRINT.f90
│   ├── INC_SOURCE.f90
│   ├── INC_STAT.f90
│   ├── INC_TIME.f90
│   ├── INC_TITLE.f90
│   ├── INC_TREES.f90
│   ├── INC_UVW.f90
│   ├── INC_VEC.f90
│   ├── INC_WALL.f90
│   ├── Makefile
│   ├── cmake_install.cmake
│   ├── grid_binary
│   ├── grid_binary(8\ obsttacles)
│   ├── inc_bbb.mod
│   ├── inc_bc.mod
│   ├── inc_boundc.mod
│   ├── inc_buoy.mod
│   ├── inc_coef.mod
│   ├── inc_coefb.mod
│   ├── inc_geo.mod
│   ├── inc_index.mod
│   ├── inc_obstacle.mod
│   ├── inc_par.mod
│   ├── inc_print.mod
│   ├── inc_source.mod
│   ├── inc_stat.mod
│   ├── inc_time.mod
│   ├── inc_title.mod
│   ├── inc_trees.mod
│   ├── inc_uvw.mod
│   ├── inc_vec.mod
│   ├── inc_wall.mod
│   ├── mpi_par.f90
│   ├── source
│   ├── streetcanyon.f90
│   └── streetcanyon.f90~

./src/目录中streetcanyon.f90mpi_par.f90需要使用mpifort编译,其余的可以通过gfortran完成。 streetcanyon.f90 需要编译成最终的可执行文件。我尝试使用项目根目录中包含的以下 CMakeList.txt

#./CMakeList.txt
cmake_minimum_required (VERSION 3.8.0)
project(mpi)
enable_language (Fortran)

file(GLOB SOURCES src/*.f90)

add_executable(streetcanyon ${SOURCES})

我也不知道我是否遵循了适合 Fortran 的项目结构。

只需使用 CMake 的 FindMPI 模块。它将从 mpifort 中提取编译标志和库,并将它们作为常规 CMake 变量提供。您所要做的就是将这些标志应用到您的库中。唯一困难的部分是必须应用几个不同的东西。这是您如何使用它的示例:

cmake_minimum_required (VERSION 3.8.0)
project(mpi)
enable_language (Fortran)

find_package(MPI)
if(NOT MPI_Fortran_FOUND)
    message(FATAL_ERROR "Could not find Fortran MPI.  Please set MPI_Fortran_COMPILER to point to the mpifort wrapper.")
endif()

include_directories(${MPI_Fortran_INCLUDE_PATH})
add_compile_options(${MPI_Fortran_COMPILE_FLAGS})

file(GLOB SOURCES src/*.f90)

add_executable(streetcanyon ${SOURCES})
target_link_libraries(streetcanyon ${MPI_Fortran_LIBRARIES})
set_property(TARGET streetcanyon APPEND_STRING PROPERTY LINK_FLAGS "${MPI_Fortran_LINK_FLAGS}")

这将按照 mpifort 编译它们的方式编译所有 streetcanyon 源代码,这在 99% 的用例中应该没问题。如果你真的只想编译一些像 mpifort 那样的文件,就像你说的那样,那么而不是

add_compile_options(${MPI_Fortran_COMPILE_FLAGS})

您可以将 MPI 编译选项仅传递给特定的源文件,需要一些小改动:

set(MPI_SOURCES foo.f90 bar.f90...)
set(NO_MPI_SOURCES baz.f90...)

# convert CMake list to string for PROPERTY COMPILE_FLAGS
set(MPI_Fortran_COMPILE_FLAGS_STR "")
foreach(ELEMENT ${MPI_Fortran_COMPILE_FLAGS})
    set(MPI_Fortran_COMPILE_FLAGS_STR  "${MPI_Fortran_COMPILE_FLAGS_STR } ${ELEMENT}")
endforeach()

set_property(SOURCE ${MPI_SOURCES} PROPERTY COMPILE_FLAGS ${MPI_Fortran_COMPILE_FLAGS_STR})

...later...
add_executable(streetcanyon ${MPI_SOURCES} ${NO_MPI_SOURCES})