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

Calling a Fortran DLL from Fortran

gib
New Contributor II
1,765 Views

I've been doing this for years, but now a simple example fails.  The only difference I can see is that I am starting to use the oneAPI compiler (building x64 with VS2019).

Here is the DLL code:

subroutine fortran_sub(i, j, n) BIND(C)
!DEC$ ATTRIBUTES DLLEXPORT :: fortran_sub
use, intrinsic :: iso_c_binding
integer(c_int) :: i, j, n

i = j**n
end subroutine

 

and here is the calling program code:

 

!DIR$ ATTRIBUTES :: fortran_sub
program main
integer :: i, j, n
j = 2
n = 5
call fortran_sub(i,j,n)
write(*,*) "i = ",i
end program

 

This fails to build:

error LNK2019: unresolved external symbol FORTRAN_SUB referenced in function MAIN__

although this is the pattern I have always used.

If I add STDCALL to ATTRIBUTES, it builds, but gives an access violation error when executed.

 

0 Kudos
4 Replies
mecej4
Honored Contributor III
1,741 Views

Compiler version: 2021.3.0 , targeting 64-bit.

The DLL source code:

 

subroutine fortran_sub(i,j,n)
implicit none
integer :: i,j,n
!
i = j**n
return
end subroutine

 

Building the DLL:

 

ifort /dll fsub.f90 /link /export:FORTRAN_SUB

 

 

The source for the calling program:

 

program main
integer :: i, j, n
j = 2
n = 5
call fortran_sub(i,j,n)
write(*,*) "i = ",i
end program

 

 

Building the EXE:

 

ifort fmain.f90 fsub.lib

 

 

0 Kudos
gib
New Contributor II
1,729 Views

Hi mecej4,

Thanks.  I am not at the machine with oneAPI installed right now, but I'm sure when I test it I will confirm that your command line build works.  You probably wondered why I used BIND(C) and iso_c_binding.  It is because I will want to call the DLL from C++ as well as from Fortran.  The other point of difference is that I want to build the programs in Visual Studio, which is my standard operating mode.  As I mentioned, the way I am trying to build this program is exactly the way I have been building other DLLs and using them with both C++ and Fortran calling programs (as far as I can tell, although I might be forgetting something.)  I wanted to test the Fortran calling first.  Can you carry out the build in VS 2019? 

0 Kudos
mecej4
Honored Contributor III
1,724 Views

Yes, Gib, before I replied in a matter-of-fact manner, it occurred to me to comment about the seemingly haphazard sprinkling of directives and attributes in your code, and the scantiness of information about your motivations and methods.

Your trying STDCALL is an instance of a "try something different" approach, and one could spend a few months trying all sorts of similar combinations of mismatched attributes, directives and build options. I put your use of BIND(C) in the same category, since you did not describe your objectives, and I do not know what you "have been doing for years".

The reason for the "unresolved external symbol" linker error is quite simple. You gave the BIND(C) attribute in the DLL source to the subroutine, which causes the symbol to be lower-case in the OBJ and DLL. In the Fortran caller, you did not specify BIND(C), and the default is to upper-case the symbol. Thus, the symbol in the library and the symbol in the OBJ will not match.

The code and procedure that I gave above work equally well with IFort 2013SP1 (64-bit).

I do not use Visual Studio to compose or build. There are any number of articles on how to do build DLLs using VS, including postings going back to the early 2000-s in this forum.  Perhaps someone else will help you with your request.

0 Kudos
gib
New Contributor II
1,671 Views

Hi mecej4,

(I already replied - or so I thought - but don't see my reply, so here I go again)

Yes, I should have provided more background in my post.  The source of my puzzlement is the fact that for years I have built and used DLLs created in the same way, with Intel Fortran and VS (up to 2012), calling them from both C++ and Fortran.  I never had to supply "name = ..." in the BIND statement.

Now I find that with BIND(C, name="FORTRAN_SUB") the Fortran caller builds and runs, and a C++ caller also runs when it calls FORTRAN_SUB.  If I use BIND(C, name="fortran_sub") the Fortran caller's build fails, but the C++ caller is happy calling fortran_sub.

Something has changed.  I previously never had to use the upper-case subroutine name when calling from Fortran.  I don't understand what is happening.  dumpbin -exports testlib.lib shows the export name as fortran_sub - why is the caller now not happy with the lower-case name?  Is this a change in VS2019, or in oneAPI Fortran?  I suspect the latter.  I have been using a very old version of IVF, 11.0.075, and I'm happy finally to be able to upgrade free.

(By the way, although the forum wants to label me "New Contributor II" I've been posting here for at least 15 years.  I even received a very useful and much-appreciated gift from Intel of a great set of Ifixit tools, which I use often.   Thanks Intel!  At some point I needed to change my password and somehow became a new user.  Not that it matters.)

 

<edit> After containing fortran_sub in a module the Fortran caller builds and runs, with the lower-case name.  Now that I think about it, I have always been using modules for the DLLs.  Duh.

0 Kudos
Reply