В настоящее время я разрабатываю fortran DLL, и у меня есть проблема с функциями с несколькими переменными. Моя конечная цель состоит в том, чтобы
- вызывать функции DLL из VBA
- отлаживать DLL, используя код на фортране, вызывающий функции DLL
Вот мой упрощенный случай:
<сильный>1. DLL-код Фортрана
module mod_thermo
implicit none
contains
function y1(x1) result(y) bind(c, name = "Y1")
use iso_c_binding, only : c_double
!GCC$ attributes dllexport, stdcall :: y1
real(c_double) :: x1
real(c_double) :: y
y = 2.d0 * x1
end function
function y2(x1, x2) result(y) bind(c, name = "Y2")
use iso_c_binding, only : c_double
!GCC$ attributes dllexport, stdcall :: y2
real(c_double) :: x1
real(c_double) :: x2
real(c_double) :: y
y = 2.d0 * x1 * x2
end function
end module
<сильный>2. Параметры компиляции Fortran DLL с помощью GCC
Компилятор - GCC. Варианты компиляций:
- -static (чтобы избежать зависимостей от других dll)
- -Wl,--kill-at (относится к VBA)
- -fno-подчеркивание (связано с VBA)
Выходные файлы находятся в папке проекта кода фортрана для будущей отладки:
- dll_thermo.dll
- libdll_thermo.a
- libdll_thermo.def
<сильный>3. Код Fortran для тестирования DLL (интерфейсы + программа)
Библиотека подключается к коду путем добавления библиотеки libdll_thermo.a.
module mod_thermo
implicit none
interface
function y1(x1) result(y) bind(c,name="Y1")
use iso_c_binding, only : c_double
real(c_double) :: x1
real(c_double) :: y
end function
function y2(x1, x2) result(y) bind(c,name="Y2")
use iso_c_binding, only : c_double
real(c_double) :: x1
real(c_double) :: x2
real(c_double) :: y
end function
end interface
end module
program main
use mod_thermo
implicit none
write(*,*)"y1 calls:"
write(*,*)y1(1.d0) ! output ok
write(*,*)y1(2.d0) ! output ok
write(*,*)y1(3.d0) ! output ok
write(*,*)"y2 calls:"
write(*,*)y2(1.d0, 1.d0) ! output ok
write(*,*)y2(2.d0, 2.d0) ! output fails
write(*,*)y2(3.d0, 2.d0)
end program
<сильный>4. Вывод и заключение
Мой вывод состоит в том, что я неправильно выполняю многовариантный вызов функции DLL y2. Каким бы был ваш способ выполнения таких звонков?
real(c_double), value :: x1
и для остальных аргументов то же самое. В противном случае они передаются как указатели, а вам нужны значения. Это повреждает стек, и второй вызов функции завершается ошибкой. - person John Alexiou   schedule 15.12.2019value
дляx1
иx2
как в код DLL, так и в код отладки fortran, и теперь у меня возникает ошибка при первом вызове y2. - person yolegu   schedule 15.12.2019y2(x1,x2)
или во втором вызове функцииy1(x1)
. Это намекает на повреждение стека из-за несоответствия соглашения о вызовах. - person John Alexiou   schedule 15.12.2019value
в объявление переменной. В результате третий вызов y2 приводит к ошибке сегментации. По сравнению с исходным сообщением об ошибке#3 0x75cda88f
заменено на#3 0x75b1a88f
. - person yolegu   schedule 15.12.2019stdcall
из описания экспорта. Я думаю, что Fortran ожидаетstdref
для соглашения о вызовах. - person John Alexiou   schedule 15.12.2019stdcall
- это правильный способ сделать вызов. Более того, использованиеstdcall
не вызывает никаких проблем в VBA. Единственная проблема - связь Fortran-Fortran. - person yolegu   schedule 15.12.2019use ISO_FORTRAN_ENV
. Но в опубликованной вами ссылке на TCL отсутствует ключевое словоstdcall
. - person John Alexiou   schedule 15.12.2019module mod_thermo
объявляется дважды. Модули не похожи на пространства имен, где код может охватывать несколько файлов. Весь блокinterface
в программе лишний, так как функции все равно объявляются внутри модуля. Я имею в виду, что вам не нужны интерфейсы при вызове других функций, объявленных в модулях и импортированных с использованием предложенияuse
, напримерuse iso_fortran_env
. - person John Alexiou   schedule 15.12.2019