CMake Fortran 未正确排序源代码

CMake Fortran does not order source correctly

我正在将 Visual Studio 2019 with Intel Fortran 2020 项目迁移到 CMake

我正在使用 CMake 3.21 和 CMakePresets 将生成器设置为 Visual Studio 2019 和 x64 位架构。

我的最终产品是一个基于多个源文件构建的 DLL。这些文件也组织在文件夹中。

编译器被正确找到并且一切运行正常,直到我到达 link 步骤,在那里我得到未解析的符号错误。现在 Visual Studio 生成一个名为 BuildLog.htm 的文件,其中包含编译器运行的所有命令的列表。我已经恢复了 CMake 生成的一个,并与 Visual Studio 项目生成的一个进行了比较。

事情是这样的

ifort <some-flags> file1.f90
ifort <some-flags> file2.f90
ifort <some-flags> file3.f90
ifort <some-flags> file4.f90

我注意到的区别是 CMake 日志是这样的

ifort <some-flags> file3.f90
ifort <some-flags> file1.f90
ifort <some-flags> file4.f90
ifort <some-flags> file2.f90

我不确定这里发生了什么,因为我在 CMake 中以正确的顺序生成了文件列表。为什么会乱码?

我读到 link 命令中列出的文件的顺序可能有问题,但我使用 CMake 生成的对象手动启动命令 link 对象和我得到了同样未解决的 linker 错误。但是,如果我以正确的顺序手动编译对象,linker 不会失败。

有人可以阐明为什么 CMake 对文件顺序这样做吗? 为什么 Visual Studio 没有我的任何输入就得到正确的订单?我是否缺少 CMake 中的某些配置选项?

这就是我创建目标的方式

set(APPEND MY_FILE_LIST
   file1.f90
   file2.f90
   file3.f90
   file4.f90
)
add_library(MY_LIB SHARED ${MY_FILE_LIST})

link命令是这样的

link /nologo /subsystem:WINDOWS /DLL /OUT:mylib.dll /IMPLIB:mylib.lib file1.obj file2.obj file3.obj file4.obj

更新:

所以我尝试手动将 CMake 创建的编译命令排序为 Visual Studio 输出的相同顺序,但 linker 失败了。所以我猜错误在那里让我失败了。我发布了编译器命令,它们不太一样,但我没有看到问题

Visual Studio 编译命令

ifort /nologo /O3 /extend_source:132 /warn:none /names:uppercase /iface:stdref /iface:mixed_str_len_arg /libs:dll /threads /c /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file1.f90"

ifort /nologo /O3 /heap-arrays0 /extend_source:132 /warn:none /names:uppercase /iface:stdref /iface:mixed_str_len_arg /libs:dll /threads /c /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file2.f90"

ifort /nologo /O3 /extend_source:132 /warn:none /names:uppercase /iface:stdref /iface:mixed_str_len_arg /libs:dll /threads /c /extfor:f /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file3.f"

ifort /nologo /O3 /heap-arrays0 /extend_source:132 /Qopenmp /warn:none /names:uppercase /iface:stdref /iface:mixed_str_len_arg /libs:dll /threads /c /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file4.f90"

CMake 编译器命令

ifort /nologo /O3 /DCMAKE_INTDIR=\"Release\" /Dmylib_EXPORTS /iface:stdref /libs:dll /threads /c /names:uppercase /iface:mixed_str_len_arg /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file1.f90"

ifort /nologo /O3 /DCMAKE_INTDIR=\"Release\" /Dmylib_EXPORTS /iface:stdref /libs:dll /threads /c /heap-arrays /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file2.f90"

ifort /nologo /O3 /DCMAKE_INTDIR=\"Release\" /Dmylib_EXPORTS /iface:stdref /libs:dll /threads /c /extend-source /f77 /extfor:f /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file3.f"


ifort /nologo /O3 /DCMAKE_INTDIR=\"Release\" /Dmylib_EXPORTS /Qopenmp /iface:stdref /libs:dll /threads /c /heap-arrays /Qlocation,link,"...\Tools\MSVC.22.27905\bin\HostX64\x64" /Qm64 "file4.f90"

到目前为止我尝试过的是:

更新 2:

仔细检查标志后,我发现我的一些编译标志丢失了。

配置 CMake 时,我设置了编译的全局标志,但随后某些文件具有特定的编译器标志。

