Linker error when C++ executable links in Fortran library and main in C++ library

Viewed 295

I have a CMake-based project consisting of three targets:

  • A static library FortLib written in Fortran.
  • A static library LibWithMain which is written in C++ and contains the definition of int main().
  • An executable App which links in both of the above libraries.

This is the contents of the CMakeList:

cmake_minimum_required(VERSION 3.7.2)
project(Mcve LANGUAGES C CXX Fortran)

add_library(FortLib STATIC fort.f90)
target_compile_options(FortLib PRIVATE /names:lowercase /assume:underscore /iface:cref)

add_library(LibWithMain STATIC main.cpp)

add_executable(App app.cpp)
target_link_libraries(App PRIVATE FortLib LibWithMain)

(For contents of the source files which can be used to reproduce the issue, see bottom)

My problem is that linking App results in the following linker error:

libifcoremdd.lib(for_main.obj) : error LNK2019: unresolved external symbol MAIN__ referenced in function main

Note that this reference comes from libifcoremdd.lib, an Intel Fortran library which apparently gets implicitly linked in.

This does not happen if the function main is defined directly in App. This can be shown by exchanging the files main.cpp and app.cpp in the CMakeList above (so that main is defined inside the app). Then everything builds and links successfully. It's the fact that the definition of main comes from LibWithMain that somehow gets the linker confused.

In my real code, LibWithMain is Boost.Test, so moving main out from it is not really an option for me.

The order of the static libraries does not matter: the error is present regardless of which lib follows which on the link line.

My toolchain is Visual Studio 2017 and Intel Fortran 18, my platform is Win64 ("x64" in Visual Studio terminology). No other compilers/platforms need to be supported at this point.

I am a C++ developer and know next to nothing about Fotran or the Intel Fortran ecosystem, so I have no idea what could be causing this or how to solve it. That is therefore my question:

What is causing the linker error, and how can I fix it?


These simple files, used in the CMakeList above, are enough to reproduce the issue:

fort.f90

integer function fortfunc
  implicit none
  fortfunc = 42
end function

main.cpp

#include <iostream>

int work();

int main()
{
  std::cout << work() << std::endl;
  return 0;
}

app.cpp

extern "C" int fortfunc_();

int work()
{
  return fortfunc_();
}
1 Answers

I don't know how cmake works but I'm guessing that you need to do it the other way round. It is possible that main is special function in your toolchain and should not exist in a library.

  1. build the fortran lib
  2. build the c lib without main (app.cpp)
  3. build the main using both c lib and fortran lib.

It probably won't moan about missing externals when building the c lib because it is a library and not everything needs to be resolved.

Also, in app.cpp, what you need to remember is that in Fortran, the callee unstacks the arguments but in C, the caller unstacks.

When the callee unstacks, you need __stdcall as part of the declaration. This used to be extern PASCAL on the older MS compilers. When a caller unstacks, you can optionally add __cdecl.

Related