2009-01-30 2 views
135

Это последующая деятельность после Dynamic Shared Library compilation with g++.C++ Dynamic Shared Library on Linux

Я пытаюсь создать общую библиотеку классов в C++ в Linux. Я могу получить библиотеку для компиляции, и я могу вызвать некоторые из (неклассовых) функций, используя обучающие программы, которые я нашел here и here. Мои проблемы возникают, когда я пытаюсь использовать классы, определенные в библиотеке. Во втором учебном пособии, в котором я был связан, показано, как загрузить символы для создания объектов классов, определенных в библиотеке, но заканчивается с использованием этих объектов для выполнения любой работы.

Кто-нибудь знает более полное руководство по созданию общих библиотек классов C++, которое также показывает, как использует эти классы в отдельном исполняемом файле? Очень простой учебник, который показывает создание объекта, использование (простые геттеры и сеттеры будут в порядке), и удаление было бы фантастическим. Ссылка или ссылка на некоторый открытый исходный код, который иллюстрирует использование библиотеки общих классов, были бы одинаково хорошими.


Хотя ответы от codelogic и nimrodm работают, я просто хотел бы добавить, что я взял копию Beginning Linux Programming с тех пор, задавая этот вопрос, и его первая глава содержит код примера C и хорошие объяснения для создания и использования как статические, так и разделяемые библиотеки. Эти примеры доступны через Поиск книг Google в an older edition of that book.

+0

Я не уверен, что понимаю, что вы подразумеваете под «использованием», когда указатель на объект возвращается, вы можете использовать его, как если бы вы использовали любой другой указатель на объект. – codelogic

+0

В статье, на которой я ссылаюсь, показано, как создать указатель на функцию объекта с помощью dlsym. Он не показывает синтаксис для создания и использования объектов из библиотеки. –

+1

Вам понадобится файл заголовка, описывающий класс. Почему, по-вашему, вы должны использовать «dlsym» вместо того, чтобы позволить ОС находить и связывать библиотеку во время загрузки? Дайте мне знать, если вам нужен простой пример. – nimrodm

ответ

119

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. Ваше основное приложение не нужно будет каким-либо образом изменять.

+6

Я сейчас пытаюсь это сделать, но просто есть один вопрос. Строго ли необходимо использовать void *, или может ли функция create_object вернуть MyClass *? Я не прошу вас изменить это для меня, я просто хотел бы знать, есть ли причина использовать один над другим. –

+0

Это может быть MyClass *, без причины для него быть недействительным *, я обновил его. – codelogic

+1

Спасибо, я попробовал это, и он работал как на Linux из командной строки (как только я внес изменения, которые вы предложили в комментариях кода). Я ценю ваше время. –

48

В следующем примере показан пример общей библиотеки разделов. [H, cpp] и модуль main.cpp с использованием библиотеки. Это очень простой пример, и make-файл можно сделать намного лучше. Но это работает, и может помочь вам:

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: 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 или аналогичный).

Следующая указывает текущий каталог в качестве пути поиска библиотек и запускает основной (Баш синтаксис):

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) 
+1

Это выглядит (по моему очень неподготовленному глазу), чтобы статически связывать libshared.so с вашим исполняемым файлом, а не использовать динамическое связывание во время выполнения. Я прав? –

+9

Нет. Это стандартная динамическая компоновка Unix (Linux). Динамическая библиотека имеет расширение «.so» (общий объект) и связана с исполняемым файлом (главным в этом случае) во время загрузки - каждый раз, когда загружается основная страница. Статическое связывание происходит во время связи и использует библиотеки с расширением «.a» (архив). – nimrodm

+8

Это динамически связано с _build_ time. Другими словами, вам необходимо заранее знать библиотеку, с которой вы связываете (например, ссылку на 'dl' для dlopen). Это отличается от динамической _loading_ библиотеки, на основе, скажем, указанного пользователем имени файла, где предварительные знания не нужны. – codelogic

8

в принципе, вы должны включать в себя CLAS s 'в коде, в котором вы хотите использовать класс в общей библиотеке. Затем, когда вы связываете, use the '-l' flag, чтобы связать ваш код с общей библиотекой. Конечно, это требует, чтобы .so находилось там, где ОС может его найти.См. 3.5. Installing and Using a Shared Library

Использование dlsym для тех случаев, когда вы не знаете во время компиляции, какую библиотеку вы хотите использовать. Это звучит не так, как в данном случае. Может быть, путаница в том, что Windows вызывает динамически загружаемые библиотеки, выполняете ли вы компоновку при компиляции или во время выполнения (с аналогичными методами)? Если да, то вы можете думать о dlsym как эквивалент LoadLibrary.

Если вам действительно нужно динамически загружать библиотеки (т. Е. Они подключаемые модули), то this FAQ должен помочь.

+1

Причина, по которой мне нужна динамическая разделяемая библиотека, заключается в том, что я также буду называть ее кодом Perl. Это может быть полное заблуждение в моей собственной части, что мне также нужно назвать его динамически из других программ на C++, которые я разрабатываю. –

+0

Я никогда не пробовал интегрированные perl и C++, но я думаю, вам нужно использовать XS: http://www.johnkeiser.com/perl-xs-c++.html –

Смежные вопросы