C++在windows与linux下编译动态库

匿名 (未验证) 提交于 2019-12-02 21:56:30

一、.so与.dll比较

 

1、.so的单独编译链接

从网上找的一个例子:

头文件:so_test.h

三个.c文件:test_a.c test_b.c test_c.c

//so_test.h #include "stdio.h" void test_a(); void test_b(); void test_c();
//test_a.c #include "so_test.h" void test_a() {   printf("this is in test_a...\n"); }
//test_b.c #include "so_test.h" void test_a() {   printf("this is in test_a...\n"); }
//test_c.c #include "so_test.h" void test_c() {   printf("this is in test_c...\n"); }

打开命令行,编译动态库:libtest.so

gcc test_a.c test_b.c test_c.c -fPIC -shared -o libtest.so

 动态库的链接

//test.c #include "so_test.h" int main() { test_a(); test_b(); test_c(); return 0; }

将test.c与动态链接库libtest.so链接生成执行文件test:

gcc test.c -L. -ltest -o test

 执行test

./test

会报错,我们需要在Linux下将动态libtest.so导入到环境变量中

LIBRARY_PATH和LD_LIBRARY_PATH是Linux下的两个环境变量,二者的含义和作用分别如下:

LIBRARY_PATH环境变量用于在程序编译期间查找动态链接库时指定查找共享库的路径,例如,指定gcc编译需要用到的动态链接库的目录。设置方法如下(其中,LIBDIR1和LIBDIR2为两个库目录):

export LIBRARY_PATH=LIBDIR1:LIBDIR2:$LIBRARY_PATH

LD_LIBRARY_PATH环境变量用于在程序加载运行期间查找动态链接库时指定除了系统默认路径之外的其他路径,注意,LD_LIBRARY_PATH中指定的路径会在系统默认路径之前进行查找。设置方法如下(其中,LIBDIR1和LIBDIR2为两个库目录):

export LD_LIBRARY_PATH=LIBDIR1:LIBDIR2:$LD_LIBRARY_PATH

开发时,设置LIBRARY_PATH,以便gcc能够找到编译时需要的动态链接库。

发布时,设置LD_LIBRARY_PATH,以便程序加载运行时能够自动找到需要的动态链接库。

现在这样执行test

export LD_LIBRARY_PATH=/home/wuyadong/Exercise-so:$LD_LIBRARY_PATH ./test

2、.dll的单独编译链接

__declspec(dllexport):声明一个导出函数,是说这个函数要从本DLL导出。我要给别人用。一般用于dll中省掉在DEF文件中手工定义导出哪些函数的一个方法。当然,如果你的DLL里全是C++的类的话,你无法在DEF里指定导出的函数,只能用__declspec(dllexport)导出类。

__declspec(dllimport):声明一个导入函数,是说这个函数是从别的DLL导入。我要用。一般用于使用某个dll的exe中不使用__declspec(dllimport)也能正确编译代码,但使用__declspec(dllimport)使编译器可以生成更好的代码。编译器之所以能够生成更好的代码,是因为它可以确定函数是否存在于DLL中,这使得编译器可以生成跳过间接寻址级别的代码,而这些代码通常会出现在跨DLL边界的函数调用中。但是,必须使用__declspec(dllimport)才能导入DLL中使用的变量。

先看两个文件:

//dllexport.h #pragma once  #ifdef WIN32 #ifdef DLL_EXPORTS #define DLL_API __declspec(dllexport) #else #define DLL_API __declspec(dllimport) #endif // DLL_EXPORTS #else #define DLL_API __attribute__((visibility("default"))) #endif // WIN32

在VS工程目录的属性页中的预处理器定义中可以看到WIN32、DLL_API的宏定义。接着根据dllexport.h来定义一个头文件

//TypeDef.h #pragma once #include "dllexport.h"  #ifdef __cplusplus extern "C" { #endif  //导出结构体的声明 typedef DLL_API struct { 	float width; 	int count; 	long long* indexes;  }GridIndex;  //导出全局函数的声明 DLL_API void* GetProgenies(long long *index, unsigned long *generations); DLL_API void ReleaseLongLongArr(void *p); DLL_API void* GetNeighbors(long long index, int dimension);  extern DLL_API int a;//导出全局变量的声明  class DLL_API CMakeDLL {//导出类的声明  public: 	CMakeDLL(void); 	// TODO:  在此添加您的方法和变量。     int myIndex;  };  #ifdef __cplusplus } #endif 

注意:在上面的代码中类、变量、函数声明时前面所加持的DLL_API在定义时就不必加了。

extern “C”代码块中的内容按照C语言的编译方式进行编译。为什么要这样呢?因为c++中支持函数重载,而C语言不支持,c++对函数经过了其他处理,如果不加extern “C”限制按照C语言的方式编译,那么c++编译器在编译C语言函数时可能就会找不到链接路径而报错。

但是在大型工程下,跨平台编译一般使用CMake关于CMakeList的写法。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!