我试图从使用gfortran编译的Fortran代码中调用DLL。我使用
导入 DISCON_32.dll!GCC$ ATTRIBUTES DLLIMPORT :: DISCON
并编译:
mingw32-gfortran "DISCON_32.dll" -cpp -ffree-line-length-none -fno-automatic -Wall -fdefault-real-8 -fno-underscoring -static BladedDLLInterface.o -o "my_program"
我收到错误:
BladedDLLInterface.o:BladedDLLInterface.f90(.text+0x6cd): undefined reference to 'discon'
请注意,入口点" discon" 在此处称为小写。使用Dependency Walker查看DLL时,入口点为" DISCON" (大写)。
我无法改变DLL的情况。有没有办法告诉我的Fortran代码寻找" DISCON"入口点而不是" discon"?
(我对该问题的扩展谷歌搜索没有让我更接近解决方案)
答案 0 :(得分:0)
有三种方法可以做到这一点:让我们制作一个示例DLL和Fortran main来演示这个问题。
! dll1.f90
! gfortran dll1.f90 -shared -odll1.dll -Wl,--out-implib,libdll1.a
module not_used
use ISO_C_BINDING
implicit none
contains
function F(x) bind(C,name='F')
!GCC$ ATTRIBUTES DLLEXPORT :: F
real(C_DOUBLE) F
real(C_DOUBLE), intent(in) ::x
F = x**2
end function F
end module not_used
用于构建dll1.dll的命令行显示在注释中 现在我们有一个Fortran主要:
! main1.f90
! fails:
! gfortran main1.f90 dll1.dll -omain1
! gfortran main1.f90 -L. -ldll1 -omain1
! works:
! gfortran main1.f90 dll1.dll -L. -ldll2 -omain1
! gfortran main1.f90 -L. -ldll1 -ldll2 -omain1
module mod1
implicit none
interface
function F(x)
import
implicit none
!GCC$ ATTRIBUTES DLLIMPORT :: F
double precision F
double precision, intent(in) :: x
end function F
end interface
end module mod1
program main1
use mod1
implicit none
double precision x, y
x = 13
y = f(x)
write(*,*) y
end program main1
上面显示的前两个gfortran命令无法构建main1.exe。第二个工作,但我们需要一个libdll2.a文件,我们可以用dlltool.exe创建它。我们从dll2.def
开始; dlltool -z dll2.def --export-all-symbol dll1.dll
; dlltool -d dll2.def -l libdll2.a
LIBRARY dll1.dll
EXPORTS
f = F
上面的第一个注释行显示了如何使用dlltool.exe为dll2.def创建一个起点。在我们的例子中输出不是很有用,所以我们主要使用文本编辑器来修改起点。 dll2.def文件将创建一个libdll2.a文件,该文件是用于链接dll1.dll的usefule,因此上面是LIBRARY行。导出的符号是' F',但是gfortran会查找“f”,所以我们在导出部分重命名它。
然后我们使用dlltool.exe通过上面的第二个注释行创建libdll2.a。拥有libdll2.a意味着我们可以根据第6行或第7行中的注释编译main1.f90
第二种方法使用函数的绑定名称。这要求函数可以互操作,但如果它不是,那么你可能无法以任何简单的方式调用它,因为它可能不是由gfortran编译的。在这里,我们不需要额外的dll2.lib,只是main2.f90中函数的不同声明:
! main2.f90
! gfortran main2.f90 dll1.dll -omain2
! gfortran main2.f90 -L. -ldll1 -omain2
module mod2
use ISO_C_BINDING
implicit none
interface
function F(x) bind(C,name='F')
import
implicit none
!GCC$ ATTRIBUTES DLLIMPORT :: F
real(C_DOUBLE) F
real(C_DOUBLE), intent(in) :: x
end function F
end interface
end module mod2
program main2
use mod2
implicit none
double precision x, y
x = 13
y = f(x)
write(*,*) y
end program main2
这可以使用评论中给出的任一gfortran命令进行编译 最后,您可以使用动态链接,如main3.f90:
! main3.f90
! gfortran main3.f90 dll1.dll -omain3
! gfortran main3.f90 -L. -ldll1 -omain3
module mod3
use ISO_C_BINDING
use ISO_C_BINDING, HANDLE => C_INTPTR_T
use ISO_C_BINDING, C_INTPTR_T => C_INTPTR_T
implicit none
abstract interface
function F(x) bind(C)
import
implicit none
real(C_DOUBLE) F
real(C_DOUBLE), intent(in) :: x
end function F
end interface
interface
function LoadLibrary(lpFileName) bind(C,name='LoadLibraryA')
import
implicit none
!GCC$ ATTRIBUTES STDCALL :: LoadLibrary
integer(HANDLE) :: LoadLibrary
character(kind=C_CHAR) lpFIleName(*)
end function LoadLibrary
function GetProcAddress(hModule,lpProcName) bind(C,name='GetProcAddress')
import
implicit none
!GCC$ ATTRIBUTES STDCALL :: GetProcAddress
type(C_FUNPTR) GetProcAddress
integer(HANDLE), value :: hModule
character(kind=C_CHAR) lpProcName(*)
end function GetProcAddress
end interface
end module mod3
program main3
use mod3, F1 => F
implicit none
double precision x, y
type(C_FUNPTR) ptr
procedure(F1), pointer :: F
integer(HANDLE) hModule
hModule = LoadLibrary('dll1.dll'//C_NULL_CHAR)
ptr = GetProcAddress(hModule,'F'//C_NULL_CHAR)
call C_F_PROCPOINTER(ptr,F)
x = 13
y = f(x)
write(*,*) y
end program main3
评论中的任何一个gfortran命令都成功构建了main3.exe。
注意:在重新测试时,main2.f90和main3.f90方法有效,但由于某些原因,使用main1.f90和dll2.def的方法不再有效,在运行时失败,因为它&# 39;试图找到符号' f'在main1.exe而不是dll1.dll。在这一点上无法弄清楚原因。
编辑:嗯,我找到了一种方法,让第一种方法与上面创建的dll1.dll和main1.f90一起工作,但我不是真的{{ 3}}所以我等了几天才看看别人是否想出了一个更可口的解决方案。如果在那段时间之后,这还没有发生,有人仍然感兴趣,他应该提醒我,我可以发布我想出的内容。