动态库和静态库的概念、生成及使用

1.动态库和静态库简介
(1)动态库和静态库的概念 
    在C\C++中,头文件只存储变量、函数或者类等功能模块的声明部分,库文件才负责存储各模块具体的实现部分。 
    C\C++ 程序从源代码生成可执行程序,会经历四个过程,分别是预处理(Preprocessing)、编译(Compilation)、汇编(Assembly)和链接(Linking)。
    库文件用于程序的链接阶段,一般来说编译器提供有2种实现链接的方式,分别为动态链接方式和静态链接方式,其中采用动态链接方式实现链接操作的库文件,称为动态链接库(动态库);采用静态链接方式实现链接操作的库文件,称为静态链接库(静态库)。在日常开发中,静态库是编译时需要的,而动态库是运行时需要的
 
    动态库:该库的内容不会进入可执行程序中,而是将功能模块的位置信息记录到文件中,直接生成可执行文件,这样可执行文件无法独立运行。
    静态库:在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中,会生成静态库。
 
    在Windows中,动态库通常以.dll和.lib作为后缀,静态库通常以.lib作为后缀;在Linux中,动态库通常以.so作为后缀,静态库通常以.a作为后缀。
 
(2)动态库和静态库的优缺点
    动态库:
  • 优势:由于可执行文件中记录的是功能模块的地址,真正的实现代码会在程序运行时被载入内存,这意味着,即便功能模块被调用多次,使用的都是同一份实现代码(这也是将动态链接库称为共享链接库的原因)。
  • 劣势:此方式生成的可执行文件无法独立运行,必须借助相应的库文件(可移植性差)。
    静态库:
  • 优势:生成的可执行文件不再需要任何静态库文件的支持就可以独立运行(可移植性强);
  • 劣势:如果程序文件中多次调用库中的同一功能模块,则该模块代码势必就会被复制多次,生成的可执行文件中会包含多段完全相同的代码,造成代码的冗余。和使用动态链接库生成的可执行文件相比,静态链接库生成的可执行文件的体积更大。
    
2.Windows下的动态库和静态库
    在Windows下,在vs中新建生成静态库的工程,编译生成成功后,只产生一个.lib文件,新建生成动态库的工程,编译成功后,产生一个.lib文件和一个.dll文件。

    静态库中的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文件,编写使用代码,并重新生成项目,同样可以运行成功。

 

 

 

3.Linux下的动态库和静态库
    在Linux下,使用GCC编译器生成动态库和静态库
(1)生成和使用动态库
①生成动态库
    在Linux下新建test.h、test.cpp文件,如下所示:
     test.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

②使用动态库
    动态链接库的使用场景就是和项目中其它源文件或目标文件一起参与链接(通过执行ldd指令,可以查看当前可执行文件在执行时需要用到的所有动态链接库)。
    新建一个main.cpp,来使用该动态库,如下所示:
#include<iostream>
#include"test.h"

using namespace std;

int main()
{
    Test t;
    cout << t.add(3, 4) << endl;
    cout << t.sub(7, 2) << endl;
}
    使用命令为:g++ main.cpp libmymath.so(也可以先生成main.o文件再使用)
    这时会生成可执行文件a.out,执行即可运行处结果。
 
    注意:
    与Windows类似,运行由动态链接库生成的可执行文件时,必须确保程序在运行时可以找到这个动态链接库。如果找不到,常用的解决方案有如下几种:
  • 将链接库文件移动到标准库目录下(例如 /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指令(此方式仅对当前登陆用户有效)
 
(2)生成和使用静态库
①生成静态库

    与生成动态库类似,将test.cpp封装成动态库,步骤如下:

    1)生成.o文件。g++ -c test.cpp

    2)打包封装成自己的静态库(注意静态链接库的不能随意起名,需遵循如下的命名规则:libxxx.a)。

        ar rcs libmymath.a test.o

②使用静态库
    对于main.cpp文件,使用命令为:g++ main.cpp -static libmymath.a(也可以先生成main.o文件再使用)
    这时会生成可执行文件a.out,执行即可运行处结果。
 
 
 
参考文章:
 
 
posted @ 2021-03-17 16:28  烟消00云散  阅读(2044)  评论(0编辑  收藏  举报