动态库和静态库的概念、生成及使用
-
优势:由于可执行文件中记录的是功能模块的地址,真正的实现代码会在程序运行时被载入内存,这意味着,即便功能模块被调用多次,使用的都是同一份实现代码(这也是将动态链接库称为共享链接库的原因)。
-
劣势:此方式生成的可执行文件无法独立运行,必须借助相应的库文件(可移植性差)。
-
优势:生成的可执行文件不再需要任何静态库文件的支持就可以独立运行(可移植性强);
-
劣势:如果程序文件中多次调用库中的同一功能模块,则该模块代码势必就会被复制多次,生成的可执行文件中会包含多段完全相同的代码,造成代码的冗余。和使用动态链接库生成的可执行文件相比,静态链接库生成的可执行文件的体积更大。
静态库中的lib:该LIB包含函数代码本身(即包括函数的索引,也包括实现),在编译时直接将代码加入程序当中。
动态库中的lib:该LIB包含了函数所在的DLL文件和文件中函数位置的信息(索引),函数实现代码由运行时加载在进程空间中的DLL提供。
下面在VS2017下测试动态库、静态库的生成和使用
(1)生成和使用动态库
①生成动态库
VS2017新建项目后,点击项目-属性-常规,将配置类型改为动态库,如图所示:
新建dlltest.h和dlltest.cpp文件,导出一个类,实现加减法,如图所示:
然后点击生成-重新生成解决方案,最后在工程Debug目录下会生成一个dll文件和一个lib文件,如图所示:
②使用动态库
有两种方法调用动态库,一种隐式链接,一种显示链接,这里只讲隐式链接。
VS2017新建工程,将生成动态库的.h文件、.dll文件和.lib文件放到工程目录下(lib文件可以不加到工程目录下,可以设置项目属性-VC++目录--库目录为lib所在的路径,再将lib添加到项目属性--链接器--输入--附加依赖项(或者直接在源代码中加入#pragma comment(lib, “**.lib”))),如图所示:
包含.h文件,编写使用代码,并重新生成项目,如图所示:
表明动态库使用成功。
需要注意的是,工程目录下,lib文件和dll文件二者都不能少,如果少了lib文件,那么编译时会报错,如果少了dll文件,那么运行时会报错,如图所示:
(2)生成和使用静态库
①生成静态库
生成静态库的方法和动态库类似,VS2017新建项目后,点击项目-属性-常规,将配置类型改为静态库,再新建libtest.h和libtest.cpp文件,不同的是,头文件类名前不需要加
__declspec(dllexport),如图所示:
然后点击生成-重新生成解决方案,最后在工程Debug目录下会生成一个lib文件,如图所示:
②使用静态库
与使用动态库类似,在项目的资源文件里加入.lib文件(或将lib路径添加到库文件),包含.h文件,编写使用代码,并重新生成项目,同样可以运行成功。
1 #ifndef _TEST_H_ 2 #define _TEST_H_ 3 4 5 class Test 6 { 7 public: 8 int add(int a, int b); 9 int sub(int a, int b); 10 }; 11 12 #endif
test.cpp:
1 #include "test.h" 2 3 int Test::add(int a, int b) 4 { 5 return a + b; 6 } 7 8 int Test::sub(int a, int b) 9 { 10 return a - b; 11 }
然后将test.cpp封装成动态库,步骤如下:
1)生成.o文件。g++ -c -fpic test.cpp
2)封装成自己的动态库(注意动态链接库的不能随意起名,需遵循如下的命名规则:libxxx.so)。
g++ -shared test.o -o libmymath.so
#include<iostream> #include"test.h" using namespace std; int main() { Test t; cout << t.add(3, 4) << endl; cout << t.sub(7, 2) << endl; }
- 将链接库文件移动到标准库目录下(例如 /usr/lib、/usr/lib64、/lib、/lib64);
- 在终端输入
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
,其中 xxx 为动态链接库文件的绝对存储路径(此方式仅在当前终端有效,关闭终端后无效); - 修改~/.bashrc 或~/.bash_profile 文件,即在文件最后一行添加
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
(xxx 为动态库文件的绝对存储路径)。保存之后,执行source .bashrc
指令(此方式仅对当前登陆用户有效)
与生成动态库类似,将test.cpp封装成动态库,步骤如下:
1)生成.o文件。g++ -c test.cpp
2)打包封装成自己的静态库(注意静态链接库的不能随意起名,需遵循如下的命名规则:libxxx.a)。
ar rcs libmymath.a test.o