当我使用由所有可执行文件共享的 Fortran 模块并使用 make -j
并行构建时,我在使用 CMake 构建多个 Fortran-90+ 可执行目标时遇到问题。问题似乎是编译后的目标文件放置在每个目标的不同子目录中,CMakeFiles/targetName.dir/src/file.f90.o
,而模块文件放置在同一目录中对于每个目标(我可以通过设置 Fortran_MODULE_DIRECTORY
来更改此目录,但它仍然是所有模块文件的相同目录)。问题是所有目标开始并行编写这些模块文件,我得到一个
fatal error :无法将模块文件“module.mod0”重命名为“module.mod”:没有这样的文件或目录
使用 gfortran 时(显然会创建一个 .mod0 文件,然后将其重命名为 .mod)。当我在没有 -j 选项(串行构建)的情况下发出 make 时,问题不会出现。
我可以看到两个解决方案,但我不知道如何实现它们。首先,将所有目标的目标文件放在同一目录中,而不是特定于目标的目录中。这可能是首选选项,因为我不必为 N 个目标编译 N 次共享源文件。然后 make 进程将识别目标文件存在,并且不会再次编译相应的源文件,因此不会再次触及 .mod(0) 文件(我可能需要使所有以下目标都依赖于第一个)。
第二种解决方案是将 .mod(0) 文件放在特定于目标的目录中,这样它们就不会被其他目标覆盖或删除。这将解决我的问题,即使它仍然涉及比必要更多的编译。我不知道如何完成任一选项,因此欢迎提供任何提示或替代解决方案。
最佳答案
@RaulLaasner 在对问题的评论中提供了我正在寻找的答案:
I would create an additional target in the form of a core library of the relevant source files, which can then be linked to all executables. This should work in parallel. The mod files can still be in put into a single directory.
我使用 add_library()
和 target_link_libraries()
来实现这一点。
请注意,例如Gentoo ebuild 脚本将 --as-needed
添加到链接器,这可能会导致 undefined references当您链接它和外部库以形成可执行文件时,在您的核心库中。为防止这种情况,请确保首先将外部库链接到核心库。为此,我的 CMakeListst.txt 包含:
add_library( "Core" STATIC src/functions.f90 src/routines.f90 ) # creates libCore.a
target_link_libraries( Core ${EXTERNAL_LIBRARIES} ) # link external libraries to libCore.a
...
add_executable( myProgram1 src/myProgram1.f90 ) # creates the first executable
target_link_libraries( myProgram1 Core ) # links libCore.a to myProgram1
可以重复最后两行来构建其他可执行文件(例如使用 foreach())。
关于使用模块为 Fortran-90+ 进行 CMake 并行构建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29728867/