- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This inquiry is an attempt to assist a team at work who currently encounter error(s) during linking a Windows DLL with a Fortran codebase that uses SUBMODULEs (due to my prior advice) and which also employs the /IFACE:CVF compiler option.
Unfortunately I don't have all the details and due to the sensitive nature of the work involving external customers and US DOE, I am not authorized to review any code besides a few API procedures which I am not allowed to refactor either. Thus I am constrained in what I can do.
Based on the limited information the team shared with me verbally, I came up with the following reproducer:
- Say there is a module 'm' in a file 'm.f90' that defines some procedure interfaces, say a subroutine named 'SUB' and a function 'FUNC'
module m interface module subroutine sub(a) !DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_SUB' :: sub !DIR$ ATTRIBUTES DLLEXPORT :: sub integer, intent(inout) :: a end subroutine module function func(x) result(r) !DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_FUNC' :: func !DIR$ ATTRIBUTES DLLEXPORT :: func integer, intent(in) :: x integer :: r end function end interface end module
- Say the subroutine 'SUB' is implemented in a SUBMODULE in a file named 'sub.f90'
submodule(m) sub_sm contains module subroutine sub( a ) !DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_SUB' :: sub !DIR$ ATTRIBUTES DLLEXPORT :: sub integer, intent(inout) :: a a = func( a ) + 42 end subroutine end submodule
- Similarly the function 'FUNC' in a SUBMODULE in a file named 'func'
submodule(m) func_sm contains module function func(x) result(r) !DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_FUNC' :: func !DIR$ ATTRIBUTES DLLEXPORT :: func integer, intent(in) :: x integer :: r r = x + 1 end function end submodule
The requirements due to the project agreements among all the parties include:
- The target platform for the Windows DLL shall be IA-32,
- The use of the DLL among different parties imply the protocol for the external procedures shall be STDCALL, REFERENCE, and MIXED_STRING_LEN_ARG for character string length argument passing i.e., /IFACE:CVF
- There must be ALIASes for the API procedures but which are not based on `BIND(C)`.
The naïve reproducer above strives to include these 3 requirements. Here is an illustration of the linker error(s) encountered with this reproducer:
C:\temp>ifort /c /standard-semantics /iface:cvf /Qm32 m.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
C:\temp>ifort /c /standard-semantics /iface:cvf /Qm32 sub.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
C:\temp>ifort /c /standard-semantics /iface:cvf /Qm32 func.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
C:\temp>link m.obj sub.obj func.obj /dll /out:m.dll
Microsoft (R) Incremental Linker Version 14.33.31630.0
Copyright (C) Microsoft Corporation. All rights reserved.
func.obj : error LNK2005: _M already defined in sub.obj
Creating library m.lib and object m.exp
LINK : warning LNK4217: symbol '_M_FUNC@4' defined in 'func.obj' is imported by 'sub.obj' in function '_M_SUB'
m.dll : fatal error LNK1169: one or more multiply defined symbols found
C:\temp>
Now consider the same exact code built using /IFACE:default option:
C:\temp>ifort /c /standard-semantics /iface:default /Qm32 m.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
C:\temp>ifort /c /standard-semantics /iface:default /Qm32 sub.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
C:\temp>ifort /c /standard-semantics /iface:default /Qm32 func.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
C:\temp>link m.obj sub.obj func.obj /dll /out:m.dll
Microsoft (R) Incremental Linker Version 14.33.31630.0
Copyright (C) Microsoft Corporation. All rights reserved.
Creating library m.lib and object m.exp
LINK : warning LNK4217: symbol '_M_FUNC' defined in 'func.obj' is imported by 'sub.obj' in function '_M_SUB'
C:\temp>
But for the LNK4217 warning, the Microsoft linker succeeding in creating the DLL. Now consider a trivial caller of this DLL in a file named 'p.f90':
use m, only : sub
integer :: n
n = 0
call sub( n )
print *, n
end
Here is the program response consuming the above DLL:
C:\temp>ifort p.f90 m.lib /standard-semantics
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.0 Build 20220726_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
Microsoft (R) Incremental Linker Version 14.33.31630.0
Copyright (C) Microsoft Corporation. All rights reserved.
-out:p.exe
-subsystem:console
p.obj
m.lib
C:\temp>p.exe
43
C:\temp>
Thus code is correct enough to work with /IFACE:default setting, but the linker fails when the code is processed using /IFACE:CVF option.
The questions I am grappling with include: 1) why does the linker throw errors with /IFACE:CVF and 2) how can this team get around the linker error while satisfying their program requirements. My hunch is the answer to 1) is a bug in Intel Fortran compiler: therefore I have submitted a support request with Intel Online Support Center. And I have asked about 2).
Does anyone have any suggestions or feedback on why the linker error(s) and how to get around them?
Thank you,
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Do you get what you want by using /IFACE:DEFAULT and putting CVF in the !DIR$ ATTRIBUTES statements (eg !DIR$ ATTRIBUTES CVF, DECORATE, ALIAS : 'M_SUB' :: sub) ? It seems to compile and link ok with ifort 19.1.2.254 (though the function names in the warning are different)
1>Compiling with Intel(R) Visual Fortran Compiler 19.1.2.254 [IA-32]...
1>m.f90
1>func.f90
1>sub.f90
1>Linking...
1>Creating library G:\Sandbox\Scratch\temps01\Console1\Dll1\Debug\Dll1.lib and object G:\Sandbox\Scratch\temps01\Console1\Dll1\Debug\Dll1.exp
1>sub.obj : warning LNK4217: locally defined symbol _M_mp_M_FUNC@4 imported in function _M_mp_M_SUB
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
@mfinnis ,
Thank you very much for your reply and your looking into this, greatly appreciated. I have forwarded the link to this thread and your reply to this team. They tell me they are currently constrained to apply the /IFACE:CVF to the Fortran MODULE files also due to several factors involving external customers and a custom build system from a 3rd party simulation vendor. And with that /IFACE:CVF option, the linker error persists unfortunately.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is indeed a compiler bug, but there is a workaround. (In fact, the workaround is preferable to using /iface).
Compare the symbol dump from submodule M compiled with /iface:cvf
000 00000000 SECT1 notype Static | .text
Section length 30, #relocs 1, #linenums 0, checksum 0
002 00000000 SECT1 notype () External | _M@SUB_SM.@0
003 00000000 SECT1 notype () External | _M
004 00000010 SECT1 notype () External | _M_SUB@4
005 00000010 SECT1 notype () External | _M_SUB
006 00000000 UNDEF notype External | __imp__M_FUNC@4
007 00000000 SECT2 notype Static | .drectve
Section length FD, #relocs 0, #linenums 0, checksum 0
009 00000001 ABS notype Static | @feat.00
and without:
000 00000000 SECT1 notype Static | .text
Section length 30, #relocs 1, #linenums 0, checksum 0
002 00000000 SECT1 notype () External | _M@SUB_SM.
003 00000010 SECT1 notype () External | _M_SUB
004 00000000 UNDEF notype External | __imp__M_FUNC
005 00000000 SECT2 notype Static | .drectve
Section length C9, #relocs 0, #linenums 0, checksum 0
007 00000001 ABS notype Static | @feat.00
Notice that with /iface:CVF, there is an extraneous symbol _M defined - this should not be there. This symbol is properly created when module M is compiled (there is a version with and without STDCALL decoration), but it should not be there for the submodule.
The workaround? Instead of using /iface:cvf, add CVF to the ATTRIBUTES directive for the exported symbols. You'll need to do this in both the module and the submodule. For example:
module m
interface
module subroutine sub(a)
!DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_SUB' :: sub
!DIR$ ATTRIBUTES DLLEXPORT, CVF :: sub
integer, intent(inout) :: a
end subroutine
module function func(x) result(r)
!DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_FUNC' :: func
!DIR$ ATTRIBUTES DLLEXPORT, CVF :: func
integer, intent(in) :: x
integer :: r
end function
end interface
end module
submodule(m) sub_sm
contains
module subroutine sub( a )
!DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_SUB' :: sub
!DIR$ ATTRIBUTES DLLEXPORT, CVF :: sub
integer, intent(inout) :: a
a = func( a ) + 42
end subroutine
end submodule
submodule(m) func_sm
contains
module function func(x) result(r)
!DIR$ ATTRIBUTES DECORATE, ALIAS : 'M_FUNC' :: func
!DIR$ ATTRIBUTES DLLEXPORT, CVF :: func
integer, intent(in) :: x
integer :: r
r = x + 1
end function
end submodule
If we do that and compile sub.f90 without /iface, we get:
000 00000000 SECT1 notype Static | .text
Section length 30, #relocs 1, #linenums 0, checksum 0
002 00000000 SECT1 notype () External | _M@SUB_SM.
003 00000010 SECT1 notype () External | _M_mp_M_SUB@4
004 00000010 SECT1 notype () External | _M_mp_M_SUB
005 00000000 UNDEF notype External | __imp__M_mp_M_FUNC@4
006 00000000 SECT2 notype Static | .drectve
Section length 111, #relocs 0, #linenums 0, checksum 0
008 00000001 ABS notype Static | @feat.00
Putting it all together:
D:\Projects>ifort /c /standard-semantics m.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.1 Build 20221019_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
D:\Projects>ifort /c /standard-semantics sub.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.1 Build 20221019_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
D:\Projects>ifort /c /standard-semantics func.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on IA-32, Version 2021.7.1 Build 20221019_000000
Copyright (C) 1985-2022 Intel Corporation. All rights reserved.
D:\Projects>link m.obj sub.obj func.obj /dll /out:m.dll
Microsoft (R) Incremental Linker Version 14.33.31630.0
Copyright (C) Microsoft Corporation. All rights reserved.
Creating library m.lib and object m.exp
LINK : warning LNK4217: symbol '_M_mp_M_FUNC@4' defined in 'func.obj' is imported by 'sub.obj' in function '_M_mp_M_SUB'
In general, avoid using command line options such as /iface and /names - use ATTRIBUTES directives if you need to.
By the way, that link warning can be ignored - it is telling you that you asked a symbol to be DLLIMPORTed, but it is defined in that DLL. This happens because the interface for func specifies DLLEXPORT, which turns into a DLLIMPORT when the module is used (implicitly by the submodules.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thank you Steve, as I mentioned in my previous comment the team in question has the link to this thread plus I have forwarded to them your post.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks @Barbara_P_Intel , hopefully the Intel Fortran team will agree it is a bug and be able to provide a fix in IFORT in a future release.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page