这就是我在 CMake 中设置标志的方式

set (common_flags "/nologo")
set (release_flags "/O3")
set (debug_flags "/debug:full /Od")
set (external_proc_flags "/names:uppercase /iface:stdref /iface:mixed_str_len_arg")
set (runtime_flags "/traceback /check:bounds /check:stack")
set (warning_flags "")
if(SHOW_WARNINGS)
  # YOU want all the compiler warnings
  set (warning_flags "/stand:f08 /warn:all ${runtime_flags}")
endif()

set (my_Fortran_FLAGS_RELEASE "${release_flags} ${external_proc_flags} ${warning_flags}")
set (my_Fortran_FLAGS_DEBUG "${debug_flags} ${external_proc_flags} ${warning_flags}")
set(CMAKE_Fortran_FLAGS "${common_flags}")
set(CMAKE_Fortran_FLAGS_DEBUG ${my_Fortran_FLAGS_DEBUG})
set(CMAKE_Fortran_FLAGS_RELEASE ${my_Fortran_FLAGS_RELEASE})
set(CMAKE_Fortran_FLAGS_RELEASE ${my_Fortran_FLAGS_RELEASE})

然后在 CMake 中的 add_library() 命令之后,我像这样为特定文件设置标志

set_property(SOURCE ${EXTEND_SOURCE_FILES} PROPERTY COMPILE_OPTIONS "/extend-source;/f77")
set_property(SOURCE ${OPENMP_FILES} PROPERTY COMPILE_OPTIONS "/Qopenmp")
set_property(SOURCE ${HEAP_ARRAYS_FILES} PROPERTY COMPILE_OPTIONS "/heap-arrays")
set_property(SOURCE ${OPENMP_PLUS_HEAP_ARRAYS_FILES} PROPERTY COMPILE_OPTIONS "/Qopenmp;/heap-arrays")

但看起来这个最终编译选项 属性 与原始标志混淆了,我发现 EXTEND_SOURCE_FILES、HEAP_ARRAYS_FILES 和 OPENMP_PLUS_HEAP_ARRAYS_FILES 中的所有文件都没有没有使 link 步骤失败的 /names:uppercase

我找到了解决问题的办法。 @Tsyvarev 指出了关于标志的正确方向,结果 cmake 没有像我预期的那样添加标志。

我需要为目标中的所有文件设置一些标志,然后为一些特定文件设置一些标志。

问题是在为源文件设置 COMPILE_OPTIONS 属性 时,一些全局标志没有进入编译命令,特别是缺少的 \names:uppercase标志是导致问题的标志,但其他一些标志也丢失了。

这是最终在 CMake 中运行的配置。

set (common_flags "/nologo")
set (release_flags "/O3")
set (debug_flags "/debug:full /Od")
set (external_proc_flags "/names:uppercase;/iface:stdref;/iface:mixed_str_len_arg")
set (runtime_flags "/traceback;/check:bounds;/check:stack")
set (warning_flags "")
if(SHOW_WARNINGS)
  set (warning_flags "/stand:f08;/warn:all;${runtime_flags}")
endif()

set(CMAKE_Fortran_FLAGS_RELEASE ${release_flags})
set(CMAKE_Fortran_FLAGS_DEBUG ${debug_flags})
set(CMAKE_Fortran_FLAGS ${common_flags})

set(my_Fortran_flags "${external_proc_flags};${warning_flags}")

# mylib_sources - list of all source files
add_library(mylib SHARED ${mylib_sources})
target_compile_options(mylib PRIVATE ${my_Fortran_flags})

set_property(SOURCE ${EXTEND_SOURCE_FILES} PROPERTY COMPILE_OPTIONS "/extend-source;/f77;${my_Fortran_flags}")

set_property(SOURCE ${OPENMP_FILES} PROPERTY COMPILE_OPTIONS "/Qopenmp;${my_Fortran_flags}")

set_property(SOURCE ${HEAP_ARRAYS_FILES} PROPERTY COMPILE_OPTIONS "/heap-arrays;${my_Fortran_flags}")

set_property(SOURCE ${OPENMP_PLUS_HEAP_ARRAYS_FILES} PROPERTY COMPILE_OPTIONS "/Qopenmp;/heap-arrays;${my_Fortran_flags}")