Содержание

Динамическая загрузка библиотек

На данной странице описаны некоторые технологии (приемы программирования), которые используются в текущем проекте.

Под динамической загрузкой разделяемой библиотеки понимается загрузка исполняемого кода, находящегося в библиотеке, во время выполнения программы. Данный подход позволяет компилировать функции на языке Fortran в отдельные разделяемые библиотеки и затем вызывать их из языка C++.

Типы данных

Fortran имеет… FIXME

Разница в передаче аргументов

Fortran передает аргументы в подпрограммы по ссылке (т.е по имени). C++ передает данные по значению.

DLL and Shared library

Явная привязка (загрузка) библиотек в Windows может быть выполнена с помощью WinAPI-функций

На Linux или Solaris явное связывание может быть сделано с помощью POSIX-функций

Загрузка Fortran-библиотеки

Исходный код библиотеки общий для Windows и Unix.

ex1.f
C     ex1.f  -  FORTRAN file for example 1
      FUNCTION FOO2(X) RESULT (R)
      !DEC$ ATTRIBUTES DLLEXPORT, ALIAS:'FOO2'::FOO2
      REAL  X
      REAL :: R
      R = X * 2
      END FUNCTION
 
      SUBROUTINE FOO
      !DEC$ ATTRIBUTES DLLEXPORT, ALIAS:'FOO'::FOO
 
      REAL :: R
 
      R = 20
      print *,"R=",R
      END SUBROUTINE

Загрузка динамической Fortran-библиотеки в Windows

Средствами Visual Studio 2008 (2005) и Intel Fortran Visual Studio Integration создаем динамическую библиотеку Проект VS 2008.

ex1win.cpp
// ex1win.cpp  -  Test file for passing a single real 
// argument to a F77 function in a dll
#include <iostream>
#include <windows.h>
 
typedef void (*SUBROUTINE)(void);
SUBROUTINE  FOO;
 
typedef float (* FUNCTION)(float&);
FUNCTION FOO2 = NULL;
 
int main()
{
    HINSTANCE hDll = LoadLibrary("ex1.dll");
	if(hDll==NULL)
	{
		printf("Error load dll!");
		return 1;
	}
 
       FOO = (SUBROUTINE)GetProcAddress(hDll, "FOO"); //ВНИМАНИЕ! Экспортируемые функции могут содеражть символ "_" в конце т.е foo_
    	if(FOO==NULL)
	{
		printf("Error load function!");
		return 1;
	}
 
	FOO();
 
	FOO2 = (FUNCTION)GetProcAddress(hDll, "FOO2"); //ВНИМАНИЕ! Экспортируемые функции могут содеражть символ "_" в конце т.е foo_
    	if(FOO==NULL)
	{
		printf("Error load function!");
		return 1;
	}
	float x = 1.2f;
    float y = 0.0f;
    y = FOO2(x);
    std::cout << "y = FOO2(" << x << ") = " 
              << y << std::endl;
    FreeLibrary(hDll);
    return 0;
}

Загрузка разделяемой Fortran-библиотеки в Unix

Для компиляции Fortran-части используется компилятор GFortran, C++-части — GCC.

Ключи компиляторов:

gfortran
gfortran -shared -fPic ex1.f -o ex1.so
gcc
gcc -o ex1lnx ex1lnx.cpp -ldl
// ex1lnx.cpp  -  Test file
// real argument to a F77 function in a dll
#include <iostream>
#include <dlfcn.h>
 
typedef void (*SUBROUTINE)(void);
SUBROUTINE FOO = NULL;
 
typedef float (*FUNCTION)(float&);
FUNCTION FOO2 = NULL;
 
int main()
{
    void *hDll = dlopen("./ex1.so", RTLD_NOW);
    if(hDll == NULL)
	{
	std::cout << "Error load library!";
       	return 1;
	}
 
    FOO = (SUBROUTINE)dlsym(hDll, "foo_");
    if(FOO == NULL)
    {
      std::cout << "Error load subroutine!";
      return 1;
    }
 
    FOO2 = (FUNCTION)dlsym(hDll,"foo2_");
    if(FOO2 == NULL)
    {
      std::cout << "Error load function!";
      return 1;
    }
 
    FOO();
 
    float x = 1.2f;
    float y = 0.0f;
    y = FOO2(x);
    std::cout << "y = foo(" << x << ") = " 
              << y << std::endl;
    dlclose(hDll);
    return 0;
}

Динамическая загрузка C++-библиотеки

Загрузка динамической C++-библиотеки в Windows

hello.cpp
//hello.cpp:
#include <iostream>
 
extern "C" void hello() {
    std::cout << "hello" << '\n';
}
main.cpp
//main.cpp
#include <windows.h>
#include <iostream>

Загрузка разделяемой C++-библиотеки в Unix

hello.cpp
//hello.cpp:
#include <iostream>
 
extern "C" void hello() {
    std::cout << "hello" << '\n';
}
main.cpp
//main.cpp:
#include <iostream>
#include <dlfcn.h>
 
int main() {
    using std::cout;
    using std::cerr;
    cout << "C++ dlopen demo\n\n";
    // open the library
    cout << "Opening hello.so...\n";
    void* handle = dlopen("./hello.so", RTLD_LAZY);
 
    if (!handle) {
        cerr << "Cannot open library: " << dlerror() << '\n';
        return 1;
    }
    // load the symbol
    cout << "Loading symbol hello...\n";
    typedef void (*hello_t)();
    // reset errors
    dlerror();
    hello_t hello = (hello_t) dlsym(handle, "hello");
    const char *dlsym_error = dlerror();
    if (dlsym_error) {
        cerr << "Cannot load symbol 'hello': " << dlsym_error <<
            '\n';
        dlclose(handle);
        return 1;
    }
       // use it to do the calculation
    cout << "Calling hello...\n";
    hello(); 
    // close the library
    cout << "Closing library...\n";
    dlclose(handle);
}

Ключи линковщика:

g++
g++ -shared -o hello.so hello.cpp
g++ -o main main.cpp -ldl