Home > OS >  CMake Fortran does not order source correctly
CMake Fortran does not order source correctly

Time:09-21

I'm migrating a Visual Studio 2019 with Intel Fortran 2020 project to CMake

I'm using CMake 3.21 and CMakePresets to set the Generator to Visual Studio 2019 and x64bit architecture.

I final product is a DLL that's built on multiple source files. Those files are organized in folders as well.

The compiler is found correctly and everything runs fine until I get to the link step, where I get unresolved symbols errors. Now Visual Studio Generates a file called BuildLog.htm where there is a list of all the commands that the compiler runs. I have recovered the one CMake generates and compared to the one generated by the Visual Studio Project.

It goes something like this

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

The differences I noticed is that the CMake log goes something like this

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

I'm not sure what is happening here since I generate the file list in CMake in the correct order. Why is it getting scrambled?

I read that it could be a problem with the order of the files listed in the link command, but I launched the command to link the objects manually with the objects generated by CMake and I get the same unresolved linker error. But if I compile the objects manually in the correct order the linker does not fail.

Can somebody shed some light as to why is CMake doing this with the file order? Why does Visual Studio get the order right without any input from me? Am I missing some configuration option in CMake?

This would be how I create the target

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

The link command is this

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

UPDATE:

So I tried manually ordering the compile commands that CMake creates to the same order that Visual Studio outputs and the linker fails. So my guess that the error was there failed me. I'm posting the compiler commnads, they are not quite the same, but I don't see the problem

Visual Studio compiler commands

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 compiler commands

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"

What I've tried so far is:

  • removing the /D definition flags
  • moving libs:dll /threads /c to just before /Qlocation,link
  • adding 132 to /extend-source
  • removing /f77

UPDATE 2:

Upon closer inspection of the flags I noticed that some of my compile flags where missing.

When configuring CMake, I set my global flags for compilation, but then some of the files have specific compiler flags.

This is how I set my flags in 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})

Then after the add_library() command in CMake, I set the flags for the specific files like this

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")

But it looks like this final compile options propery messed with the original flags, I found that all the files in EXTEND_SOURCE_FILES, HEAP_ARRAYS_FILES and OPENMP_PLUS_HEAP_ARRAYS_FILES did not have the /names:uppercase which makes the link step fail.

CodePudding user response:

I found the solution to my problem. @Tsyvarev pointed me in the right direction about the flags, turns out cmake wasn't adding the flags like I expected.

I needed to set some flags to all the files in the target, and then some specific files a few files.

The problem was that when setting the COMPILE_OPTIONS property to the source files, some of the global flags didn't make it to the compile command, specifically the missing \names:uppercase flag was the one that caused the problem, but some others where missing too.

This is the configuration that finally got it working in 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}")
  • Related