这是使用g ++进行动态共享库编译的后续内容.
我正在尝试在Linux上用C++创建一个共享类库.我能够编译库,我可以使用我在这里和这里找到的教程调用一些(非类)函数.当我尝试使用库中定义的类时,我的问题开始了.我链接的第二个教程展示了如何加载符号来创建库中定义的类的对象,但是没有使用这些对象来完成任何工作.
Does anyone know of a more complete tutorial for creating shared C++ class libraries that also shows how to use those classes in a separate executable? A very simple tutorial that shows object creation, use (simple getters and setters would be fine), and deletion would be fantastic. A link or a reference to some open source code that illustrates the use of a shared class library would be equally good.
虽然codelogic和nimrodm的答案确实有效,但我只是想补充一下,自从提出这个问题以来,我选择了初学Linux编程的副本,其第一章有示例C代码以及创建和使用静态和共享库的良好解释.这些示例可通过旧书版本中的 Google图书搜索获得.
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" #includeusing 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< class_user.cc
#include#include #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
.您的主应用程序无需以任何方式进行更改.
我正在尝试这个,但只有一个问题.是否必须使用void*,或者create_object函数是否可以返回MyClass*?我不是要求你为我改变这个,我只是想知道是否有理由使用一个而不是另一个.
@ ant2009你需要`extern"C"`因为`dlsym`函数是一个C函数.并且要动态加载`create_object`函数,它将使用C风格的链接.如果您不使用`extern"C"`,则无法知道.so文件中`create_object`函数的名称,因为C++编译器中存在名称错位.
2> nimrodm..:下面显示了共享的共享类库的示例.[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#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; } 以及生成libshared.so和链接main与共享库的makefile:
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或类似).
以下指定当前目录作为库的搜索路径并运行main(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)
我试图解释(严重)的是,在这种情况下,您需要在构建时知道库的名称(您需要将-lshared传递给gcc).通常,当信息不可用时,使用dlopen(),即在运行时发现库的名称(例如:插件枚举).
不.这是标准的Unix(Linux)动态链接.动态库具有扩展名".so"(共享对象),并在加载时与可执行文件(在本例中为main)链接 - 每次加载main时.静态链接在链接时发生,并使用扩展名为".a"(存档)的库.
这是在_build_时动态链接的.换句话说,您需要事先知道您要链接的库(例如,与dlopen的'dl'链接).这与动态_loading_库不同,基于用户指定的文件名,不需要先验知识.
使用`-L。-lshared -Wl,-rpath = $$(ORIGIN)在链接并删除该LD_LIBRARY_PATH =时。
3> Matt Lewis..:基本上,您应该在要在共享库中使用该类的代码中包含类的头文件.然后,在链接时,使用'-l'标志将代码链接到共享库.当然,这要求.so是操作系统可以找到它的地方.见3.5.安装和使用共享库
使用dlsym是为了在编译时不知道要使用哪个库.这听起来不像是这样的情况.也许混淆是Windows调用动态加载的库,无论你是在编译还是运行时进行链接(使用类似的方法)?如果是这样,那么你可以认为dlsym相当于LoadLibrary.
如果你真的需要动态加载库(即它们是插件),那么这个FAQ应该有所帮助.