Linux 静态链接库和动态连接库

(0)目录

VMware 下安装Ubuntu的吐血经历

零基础学习Shell编程

Linux下的makefile的妙用

Linux调试神器 -- gdb

十分钟学会Python的基本类型

Linux 静态链接库和动态连接库


一:静态链接库的应用  三步走~~~


##g++ -c StaticMath.cpp

##ar -crv libstaticmath.a StaticMath.o

##g++ -o run test_a.cpp -L. -lstaticmath

#[@sjs_37_33 lib_A_SO]# ./run
a + b = 12
a - b = 8
a * b = 20
a / b = 5
**********************
**********************
sh: pause: command not found
**********************

二:走的弯路~~~~

#[@sjs_37_33 lib_A_SO]# g++ -o run test_a.cpp  // 缺少依赖库文件
/tmp/ccx8rZph.o: In function `main':
test_a.cpp:(.text+0x39): undefined reference to `StaticMath::add(double, double)'
test_a.cpp:(.text+0x76): undefined reference to `StaticMath::sub(double, double)'
test_a.cpp:(.text+0xb3): undefined reference to `StaticMath::mul(double, double)'
test_a.cpp:(.text+0xf0): undefined reference to `StaticMath::div(double, double)'
test_a.cpp:(.text+0x12a): undefined reference to `StaticMath::StaticMath()'
test_a.cpp:(.text+0x136): undefined reference to `StaticMath::print()'
test_a.cpp:(.text+0x151): undefined reference to `StaticMath::~StaticMath()'
test_a.cpp:(.text+0x16d): undefined reference to `StaticMath::~StaticMath()'
collect2: ld ?μ?? 1

#[@sjs_37_33 lib_A_SO]# g++ -o run test_a.cpp -L. -lstaticmath // 缺少依赖库?非也,缺少实现函数即.cpp没有实现.h中的文件
/tmp/cczojb8v.o: In function `main':
test_a.cpp:(.text+0x12a): undefined reference to `StaticMath::StaticMath()'
test_a.cpp:(.text+0x151): undefined reference to `StaticMath::~StaticMath()'
test_a.cpp:(.text+0x16d): undefined reference to `StaticMath::~StaticMath()'
collect2: ld ·μ?? 1

三: 动态库的应用 两步走~~·

###  g++ -fPIC -shared -o libdynmath.so StaticMath.cpp  ---- 生成-o libdynmath.so 动态库


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

###g++ TestDynamicLibrary.cpp -L../DynamicLibrary -ldynmath
然后运行:./a.out,发现竟然报错了!!!

#[@sjs_37_33 lib_A_SO]# ./a.out 

./a.out: error while loading shared libraries: libdynmath.so: cannot open shared object file: No such file or directory

那么,在执行的时候是如何定位共享库文件的呢?
1)        当系统加载可执行代码时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统动态载入器(dynamic linker/loader)。
2)        对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的 DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib 目录找到库文件后将其载入内存。
如何让系统能够找到它:

 如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作;如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下:

编辑/etc/ld.so.conf文件,加入库文件所在目录的路径;运行ldconfig ,该命令会重建/etc/ld.so.cache文件;我们将创建的动态库复制到/usr/lib下面,然后运行测试程序,成功。


四:  Linux下库相关命令

##ldd libdynmath.so 
        linux-vdso.so.1 =>  (0x00007fffed837000)
        libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00007f48b0413000)
        libm.so.6 => /lib64/libm.so.6 (0x00007f48b018e000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f48aff78000)
        libc.so.6 => /lib64/libc.so.6 (0x00007f48afbe8000)

        /lib64/ld-linux-x86-64.so.2 (0x0000003da7800000)

g++(gcc)编译选项
  -shared :指定生成动态链接库。
  -static :指定生成静态链接库。
  -fPIC :表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码, 念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
  -L. :表示要连接的库所在的目录。
  -l:指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a/.so来确定库的名称。

  -Wall :生成所有警告信息。
  -ggdb :此选项将尽可能的生成gdb 的可以使用的调试信息。
  -g :编译器在编译的时候产生调试信息。
  -c :只激活预处理、编译和汇编,也就是把程序做成目标文件(.o文件) 。

  -Wl,options :把参数(options)传递给链接器ld 。如果options 中间有逗号,就将options分成多个选项,然后传递给链接程序。

nm命令
有时候可能需要查看一个库中到底有哪些函数,nm命令可以打印出库中的涉及到的所有符号。库既可以是静态的也可以是动态的。nm列出的符号有很多,常见的有三种:
  一种是在库中被调用,但并没有在库中定义(表明需要其他库支持),用U表示;
  一种是库中定义的函数,用T表示,这是最常见的;
  一种是所谓的弱态”符号,它们虽然在库中被定义,但是可能被其他库中的同名符号覆盖,用W表示。
$nm libhello.h

ldd命令

ldd命令可以查看一个可执行程序依赖的共享库,例如我们编写的四则运算动态库依赖下面这些库:


打开文件、保存、关闭文件(vi命令模式下使用) 

vi filename       //打开filename文件 
:w       //保存文件 
:w vpser.net //保存至vpser.net文件 
:q          //退出编辑器,如果文件已修改请使用下面的命令 
:q!        //退出编辑器,且不保存 
:wq         //退出编辑器,且保存文件


五:相关代码

h文件

#pragma once
class StaticMath
{
public:
    StaticMath(void);
    ~StaticMath(void);
 
    static double add(double a, double b);//加法
    static double sub(double a, double b);//减法
    static double mul(double a, double b);//乘法
    static double div(double a, double b);//除法
 
    void print();
};

cpp文件

#include "StaticMath.h"
#include <stdio.h> 

StaticMath::StaticMath(void)
{
    //
    print();
}

StaticMath::~StaticMath(void)
{
    //
    print();
}

double StaticMath::add(double a, double b)//加法
{
    return a + b;
}
double StaticMath::sub(double a, double b)//减法
{
    return a - b;
}   
    
double StaticMath::mul(double a, double b)//乘法
{
    return a * b;
}
double StaticMath::div(double a, double b)//除法
{
    if(0==b) 
        return -1;
    return a / b;
}

void StaticMath::print()
{
    printf("**********************\n");
}

测试文件

#include "StaticMath.h" // 测试静态库libstaticmath.a 和 动态库libdynmath.so

#include <iostream>
#include <stdlib.h>
using namespace std;
 
int main(int argc, char* argv[])
{
    double a = 10;
    double b = 2;
 
    cout << "a + b = " << StaticMath::add(a, b) << endl;
    cout << "a - b = " << StaticMath::sub(a, b) << endl;
    cout << "a * b = " << StaticMath::mul(a, b) << endl;
    cout << "a / b = " << StaticMath::div(a, b) << endl;
 
    StaticMath sm;
    sm.print();
 
    system("pause");
    return 0;
}

六:总结

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。动态库就是在需要调用其中的函数时,根据函数映射表找到该函数然后调入堆栈执行。如果在当前工程中有多处对dll文件中同一个函数的调用,那么执行时,这个函数只会留下一份拷贝。但是如果有多处对lib文件中同一个函数的调用,那么执行时,该函数将在当前程序的执行空间里留下多份拷贝,而且是一处调用就产生一份拷贝。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值