2017-11-16 14 views
1

gfortran으로 컴파일 된 Fortran 코드에서 DLL을 호출하려고합니다. 내가 함께 에게 DISCON_32.dll을 가져 해요 :Fortran에서 외부 DLL을 호출하고 gfortran으로 컴파일 할 때 대소 문자를 구분할 때 문제가 발생했습니다.

!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" 소문자라고합니다. 종속성 워커를 사용하여 DLL을 조사 할 때 진입 점은 "DISCON" (대문자)입니다.

DLL의 대소 문자를 변경할 수 없습니다. 내 포트란 코드에 "discon"대신 "DISCON"진입 점을 찾도록 지시하는 방법이 있습니까? 의 문제를 설명하기위한 예제 DLL 및 포트란 주를 만들어 보자 :

이 작업을 수행하는 3 가지 방법이 있습니다

+0

"별칭"을 사용하면! DEC $ ATTRIBUTES DLLIMPORT, DECORATE, ALIAS와 같은 다른 컴파일러와 비슷한 구성을 사용하고 있습니까? 'DISCON':: DISCON gfortran (확실하지 않음) 및 적어도이 대문자로이 동작을 변경하는 플래그를 찾을 수 없습니다. – PiWi

답변

0

(문제의 내 확장 된 인터넷 검색 가까이 솔루션에 저를하지 않았다).

! 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을 빌드하는 데 사용되는 명령 줄은 주석에 표시됩니다.
이제 우리는 포트란 주요 있습니다 위

! 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 

위의 첫 번째 주석 행은 dll2.ool.exe에서 dll2.def의 시작점을 만드는 방법을 보여줍니다. 우리의 경우 출력물은 그다지 유용하지 않으므로 대부분 텍스트 편집기를 사용하여 시작점을 수정했습니다. dll2.def 파일은 dll1.dll과 링크하기 위해 usefule 인 libdll2.a 파일을 작성하므로 위의 LIBRARY 행을 사용하십시오. 내 보낸 심볼은 'F'였지만, gfortran은 'f'를 찾으므로 내보내기 섹션에서 이름을 바꿉니다.
그런 다음 위의 두 번째 주석 행을 통해 dlltool.exe를 사용하여 libdll2.a를 만듭니다. libdll2.a를 사용하면 6 또는 7 행의 주석에 따라 main1.f90을 컴파일 할 수 있습니다.
두 번째 방법은 함수에 바인딩 이름을 사용합니다. 이것은 함수가 상호 운용 될 것을 요구하지만, 그렇지 않다면 아마 gfortran에 의해 컴파일되지 않았다고 가정하면 어떤 간단한 방법으로도 호출 할 수 없을 것입니다. 여기에서 우리는 main2.f90에, 함수의 단지 다른 선언을 추가 dll2.lib 필요하지 않습니다 :

! 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 같이 동적 링크를 사용할 수 있습니다 다음 gfortran 명령

! 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 

하나를 코멘트에 성공적으로 main3.exe을 구축합니다.

참고 : 재시험 중, main2.f90 및 main3.f90 메서드는 작동했지만 어떤 이유로 main1.f90 및 dll2.def를 사용하는 메서드가 더 이상 작동하지 않고 dll1.dll이 아닌 main1.exe에서 심볼 'f'를 찾으려고하기 때문에 런타임에 오류가 발생합니다. 이 시점에서 이유를 알 수 없습니다.

편집 : 글쎄, 위에서 만든 dll1.dll하고 그대로 main1.f90와 첫 번째 방법 일을 할 수있는 방법을 찾았지만, 그래서 나는 기다릴 것이다 like에게 정말하지 않습니다 다른 사람이 좀 더 맛있는 해결책을 제시하는지 확인하는 데는 며칠이 걸립니다. 그 시간이 지나도 이런 일이 일어나지 않고 누군가가 여전히 관심이 있다면 그는 나에게 생각 나게해야하고 내가 생각한 것을 올릴지도 모른다.

+0

명령 줄의 명령 줄? 여기에 의견이 없습니다. –

+0

dll1.f90의 2 번 줄, main1.f90m 줄 1의 3 번, 4 번 및 7 번 줄,보다 유용하게는 2 번, 2 번 및 3 번 줄은 main2.f90, 줄 2 및 3은 main3입니다. f90. 브라우저에 표시되지 않습니까? – user5713492

+0

좋아요, 소스 파일의 주석에, 지금 볼 수 있습니다. –