Записки программиста
Авторский блог Михаила Лукина

Мой блог

Это Ваш персональный сетевой дневник.


ОБЛАКО ТЕГОВ:


.NET .NET Compact Framework 0xc8000222 Android Android SDK autorun C# C++ CUDA DOM error find JDK Gamedev Linux lock-free алгоритмы OpenCL ostringstream Unity vector Vusual Studio Windows Windows 7 XML XmlDocument массивы обновления обновления Windows Отключение autorun ошибка 0xc8000222 Параллельное программирование

Все теги


« Как преобразовать строку в шестнадцатеричное число int64  | В начало |  Суффиксы и префиксы у констант C++ »


Динамические библиотеки под Windows и Linux

22.02.12 11:42

Сегодня будем писать кросс-платформенную динамическую библиотеку (DLL).


Заведем заголовочный файл, в котором будут макросы для экспортирования функций в библиотеку в зависимости от платформы.


Файл export.h:


#ifndef _EXPORT_H

#define _EXPORT_H


#if defined (_MSC_VER)

#ifdef __cplusplus

#define LIB_EXPORT extern "C" __declspec(dllexport)

#else

#define LIB_EXPORT __declspec(dllexport)

#endif

#elif defined (__GNUC__)

#ifdef __cplusplus

#define LIB_EXPORT extern "C" __attribute__((visibility("default")))

#else

#define LIB_EXPORT __attribute__((visibility("default")))

#endif

#else

#warning Unknown dynamic link semantics

#ifdef __cplusplus

#define LIB_EXPORT extern "C" 

#else

#define LIB_EXPORT 

#endif

#endif


#endif



Теперь создадим саму библиотеку. Покажем, как делать экспорт функций и классов.


Файл export_functions.h:


#ifndef EXPORT_FUNCTIONS_H

#define EXPORT_FUNCTIONS_H


#include "export.h"


LIB_EXPORT int export_function(int x);


class EClass

{

public:

virtual void func() =0;

};


class EClassImpl : public EClass

{

public:

virtual void func();

};


LIB_EXPORT EClass *GetEClass();

LIB_EXPORT void DeleteEClass(EClass *a);


#endif


Файл export_functions.cpp:

#include <iostream>


#include "export_functions.h"


using namespace std;


int export_function(int x)

{

cout << "DLL function! parameter: " << x << endl;

return x;

}


EClass *GetEClass()

{

return new EClassImpl;

}


void DeleteEClass(EClass *a)

{

delete a;

}


void EClassImpl::func()

{

cout << "Class function from DLL!" << endl;

}


Положим все эти файлы в папку SharedLibrary.



Для сборки под Linux при помощи GCC можно использовать следующий Makefile:

libshared:

g++ -fPIC -Wall -g -c export_functions.cpp

g++ -shared -Wl,-soname, -o libshared.so export_functions.o -lc



clean: 

rm -f *.o libshared.so 


Файл libshared.so требуется либо положить в стандартное место для библиотек, либо перед использованием изменять переменную LD_LIBRARY_PATH.


Для сборки в Visual Studio под Windows требуется создать проект типа Win32 Console application и указать, что это DLL.


Теперь создадим пользователя этой библиотеки. Первый вариант: У нас есть заголовочный файл и мы будем линковаться с ней при сборке.


Файл StaticUser.cpp:


#include <iostream>


#include "../SharedLibrary/export_functions.h"


int main(int argc, char **argv)

{

export_function(5);


EClass *a = GetEClass();

a->func();

DeleteEClass(a);

return 0;

}


Makefile для сборки под Linux:

StaticUser: 

g++ -Wall -g -c StaticUser.cpp 

g++ -g -o StaticUser StaticUser.o -L../SharedLibrary -lshared 



Для сборки в Visual Studio под Windows в зависимостях проект (Project dependencies) требуется поставить проект SharedLibrary.


Второй вариант: У нас нет заголовочного файла, и мы будем загружать библиотеку самостоятельно.


В Windows загрузка DLL осуществляется при помощи функции LoadLibrary. Если загрузка DLL произошла удачно, возвращается переменная типа HINSTANCE (В VisualStudio этот тип определен как void *). В противном случае возвращается 0. Чтобы понять, какая произошла ошибка, вызываем функцию GetLastError. Коды ошибок в Windows можно посмотреть тут


Пользователь библиотеки будет состоять из одного файла LibraryUser.cpp:

#include <iostream>

#include <Windows.h>


using namespace std;


typedef int (*export_function_t) (int);

export_function_t export_function;


int main(int argc, char **argv)

{

DWORD err;

LPCSTR path = (LPCSTR)"SharedLibrary.dll";


if (GetFileAttributesA(path) == -1) //file does not exist.

{

cout << "Library not found ):" << endl;

}


HINSTANCE hDLL = LoadLibraryA(path);


if (hDLL)

{

cout << "Library loaded!" << endl;


export_function = reinterpret_cast<export_function_t> (GetProcAddress(hDLL, "export_function"));

if (!export_function)

{

cout << "Function not loaded ):" << endl;

return 1;

}


cout << "Function export_function loaded!" << endl;

int x = export_function(5);

cout << "Function returned " << x << endl;

}

else

{

err = GetLastError();

cout << "Error in load library: " << err << endl;

}

return 0;

}


Под Linux загрузка библиотеки осуществляется функцией dlopen.

Линуксовый пользователь библиотеки будет состоять из файла lu.cpp:

#include <iostream>

#include <dlfcn.h>

#include <link.h>


#include "../SharedLibrary/export_functions.h"


using namespace std;


int main(int argc, char ** argv)

{

void *handle = dlopen("/lib/libshared.so", RTLD_LAZY);


if (!handle)

{

cerr << "Couldn't load library ):" << endl;

return 1;

}


EClass * (*GetEClass)();

void * (DeleteEClass)(EClass *);


GetEClass = (EClass* (*)())dlsym(handle, "GetEClass");


EClass *a = (EClass *) GetEClass();

a->func();


return 0;

}


Собирается файл строкой g++ -o lu -ldl lu.cpp. Ключ -ldl подключает библиотеку, в которой находятся dlopen и другие функции для работы с динамическими библиотеками.





Рубрики: C++ Windows Linux

« Как преобразовать строку в шестнадцатеричное число int64  | В начало |  Суффиксы и префиксы у констант C++ »



© 2010-2014. Записки программиста. Все права защищены.
Яндекс.Метрика
ВебСтолица.РУ: создай свой бесплатный сайт!  | Пожаловаться  
Движок: Amiro CMS