- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Fortranners, consider the following function,
module Square_mod implicit none contains function getSquare(val) result(valSquared) bind(C, name="getSquare") !DEC$ ATTRIBUTES DLLEXPORT :: getSquare use iso_c_binding use, intrinsic :: iso_fortran_env, only: RK => real64 real(RK), intent(in) :: val real(RK) :: valSquared valSquared = val ** 2 end function getSquare end module Square_mod
Now generating the DLL,
ifort /dll Square_mod.f90 /exe:Square
and here is a program that can successfully call the function in the DLL,
program Square_prog use, intrinsic :: iso_fortran_env, only: RK => real64 use Square_mod, only: getSquare implicit none real(RK) :: val = 100._RK write(*,"(*(g0.13,:,' '))") "Square of", val, "is", getSquare(val) end program Square_prog
However, consider the following modified module that gives its function a different bind(c) name, getSq,
module Square_mod implicit none contains function getSquare(val) result(valSquared) bind(C, name="getSq") !DEC$ ATTRIBUTES DLLEXPORT :: getSquare use iso_c_binding use, intrinsic :: iso_fortran_env, only: RK => real64 real(RK), intent(in) :: val real(RK) :: valSquared valSquared = val ** 2 end function getSquare end module Square_mod
Note that the only difference with the original function is in the binding name. I expected this function to be callable with the new name from the main program, but it is not,
program Square_prog use, intrinsic :: iso_fortran_env, only: RK => real64 use Square_mod, only: getSq implicit none real(RK) :: val = 100._RK write(*,"(*(g0.13,:,' '))") "Square of", val, "is", getSq(val) end program Square_prog
Why is ifort able to "use Square_mod, only: getSquare" in the first version with a binding name that is the same as the function name, while in the latter case with a binding name different from the function name, it gives the following compile error?
Square_prog.f90(3): error #6580: Name in only-list does not exist or is not accessible. [GETSQ] use Square_mod, only: getSq --------------------------^ Square_prog.f90(6): error #6404: This name does not have a type, and must have an explicit type. [GETSQ] write(*,"(*(g0.13,:,' '))") "Square of", val, "is", getSq(val) --------------------------------------------------------^ compilation aborted for Square_prog.f90 (code 1)
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think I have got a reasonable understanding of the issue here. The following code, nicely compiles and runs,
program Square_prog use, intrinsic :: iso_fortran_env, only: RK => real64 use Square_mod, only: getSquare implicit none real(RK) :: val = 100._RK interface function getSq(val) result(valSquared) !DEC$ ATTRIBUTES DLLIMPORT, DECORATE, ALIAS: 'getSq' :: getSq use, intrinsic :: iso_fortran_env, only: RK => real64 real(RK), intent(in) :: val real(RK) :: valSquared end function getSq end interface write(*,"(*(g0.13,:,' '))") "Square of", val, "is", getSquare(val) write(*,"(*(g0.13,:,' '))") "Square of", val, "is", getSq(val) end program Square_prog
with the following module compiled to a DLL file that is used by the above program,
module Square_mod implicit none contains function getSquare(val) result(valSquared) bind(C, name="getSq") !DEC$ ATTRIBUTES DLLEXPORT :: getSquare use, intrinsic :: iso_fortran_env, only: RK => real64 real(RK), intent(in) :: val real(RK) :: valSquared valSquared = val ** 2 end function getSquare end module Square_mod
So it seems like, when the bind name (getSq) and the DLLEXPORT (getSquare) name are different, both of them are exported, one as a module procedure which can be "USE"d in Fortran program, and the other as a global identifier "getSq" which can be called by other languages as well as Fortran, as done in the above example program.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'd say that was a compiler bug. As you found, the ALIAS attribute works; BIND(C, NAME=) should work the same. Please submit a bug report to Intel Support. Ignore - see below.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think the original program shouldn't compile. The binding label is just a name visible to the linker or in a *.DLL and isn't syntactically the same as the name of a function. You could use it in a Fortran program by explicitly linking to it (XXX in my example) or using LoadLibrary, GetProcAddress, and C_F_PROCPOINTER (YYY in my example, that I can't seem to get to work just now), but there is no way to just invoke it as a function.
program Square_prog use, intrinsic :: iso_fortran_env, only: RK => real64 use Square_mod, only: getSquare use IFWIN, only: LoadLibrary, HANDLE, GetProcAddress use ISO_C_BINDING, only: C_FUNPTR, C_F_PROCPOINTER implicit none procedure(getSquare), bind(C,name='getSq') :: XXX integer(HANDLE) hModule type(C_FUNPTR) :: ProcAddress procedure(getSquare), pointer :: YYY real(RK) :: val = 100._RK write(*,"(*(g0.13,:,' '))") "Square of", val, "is", XXX(val) hModule = LoadLibrary('Square.dll'//achar(0)) ProcAddress = transfer(GetProcAddress(hModule,'getSq'//achar(0)),ProcAddress) call C_F_PROCPOINTER(ProcAddress,YYY) write(*,"(*(g0.13,:,' '))") "Square of", val, "is", YYY(val) end program Square_prog
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Repeat Offender, very interesting third approach, that I had no idea about. Any resources to learn more about IFWIN module would be greatly appreciated.
Steve, thanks. Which implementation is a bug in your opinion? original, or the alternative using `getSq` as the bind name, or the last solution in my response to the question (via DLLIMPORT)?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Sorry, I missed something again.
The original program shows correct behavior. As RO correctly says, you are not supposed to use the binding label for a reference in Fortran. getSq is not a Fortran identifier defined by the module. The compiler correctly DLLEXPORTs 'getSq' as the global symbol and correctly references it when you call getSquare in the main program. There is no compiler bug.
Your revised program that "works" basically does an end-run around the module interface. You should never have to declare an explicit interface to a Fortran routine (generics and submodules sometimes excepted.)
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page