На данной странице описаны некоторые технологии (приемы программирования), которые используются в текущем проекте.
Под динамической загрузкой разделяемой библиотеки понимается загрузка исполняемого кода, находящегося в библиотеке, во время выполнения программы. Данный подход позволяет компилировать функции на языке Fortran в отдельные разделяемые библиотеки и затем вызывать их из языка C++.
Fortran имеет…
Fortran передает аргументы в подпрограммы по ссылке (т.е по имени). C++ передает данные по значению.
Явная привязка (загрузка) библиотек в Windows может быть выполнена с помощью WinAPI-функций
На Linux или Solaris явное связывание может быть сделано с помощью POSIX-функций
Исходный код библиотеки общий для Windows и Unix.
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
Средствами Visual Studio 2008 (2005) и Intel Fortran Visual Studio Integration создаем динамическую библиотеку Проект VS 2008.
// 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-части используется компилятор GFortran, C++-части — GCC.
Ключи компиляторов:
gfortran -shared -fPic ex1.f -o ex1.so
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; }
//hello.cpp: #include <iostream> extern "C" void hello() { std::cout << "hello" << '\n'; }
//main.cpp #include <windows.h> #include <iostream>
//hello.cpp: #include <iostream> extern "C" void hello() { std::cout << "hello" << '\n'; }
//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++ -shared -o hello.so hello.cpp g++ -o main main.cpp -ldl