Search code examples
linkerfortranintel-fortran

Function not found when compiling a Fortran program against a static library (in Windows using IFORT)


Given the following Fortran module:

MODULE Test

    IMPLICIT NONE

    INTERFACE

        INTEGER(c_int) FUNCTION process_(script, script_size) BIND(C, name = "process")
            USE, INTRINSIC :: iso_c_binding, ONLY: c_int, c_char
            CHARACTER(c_char), INTENT(IN) :: script(*)
            INTEGER(c_int), INTENT(IN), VALUE :: script_size
        END FUNCTION

    END INTERFACE

    CONTAINS

        FUNCTION process(script)
            #ifdef SHARED_LIB
                !DEC$ ATTRIBUTES DLLEXPORT :: process
            #endif
            INTEGER :: process
            CHARACTER(LEN = *), INTENT(IN) :: script

            process = process_(script, LEN(script))
        END FUNCTION

END MODULE

I am able to successfully compile this module using IFORT (in Windows), both as a shared library and a static library.

Additionally, I am able to successfully compile a small Fortran program (named example.f90) that uses the shared library. The small program is the following:

PROGRAM Example

    USE Test

    INTEGER :: state

    state = process("Hello world!")

END PROGRAM

Now, when I try to compile the same small Fortran program this time using the static library it gives the following error:

C:\workspace\>ifort.exe /Qopenmp /module:library library\Test.lib example.f90

Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 16.0 Build 20160811
Copyright (C) 1985-2016 Intel Corporation.  All rights reserved.

Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

-out:example.exe
-subsystem:console
-defaultlib:libiomp5md.lib
-nodefaultlib:vcomp.lib
-nodefaultlib:vcompd.lib
library\Test.lib
example.obj
example.obj : error LNK2019: unresolved external symbol __imp_TEST_mp_process referenced in function MAIN__
example.exe : fatal error LNK1120: 1 unresolved externals

Any idea how to solve this?


Solution

  • The DLLEXPORT in routine process is turned into a DLLIMPORT when you USE the module (this is a feature added some versions back, but I don't remember exactly when.) The compiler is therefore assuming that process comes from a DLL and adds the __imp_ prefix, but since you built the library as a static library it is not found. You can 1) Remove the DLLEXPORT, 2) use conditional compilation based on the _DLL symbol (predefined for DLL builds) to enable DLLEXPORT only then, 3) build the library as a DLL.

    I will also caution you that order of libraries and objects in the link step can matter, though I don't think it does here. I would recommend putting libraries after sources when building the executable.