i21sys/Docu.Работа с DLL/creating-in-Fortran.odc

Создание DLL в фортране

Для компиляции любого модуля Блэкбокса в нижеследующем тексте нужно выделить текст модуля (или просто ключевого слова MODULE, например, двойным кликом) и выполнить команду меню Dev, Compile Selection.
Общие замечания
Обычно в фортране параметры передаются по ссылке, так что соответствующие параметры в Блэкбоксе должны объявляться как VAR (или IN/OUT, если имеется полное понимание того, что делает соответствующая подпрограмма).
Фортрановские типы float и real*4 соответствуют типу SHORTREAL в Блэкбоксе, а double и real*8  типу REAL.
Если в фортране параметр является массивом, то соответствующий параметр-массив в Блэкбоксе должен быть объявлен с системным флагом [untagged] (об этом см. Особенностиплатформы). Тогда длина массива передается через отдельный параметр.
Массивы размещаются в памяти в фортране по-другому по сравнению с Блэкбоксом: первый индекс меняется быстрее всего: a(0,0), a(1,0), и т.д., ... тогда как в Блэкбоксе a[0,0], a[0,1], и т.д..
Если нужен доступ к переменным в COMMON-блоках, нужно добавить соответствующие процедуры в исходник на фортране.
Мы создадим DLL с именем BBtest.dll из следующих двух подпрограмм на фортране:

	SUBROUTINE proc1 ( a, res )
	INTEGER a
	DOUBLE PRECISION res
	res = a + res
	END

	SUBROUTINE proc2 ( a, res )
	INTEGER a
	DOUBLE PRECISION res
	res = a
	END

Соответствующий интерфейсный модуль для вызова получающейся DLL из Блэкбокса имеет следующий вид

MODULE Epse21DllFortran ["BBtest"];
	PROCEDURE Add* ["proc1"] ( VAR a: INTEGER;  VAR res: REAL );
	PROCEDURE Assign* ["proc2"] ( VAR a: INTEGER;  VAR res: REAL );
END Epse21DllFortran.

Скомпилируем его. Работа с DLL через такой интерфейсный модуль соответствует статической загрузке DLL.
Для проверки скомпилируем следующий модуль и выполним процедуру Do кликом по черному коммандеру, стоящему за модулем:

MODULE  Epse21DllFortranTest;
	IMPORT  Log := StdLog,  Math,  In := Epse21SysIn,  For := Epse21DllFortran;
	
	PROCEDURE Do*;
		VAR  a: INTEGER;  res: REAL;
	BEGIN
		a := 5;  res := 7;
		Log.Int( a );  Log.Real( res );  Log.Ln;
		For.Add( a, res );
		Log.Int( a );  Log.Real( res );  Log.Ln;
		For.Assign( a, res );
		Log.Int( a );  Log.Real( res );  Log.Ln;
	END Do;
	
END  Epse21DllFortranTest.

Epse21DllFortranTest.Do
Compaq/Digital Visual Fortran 6.1.A
Это компилятор, доступный в CERN во время написания данного документа. Эта система (в дальнейшем VF) родственна Visual C++. Главный источник информации  документация VF, разделы Creating Fortran DLLs, Building Dynamic-Link Libraries, Programming with Mixed Languages.
В VF, создадим (Ctrl+N) новый проект класса Dynamic Link Library, назовем его BBtest и укажем для него местонахождение  всё в одном диалоге. Кликнем OK.
В следующем диалоге, которые появится, выберем опцию "A DLL application with exported symbols". Кликнем по Finish. 
Система создает проект с единственным исходником с именем BBTEST.f90.
Дважды кликнем по нему в левой части окна.
В правой части будет показано следующее:

!  BBtest.f90 
!
!  FUNCTIONS/SUBROUTINES exported from BBTEST.dll:
!	BBTEST      - subroutine 
!
subroutine BBTEST

  ! Expose subroutine BBTEST to users of this DLL
  !
  !DEC$ ATTRIBUTES DLLEXPORT::BBTEST

  ! Variables

  ! Body of BBTEST

end subroutine BBTEST

Изменим текст, скопировав две фортрановские подпрограммы, стерев подпрограмму BBTEST и вставив для каждой подпрограммы строчку ATTRIBUTES следующим образом:

!  BBtest.f90 
!
!  FUNCTIONS/SUBROUTINES exported from BBTEST.dll:
!
	SUBROUTINE proc1 ( a, res )
	!DEC$ ATTRIBUTES STDCALL, REFERENCE, DLLEXPORT::proc1
	INTEGER a
	DOUBLE PRECISION res
	res = a + res
	END

	SUBROUTINE proc2 ( a, res )
	!DEC$ ATTRIBUTES STDCALL, REFERENCE, DLLEXPORT::proc2
	INTEGER a
	DOUBLE PRECISION res
	res = a
	END

Смысл опций ATTRIBUTES:

REFERENCE означает, что параметры передаются по ссылке (что соответствует VAR в Блэкбоксе).
STDCALL означает, что будут использоваться соглашения о передаче параметров StdCall; важно использовать STDCALL, если DLL будет загружаться динамически. (В языке Си по умолчанию используется соглашение ccall вместо STDCALL.)
DLLEXPORT указывает имя соответствующей подпрограммы в таблице экспорта DLL. 
Выполним команду меню Build, Build BBtest.dll.
Это создает BBtest.dll в папке Debug или Release в папке проекта, указанной ранее (Debug или Release  в зависимости от соотв. установки в диалоге Build, Set Active Configuration...).
Скопируем DLL, например, в папку Блэкбокса (в этом случае не нужно указывать полный путь для этой DLL в интерфейсном модуле в Блэкбоксе).
Для проверки DLL из Блэкбокса скомпилируем и выполним пару модулей Epse21DllFortran и Epse21DllFortranTest (см. выше).
Fortran Power Station 4.0
Это более старая версия VF. Главный источник информации  документация FPS, раздел Mixed-Language Programming.
В FPS, создадим новое workspace класса Dynamic Link Library, назовем его BBtest, и создадим в нем единственный файл prog.f, в который скопируем вышеприведенный фортрановский код.
В начале файла добавим две мета-инструкции, под одной на каждую процедуру:
!MS$ATTRIBUTES STDCALL, REFERENCE, ALIAS:'proc1' :: proc1 
!MS$ATTRIBUTES STDCALL, REFERENCE, ALIAS:'proc2' :: proc2 
Каждая из них должна начинаться в первой позиции строки (в отличие от инструкций фортрана).
REFERENCE означает, что параметры должны передаваться по ссылке (что соответствует VAR в Блэкбоксе).
STDCALL означает, что при передаче параметров будет использоваться соглашение StdCall; важно использовать STDCALL, если DLL будет загружаться динамически.
Далее нужно обеспечить, чтобы две процедуры появились в списке экспорта DLL.
Для этого откроем меню Build, Settings ... и найдем закладку Link. 
В конце содержимого Project Options, добавим 
	 /export:"proc1" /export:"proc2"
как на следующей картинке:


(Если окно серое, это вероятно потому, что в левой части выделены обе строчки; должна быть только одна нужная.)
Нажмем OK.
Выполним команду меню Build, Build ... Это создаст BBtest.dll.
Скопируем созданную DLL, например, в папку Блэкбокса (тогда не нужно указывать ее полный путь в интерфейсном модуле в Блэкбоксе). Для проверки скомпилируем и выполним два модуля Блэкбокса, приведенные в начале документа.