Linux学习(六):静态库和动态库

在Windows中安装好的软件目录下会看到一大堆以lib,dll后缀的文件。而且有时候玩游戏或者运行软件的时候经常会遇到无法运行,因为缺少×××.dll,而这些就是软件运行需要的库,也就是源码编译后的文件。

 

一、程序中的库是什么

本质上说库是一种可执行的二进制文件,可以直接被操作系统载入内存执行。

二、库的种类

库有两种:静态库和动态库。Windows平台下的静态库以“.lib”为后缀名,动态库以“.dll”为结尾。Linux平台下的静态库以“.a”结尾,动态库以“.so”为结尾。

三、静态和动态库的不同

程序从源码到变成可执行程序需要经过四个过程:预编译,编译,汇编,链接。而静态和动态的主要区别在于最后的链接部分。

四、静态库的创建和使用

静态库的命名规则:名字分为三部分:前缀lib+库名字+后缀.a      (注意:库的名字一般为小写)

为了方便,我们新建一个数学类:StaticMath.h 和 StaticMath.cpp

//StaticMath.h
#pragma once

class StaticMath
{
public:

    StaticMath(void);
    ~StaticMath(void); 

    static double add(double a, double b);

    void print();
};
//StaticMath.cpp
#include"StaticMath.h"
#include<iostream>
#include<stdlib.h>

using namespace std;


StaticMath::StaticMath()
{
    cout<< "StaticMath(void) has been called"<<endl;
}
StaticMath::~StaticMath()
{
    cout<<"~StaticMath(void) has been called"<<endl;
}

double StaticMath::add(double a, double b)
{
    double c = a + b;
    return c;
}

void StaticMath::print()
{
    cout<<"print function has been called!"<<endl;
}

静态库的创建:

首先,将代码文件编译成目标文件.o(StaticMath.o)

  • -static指定生成静态链接库(也可以省略);
g++ -static -c StaticMath.cpp

然后,通过ar工具将目标文件打包成.a静态库文件

ar -crv libstaticmath.a StaticMath.o

此时就生成了静态库libstaticmath.a

然后在写一个main.cpp的测试调用文件:

//main.cpp
#include"StaticMath.h"
#include<iostream>

using namespace std;

int main(int argc, char* argv[])
{
    double a = 10;
    double b = 20;

    cout<<"a + b = "<<StaticMath::add(a,b)<<endl;

    StaticMath sm;
    sm.print();

    system("pause");
    return 0;
}

调用命令大致分为三部分:编译器 命令 参数

g++ -o main main.cpp -L../StaticLibraryDir -l staticmath 
  • -L后面加的参数是静态库的存放文件夹,因为是当前目录,所以使用”.“代替"./StaticLibraryDir"即可;
  • -l后面加的参数是静态库的名字(去掉前缀后的名字)。

最后生成的main程序,在当前目录下使用以下命令即可调用:

./main

五、动态库的创建和使用

为了方便,我们新建一个数学类:DynamicMath.h 和 DynamicMath.cpp

//DynamicMath.h
#pragma once

class DynamicMath
{
    public:
        DynamicMath(void);
        ~DynamicMath(void);

        static double add(double a, double b);
        void print();
};
//DynamicMath.cpp
#include"DynamicMath.h"
#include<iostream>

using namespace std;


DynamicMath::DynamicMath()
{
    cout<< "DynamicMath(void) has been called"<<endl;
}
DynamicMath::~DynamicMath()
{
    cout<<"~DynamicMath(void) has been called"<<endl;
}

double DynamicMath::add(double a, double b)
{
    double c = a + b;
    return c;
}

void DynamicMath::print()
{
    cout<<"print function has been called!"<<endl;
}

动态库和静态库的不同在于,在于添加命令的时候需要加上-fPIC。-fPIC (位置无关代码Position-Independent Code)的使用,会生成 PIC 代码,.so 要求为 PIC,以达到动态链接的目的,否则,无法实现动态链接。

首先,生成目标文件,此时要加编译器选项-fPIC

g++ -fPIC -c DynamicMath.cpp

然后,生成动态库,此时要加链接器选项-shared

g++ -o libdynamicmath.so -shared DynamicMath.o

这样就生成了动态库,将main.cpp修改一下测试:

//main.cpp
#include"DynamicMath.h"
#include<iostream>
#include<stdlib.h>

using namespace std;

int main(int argc, char* argv[])
{
    double a = 10;
    double b = 20;

    cout<<"a + b ="<<DynamicMath::add(a,b)<<endl;

    DynamicMath Dm;
    Dm.print();

    system("pause");
    return 0;
}

引用动态库编译成可执行文件(跟静态库方式一样):

g++ -o main main.cpp -L../DynamicLibraryDir -l dynamicmath
  • -L后面加的参数是静态库的存放文件夹,因为是当前目录,所以使用”.“代替"./DynamicLibraryDir"即可;
  • -l后面加的参数是静态库的名字(去掉前缀后的名字)。

但是运行此时生成的main不并能成功!因为系统无法定位到这个动态库,而不是程序发现不了。

方法一:(系统级)

将生成的.so文件拷贝到系统/usr/lib或者/lib文件夹下,再运行即可。

方法二:(临时办法)

在运行main前指定运行的库的路径为当前路径

LD_LIBRARY_PATH=. ./main

方法三:(makefile)

这个属于方法二的延伸,为的就是使其自动化一些,在makefile中加入后,就不用每次运行都写前缀了:

main.out: main.cpp DynamicMath.so
    g++ main.cpp -L . -l dynamicmath
    LD_LIBRARY_PATH=. ./main.out

运行结果就是:

六、静态库和动态库的区别

最要的区别在于资源的利用上:

但是理论上的区别有很多:

1、二者的不同点在于代码被载入的时刻不同。静态库在程序编译过程中会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。动态库在程序编译过程中并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小

2、静态库属于完整意义上的封装。动态库并不算完整意义上的封装,更侧重于共享

七、在Linux下显式调用动态库

#include <dlfcn.h>,提供了下面几个接口:

  • void * dlopen( const char * pathname, int mode ):函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。
  • void* dlsym(void* handle,const char* symbol):dlsym根据动态链接库操作句柄(pHandle)与符号(symbol),返回符号对应的地址。使用这个函数不但可以获取函数地址,也可以获取变量地址。
  • int dlclose (void *handle):dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。
  • const char *dlerror(void):当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值