С++ Dynamic Shared Library на Linux
Это продолжение компиляции динамической общей библиотеки с g++.
Я пытаюсь создать общую библиотеку классов в С++ в Linux. Я могу получить библиотеку для компиляции, и я могу вызвать некоторые из (неклассовых) функций, используя обучающие программы, которые я нашел здесь и здесь. Мои проблемы возникают, когда я пытаюсь использовать классы, определенные в библиотеке. Во втором учебном пособии, в котором я был связан, показано, как загружать символы для создания объектов классов, определенных в библиотеке, но не удается использовать эти объекты для выполнения любой работы.
Кто-нибудь знает более полное руководство по созданию общих библиотек классов С++, которое также показывает, как использовать эти классы в отдельном исполняемом файле? Очень простой учебник, который показывает создание объекта, использование (простые геттеры и сеттеры будут в порядке), и удаление было бы фантастическим. Ссылка или ссылка на некоторый открытый исходный код, который иллюстрирует использование библиотеки общих классов, были бы одинаково хорошими.
Хотя ответы codelogic и nimrodm работают, я просто хотел добавить, что я взял копию Начало программирования Linux, начиная с вопроса, и в первой главе содержится пример кода на C и полезные пояснения для создания и использования как статических, так и разделяемых библиотек, Эти примеры доступны через Поиск книг Google в более старом выпуске этой книги.
Ответы
Ответ 1
myclass.h
#ifndef __MYCLASS_H__
#define __MYCLASS_H__
class MyClass
{
public:
MyClass();
/* use virtual otherwise linker will try to perform static linkage */
virtual void DoSomething();
private:
int x;
};
#endif
myclass.cc
#include "myclass.h"
#include <iostream>
using namespace std;
extern "C" MyClass* create_object()
{
return new MyClass;
}
extern "C" void destroy_object( MyClass* object )
{
delete object;
}
MyClass::MyClass()
{
x = 20;
}
void MyClass::DoSomething()
{
cout<<x<<endl;
}
class_user.cc
#include <dlfcn.h>
#include <iostream>
#include "myclass.h"
using namespace std;
int main(int argc, char **argv)
{
/* on Linux, use "./myclass.so" */
void* handle = dlopen("myclass.so", RTLD_LAZY);
MyClass* (*create)();
void (*destroy)(MyClass*);
create = (MyClass* (*)())dlsym(handle, "create_object");
destroy = (void (*)(MyClass*))dlsym(handle, "destroy_object");
MyClass* myClass = (MyClass*)create();
myClass->DoSomething();
destroy( myClass );
}
В Mac OS X скомпилируйте с помощью:
g++ -dynamiclib -flat_namespace myclass.cc -o myclass.so
g++ class_user.cc -o class_user
В Linux, скомпилируйте с помощью:
g++ -fPIC -shared myclass.cc -o myclass.so
g++ class_user.cc -ldl -o class_user
Если бы это было для плагиновой системы, вы бы использовали MyClass в качестве базового класса и определяли все необходимые функции виртуальными. Тогда автор плагина получал бы из MyClass, переопределял бы виртуальные машины и реализовал бы create_object
и destroy_object
. Ваше основное приложение не нужно каким-либо образом изменять.
Ответ 2
Ниже представлен пример общей библиотеки разделов. [h, cpp] и модуль main.cpp с использованием библиотеки. Это очень простой пример, и makefile можно сделать намного лучше. Но он работает и может вам помочь:
shared.h определяет класс:
class myclass {
int myx;
public:
myclass() { myx=0; }
void setx(int newx);
int getx();
};
shared.cpp определяет функции getx/setx:
#include "shared.h"
void myclass::setx(int newx) { myx = newx; }
int myclass::getx() { return myx; }
main.cpp использует класс,
#include <iostream>
#include "shared.h"
using namespace std;
int main(int argc, char *argv[])
{
myclass m;
cout << m.getx() << endl;
m.setx(10);
cout << m.getx() << endl;
}
и makefile, который генерирует libshared.so и ссылки main с общей библиотекой:
main: libshared.so main.o
$(CXX) -o main main.o -L. -lshared
libshared.so: shared.cpp
$(CXX) -fPIC -c shared.cpp -o shared.o
$(CXX) -shared -Wl,-soname,libshared.so -o libshared.so shared.o
clean:
$rm *.o *.so
Для реального запуска 'main' и ссылки с libshared.so вам, вероятно, потребуется указать путь загрузки (или поместить его в /usr/local/lib или аналогичный).
Далее указан текущий каталог в качестве пути поиска для библиотек и выполняется главный (bash синтаксис):
export LD_LIBRARY_PATH=.
./main
Чтобы увидеть, что программа связана с libshared.so, вы можете попробовать ldd:
LD_LIBRARY_PATH=. ldd main
Печать на моей машине:
~/prj/test/shared$ LD_LIBRARY_PATH=. ldd main
linux-gate.so.1 => (0xb7f88000)
libshared.so => ./libshared.so (0xb7f85000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e74000)
libm.so.6 => /lib/libm.so.6 (0xb7e4e000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0xb7e41000)
libc.so.6 => /lib/libc.so.6 (0xb7cfa000)
/lib/ld-linux.so.2 (0xb7f89000)
Ответ 3
В принципе, вы должны включить заголовочный файл класса в код, в котором вы хотите использовать класс в общей библиотеке. Затем, когда вы связываете, используйте флаг -l, чтобы связать ваш код с общей библиотекой. Конечно, это требует, чтобы .so находилось там, где ОС может его найти. См. 3.5. Установка и использование общей библиотеки
Использование dlsym - это когда вы не знаете во время компиляции, какую библиотеку вы хотите использовать. Это звучит не так. Может быть, путаница в том, что Windows вызывает динамически загружаемые библиотеки, выполняете ли вы компоновку при компиляции или во время выполнения (с аналогичными методами)? Если да, то вы можете думать о dlsym как эквивалент LoadLibrary.
Если вам действительно нужно динамически загружать библиотеки (то есть, они являются плагинами), то этот FAQ должен помочь.