【发布时间】:2023-03-08 10:23:02
【问题描述】:
我正在将带有 Intel Fortran 2020 的 Visual Studio 2019 项目迁移到 CMake
我正在使用 CMake 3.21 和 CMakePresets 将生成器设置为 Visual Studio 2019 和 x64 位架构。
我的最终产品是基于多个源文件构建的 DLL。这些文件也被组织在文件夹中。
编译器被正确找到并且一切运行正常,直到我到达链接步骤,在那里我得到了未解决的符号错误。现在 Visual Studio 生成一个名为 BuildLog.htm 的文件,其中列出了编译器运行的所有命令。我已经恢复了 CMake 生成的那个,并与 Visual Studio Project 生成的那个进行了比较。
事情是这样的
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 中以正确的顺序生成了文件列表。为什么会乱码?
我读到链接命令中列出的文件的顺序可能有问题,但是我启动了命令以手动将对象与 CMake 生成的对象链接起来,我得到了相同的未解决的链接器错误。但是如果我以正确的顺序手动编译对象,链接器就不会失败。
有人可以解释一下为什么 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 /nologo /subsystem:WINDOWS /DLL /OUT:mylib.dll /IMPLIB:mylib.lib file1.obj file2.obj file3.obj file4.obj
更新:
所以我尝试手动将 CMake 创建的编译命令与 Visual Studio 输出的顺序相同,并且链接器失败。所以我猜测那里的错误让我失望了。我正在发布编译器命令,它们并不完全相同,但我没有看到问题
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\14.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\14.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\14.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\14.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\14.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\14.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\14.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\14.22.27905\bin\HostX64\x64" /Qm64 "file4.f90"
到目前为止我尝试过的是:
- 删除 /D 定义标志
- 将
libs:dll /threads /c移动到/Qlocation,link之前 - 将 132 添加到
/extend-source - 删除 /f77
更新 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 中的所有文件都没有/names:uppercase,这导致链接步骤失败。
【问题讨论】:
-
什么是链接器错误?源文件之间的依赖关系是什么?
-
链接器错误是 LNK 2019 和 LNK2001。这不是我的代码,但从我所见,一些文件定义了其他文件中使用的子例程,而其他文件定义了其他文件中使用的模块,这似乎是问题所在,但是错误的数量从一个编译到另一个编译发生了变化。我看到一个有 42 错误,另一个有 47
-
在所有源文件编译完成后调用链接器。因此,
ifort调用 sources 的顺序无关紧要。对于调试链接器错误,您需要检查 linker 标志和参数。 -
你能给出链接器给出的确切错误信息吗? (请将它们复制并粘贴到您的问题中)。为了解决依赖关系,文件
a依赖于文件b,如果文件a包含行use foo,并且文件b包含module foo。 -
@veryreverie fileB.obj : 错误 LNK2019: 函数 funcB(fileB) fileC.obj 中引用的无法解析的外部符号 funcA(fileA) 错误 LNK2001: 无法解析的外部符号 funcD(fileD) 我要减少文件的数量,看看我是否可以编译一个 MWE
标签: visual-studio cmake fortran intel-fortran