Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28386 Discussions

Fortran Library Link Error in Visual Studio 2015

Martin__Jonathan
Beginner
331 Views

I'm having a linker issue when building a Fortran DLL. I'm using the following:

  • Visual Studio 2015 with Update 3
  • Parallel Studio 2016 with Update 3

Here's a description of the projects involved:

  • CommonSource project:
    • Output: C++ static library
    • Contains a .cpp/.h source that specifies the following method:
      • Log.h
        void CLOSE_LOG();
      • log.cpp
        void CLOSE_LOG()
        {
            g_OutStream.close();
        }
  • Subroutine project:

    • Output: Fortran static library

    • 'Additional Include Directories' points to Debug directory of the CommonSource project

    • Contains a .for source that calls on the CLOSE_LOG method:

      • exit_model.for
        SUBROUTINE EXIT_MODEL(A_MESSAGE)
            ...
            CALL CLOSE_LOG
            ...
        END SUBROUTINE EXIT_MODEL
  • DLL project:

    • Output: Fortran DLL

    • 'Additional Dependencies' includes the CommonSource and Subroutine static libraries

    • Contains a .for source that calls on the CLOSE_LOG method:

      • name.for
        FUNCTION NAME()
            ...
            CALL CLOSE_LOG
            ...
        END FUNCTION NAME
        

Individually, both 'CommonSource' and 'Subroutine' projects build successfully. However, when building the DLL project I get a link error on the 'CLOSE_LOG' call in exit_model.for of the Subroutine project. However, an error is not shown for the same call in name.for.

Why would the link error occur in an accompanying dependency (Subroutine) and not the DLL project itself? How can this issue be resolved?

0 Kudos
3 Replies
IanH
Honored Contributor II
331 Views

The linker reports missing definitions for the symbols encountered in code that it is trying to link together into its output.  The linker has decided that it needs to put the code for the exit_model subroutine into the output, therefore it needs to resolve the symbol CLOSE_LOG that the Fortran compiler has indicated is required.  None of the other libraries or object files that you supply define that exact symbol, hence you get an error.  In different circumstances, perhaps the linker would be considering just the name function, and give you a similar error.

Note you are compiling C++ code.  The C++ compiler will generate a "mangled" linker symbol for your C++ procedure that incorporates information such as the types of the arguments to the procedure.  This will bear no resemblance to the linker symbol generated by the Fortran compiler.  Perhaps you forgot to declare and define the C++ function with extern "C".

In general, Fortran compilers and C compilers have differing conventions for how they convert names in your source code across to the symbolic names that the linker deals with (along with other differences in how procedures are called between the two languages) - they will differ between languages, they may differ from compiler to compiler within a language, and they may differ for a particular compiler depending on command line options.

Modern Fortran includes language features that effectively specify that the linker symbol for a Fortran procedure be the same as the symbol that would be generated for an appropriately named C function when compiled by a companion C (or C++, with extern "C") compiler to the Fortran compiler.  This ability also helps resolve other differences that may arise in calling convention between the two languages.  You really should use these language features.  Look up the BIND suffix for procedure declarations in your Fortran manual.

SUBROUTINE EXIT_MODEL !(A_MESSAGE)
    INTERFACE
      SUBROUTINE CLOSE_LOG() BIND(C, NAME='CLOSE_LOG')
        IMPLICIT NONE
      END SUBROUTINE CLOSE_LOG
    END INTERFACE
    !...
    CALL CLOSE_LOG
    !...
END SUBROUTINE EXIT_MODEL

 

0 Kudos
Martin__Jonathan
Beginner
331 Views

Thank you for the response. To follow up:

  • The method is declared using 'extern "C"' in the log.h header file:
    • extern "C"
      {
          void CLOSE_LOG();
      }
  • When compiling the DLL project the link error specifically states 'error LNK2019: unresolved external symbol _CLOSE_LOG@0 referenced in function _EXIT_MODEL'.
    • What's the significance of the '@0' suffix?
  • I implemented the BIND declaration in the Fortran file with the 'EXIT_MODEL' subroutine and successfully compiled the Subroutine project. Then, when I compiled the DLL project I got the error 'error LNK2005: _CLOSE_LOG already defined in CommonSource.lib (log.obj)'.
  • Based on the two previous points, my guess is that the C++ lib has defined the method as _CLOSE_LOG but the Fortran project is looking for _CLOSE_LOG@0.
0 Kudos
Steve_Lionel
Honored Contributor III
331 Views

The @0 indicates that you have compiled the Fortran source with an option that changes the calling convention to STDCALL. For example, /iface:CVF will do this. In your Fortran projects properties, make sure that in the External Procedures page that Calling Convention is set to Default and that string-length-argument-passing is "After all arguments.

0 Kudos
Reply