Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Beginner
212 Views

Can LNK4006 warnings be safely ignored in mixed Fortran/C++ solutions?

Jump to solution

Our current solution is a mixed C++ Fortran application in Visual Studio 2013, with approximately 40 projects of each.

Although we can build the solution just fine, we are getting about 6000 warnings - a vast majority of which are LNK4006 warnings, where a function is being "duplicated":

    warning LNK4006: _XXXXXXXXXXX@8 already defined in project1.lib(module1.obj); second definition ignored    project2.lib(module1.obj)    

The common thread is that the functions that are being duplicated are defined in Fortran modules - of which many (but not all) are just interfaces to C++ functions:

    MODULE mINTERFACES
    
    USE ISO_C_BINDING
    
    INTERFACE
        INTEGER(4) FUNCTION GetLastErrorCode [C, ALIAS: '_GetLastErrorCode'] (index)
    
            USE ISO_C_BINDING
    
            INTEGER(C_SIZE_T), INTENT(IN) :: index
        END FUNCTION GetLastErrorCode
    END INTERFACE
    
    END

Since these modules are used across many Fortran projects, each project has an independent version of the interface function - hence the duplication.

This all makes perfect sense, but my question is: can I just ignore the warnings (i.e. exclude them in the project configuration)?  I can't see any obvious way to restructure our code to remove the warnings, and I was under the impression that putting these interfaces in a module was good practice...

0 Kudos

Accepted Solutions
Highlighted
Black Belt
212 Views

If you are compiling a STDCALL function for 32 bit windows (x86) the compiler may generate two symbolic names for the procedure, one with the @nn suffix decoration and one without.  Consequently the number of duplicate symbols is doubled.

As per stack overflow, you don't want to be compiling the same module multiple times.  Move the entire module (and perhaps some prerequisites) into a new project, and then reference that project (right click on the project name in the solution explorer, select Project/Build dependencies (depending on VS version - nominate the appropriate prerequisite project) in any project that originally compiled the module.  This isn't a source change - it is a change to the way your source files are arranged into projects.

Attached a simple example - the module A in LibA is referenced by the modules in both projects LibB and LibC.

 

View solution in original post

0 Kudos
7 Replies
Highlighted
212 Views

Something else is wrong - an interface does not create a definition. Furthermore, the interface you showed (using obsolete Microsoft Fortran PowerStation syntax) would not create a symbol of the form you show in the error message. So your guess as to what is creating the duplicates is not correct.

So, no, you can't ignore these errors as you don't know yet what is causing them.

0 Kudos
Highlighted
Beginner
212 Views

Thanks you, Steve - it looks like we're going to have to move a lot of our accessor functions.

On the interface subject, I've just looked again, and the warnings are slightly different:

Warning    2155     warning LNK4006: _MINTERFACES_mp_GETGAUGE@16 already defined in control F.lib(mInterfaces.obj); second definition ignored    dtrain F.lib(mInterfaces.obj)    

This warning includes the prefix _MINTERFACES_mp to the function name, whereas the functions fully defined in the modules do not.  Does this have any significance?

I'm also looking for the modern interface block definition.  Is it the one here: https://software.intel.com/en-us/forums/intel-visual-fortran-compiler-for-windows/topic/275071#comme....  In which case it seems very similar, but doesn't appear to allow the specification of calling convention.  Is that an option?

 

0 Kudos
Highlighted
212 Views

The significance is that your module MINTERFACES contains a module procedure GETGAUGE, not just an interface block.  This causes the global symbol to be prefixed with MINTERFACES_mp_. The message also tells me that you have the object from compiling MINTERFACES in both libraries and for some reason both are being pulled in by the linker (perhaps one has a different set of symbols defined.) 

0 Kudos
Highlighted
Black Belt
212 Views

A handy document for the specification of the standard syntax is the draft standard, some of the variants of which is linked to in the "Useful information and frequently asked questions" for this forum available at the top of the home page of this forum.  For example, in the F2008 committee working draft, see section 12.4.3.2 (just search for the syntax rule "interface-body").  If you read the syntax for the function statement that opens an interface body for a function you will see that you can have an optional BIND(C,NAME='xxx') suffix on the statement, which specifies that the interface is for a function that is interoperable with C (has the C calling convention), with the C identifier xxx.

This syntax is also documented in the Intel Fortran help installed with the compiler (see for example the description of the function statement), but I think it is a little harder to fish out in this case.

On stack overflow you will find numerous examples in questions with the (unfortunately named) fortran-iso-c-binding tag.

0 Kudos
Highlighted
Beginner
212 Views

Thank you Steve and Ian - I think I'm getting to the bottom of it.

A vast majority of the warnings are coming from the modules' "accessors", which are defined in the modules themselves, instead of a separate file where they would only be compiled once.

On further inspection, the second category isn't coming from the interface blocks themselves, but from the paradigm that I'm using to interface a C function that returns a char*.  This is described here: http://stackoverflow.com/questions/9972743/creating-a-fortran-interface-to-a-c-function-that-returns-a-char.

Effectively, this maps an interface block to the C function thus:

    interface TYPE(C_PTR) function GetGaugeNamePtr(pointer, index_gauge) bind(C, name='GetGaugeName')       ! Maps to the C function GetGaugeName

But the function called from Fortran is:

    FUNCTION GetGaugeName(pointer, index_gauge)       ! This calls the function GetGaugeNamePtr and converts the C pointer into a Fortran string

Although this all links up and works fine, the linker firstly finds the complete body for GetGaugeName defined in the module (this is a correct warning and could be fixed by moving these into a separate file which is compiled only once), but I think there might be something else going on as well, as each module reports the warning twice:

Warning    140     warning LNK4006: _minterfaces_mp_getgaugename already defined in project1.lib(mInterfaces.obj); second definition ignored    project2.lib(mInterfaces.obj), and

 

Warning    141     warning LNK4006: _minterfaces_mp_getgaugename@16 already defined in project1.lib(mInterfaces.obj); second definition ignored    project2.lib(mInterfaces.obj)    

0 Kudos
Highlighted
Black Belt
213 Views

If you are compiling a STDCALL function for 32 bit windows (x86) the compiler may generate two symbolic names for the procedure, one with the @nn suffix decoration and one without.  Consequently the number of duplicate symbols is doubled.

As per stack overflow, you don't want to be compiling the same module multiple times.  Move the entire module (and perhaps some prerequisites) into a new project, and then reference that project (right click on the project name in the solution explorer, select Project/Build dependencies (depending on VS version - nominate the appropriate prerequisite project) in any project that originally compiled the module.  This isn't a source change - it is a change to the way your source files are arranged into projects.

Attached a simple example - the module A in LibA is referenced by the modules in both projects LibB and LibC.

 

View solution in original post

0 Kudos
Highlighted
Beginner
212 Views

Thanks, IanH.  Sorry it's taken me a while to get back on this - I've been out for a few days, and it took a long time to re-organise all of the projects.

But it seems to work!  It all compiles correctly, and the warnings have dropped from ~4000 to ~1000 - still a way to go, but it gets a lot of 'chafe' out of the way.

0 Kudos