Linux使用静态库和动态库

Linux使用静态库和动态库

(一)库的概念

库是可以复用的代码,在一些大的项目中常常会用到库。

本质上说:库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

一般说库是说两种:

静态库:linux下.a文件、windows下.lib文件

动态库:linux下.so文件、windows下.dll文件

最近花了一些时间把linux下编译、链接等研究了一下,作为一个菜鸟记录并分享一蛤。


(二)静态库与动态库

程序的编译运行要经过以下步骤:

1.源文件(.h .cpp等)

2.预编译

3.编译

4.汇编(.o文件)

5.链接

6.运行

在上述过程中,静态库是在链接阶段,将汇编生成的目标文件.o与引用到的库一起打包到可执行文件中,此种链接方式被称为静态链接。静态库其实一组目标文件(.o/.obj)的集合,即很多目标文件经过压缩打包后形成的一个文件,有一个说法称为:Archive即归档合并到一起。静态库在链接过程中被一起打包到可执行文件中,因此程序在运行时与函数库再无瓜葛,移植起来就很方便,但也因为这个原因会浪费空间资源,因为所有相关的目标文件与牵涉到的函数库都会被链接成一个可执行文件,如果10个100个可执行文件使用同一个静态库,就会造成大大的浪费;并且由于静态库是需要链接进入应用程序的,因此一旦对静态库进行修改,就需要对整个程序重新编译。

与静态库不同,动态库不会被链接打包到目标代码中,而是在程序运行时才被载入。这样就解决了静态库浪费空间的缺点,动态库把对一些库函数的链接载入推迟到程序运行的时期,在内存中只存在一份拷贝,这样可以实现进程之间的资源共享。

在linux和windows下静态库和动态库的概念以及使用方法有所不同,之后会慢慢学习分享。


(三)Linux下使用静态库

首先知道一个概念,也就是.h头文件,静态库.a文件的关系:

.h头文件是编译时必须的,声明函数接口,编译时通过引用.h文件找到函数声明。

.a文件是linux下静态库文件的后缀,通常以libxxxx.a的形式出现,在链接时必不可少。

下面编写一个简单的四则运算库:

首先是声明部分:

//StaticMath.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文件实现上述接口声明:

//StaticMath.cpp
#include "StaticMath.h"
double StaticMath::add(double a,double b)
{
    return a+b;
}

由于静态库是目标文件的集合,那么我们现在需要对上述文件进行预编译->编译->汇编步骤,生成对应的.o文件,通过g++ --help命令知道参数-c的描述是:

因此执行命令:

g++ -c StaticMath.cpp

将代码文件编译汇编成目标文件StaticMath.o

然后,使用ar工具将目标文件打包成.a形式的静态库文件,这里的ar实际上可以理解为Archive的简写:

ar -crv libstaticmath.a StaticMath.o

如此生成静态库文件libstaticmath.a。

PS:在以前做过的嵌入式项目里面,静态库的生成和使用大多通过一些自动化工具例如autogen、cmake等,一直没有搞懂其真正的原理,这下也算学习了一蛤。

最后编写测试代码使用静态库

//test.cpp
#include <iostream>
#include "StaticMath.h"
int main()
{
    double a=1.2;
    double b=2.4;
    std::cout << "a+b="<<StaticMath::add(a,b)<<std::endl;
    return 0;
}

因为在链接的过程中要使用静态库,这里编译的时候需要加入静态库所在目录和静态库的名字来作为编译选项,否则会出现问题:

g++ -o test test.cpp -L ./ -lstaticmath

最后可执行文件test正常执行:


(四)Linux下使用动态库

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。

同样的首先编写库文件。

声明:

//DynamicMath.h
#pragma once
class DynamicMath
{
    public:
    DynamicMath();
    ~DynamicMath();

    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);
};

实现:

//DynamicMath.cpp
#include "DynamicMath.h"
double DynamicMath::add(double a,double b)
{
    return a+b;
}

生成动态库libxxxx.so

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

-fPIC 创建与地址无关的编译程序(pic,position independent code),是为了能够在多个应用程序间共享。

-shared指定生成动态链接库。

使用动态库,测试代码:

//test.cpp
#include <iostream>
#include "DynamicMath.h"
int main()
{
    double a=1.2;
    double b=2.4;
    std::cout << "a+b =" << DynamicMath::add(a,b)<<std::endl;
    return 0;
}

跟静态库使用类似,编译测试文件并加上合适的编译选项,生成可执行文件,并且通过ldd命令查看应用程序依赖的动态库及其相关信息:

最后动态库的使用有一个需要注意的地方:

动态库是在运行时加载,这时候需要一个动态载入器(dynamic linker/loader),来得知动态库的绝对路径。

对于elf格式的可执行程序,是由ld-linux.so*来完成的,它先后搜索elf文件的 DT_RPATH段—环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib 目录找到库文件后将其载入内存。

什么意思呢?就是首先有一堆配置文件可以配置动态载入库搜索动态库的路径,ld会在这些路径中去寻找依赖的动态库,这样就有两个解决办法:

1. 修改配置文件(/etc/ld.so.conf)添加我们创建的动态库的目录

2. 将我们创建的动态库(.so)拷贝到默认的动态库目录下/lib或者/usr/lib

关于上述第1点,我们可以这样做,在终端

添加动态库目录
 echo /home/zhangxiao/learnlib/dynamiclib/ >> /etc/ld.so.conf
配置生效
ldconfig

关于上述第2点,直接将生成动态库拷贝到/usr/lib目录下即可。

参考:

http://www.cnblogs.com/skynet/p/3372855.html

http://blog.csdn.net/yusiguyuan/article/details/12649737

时间: 2024-10-27 17:13:40

Linux使用静态库和动态库的相关文章

linux上静态库和动态库的编译和使用(附外部符号错误浅谈)

主要参考博客gcc创建和使用静态库和动态库 对于熟悉windows的同学,linux上的静态库.a相当于win的.lib,动态库.so相当于win的.dll. 首先简要地解释下这两种函数库的区别,参考<Linux程序设计> 1. 静态库也被称为归档文件(archive,因此创建命令是ar),编译器和链接器负责将程序代码和静态库结合在一起组成单独的可执行文件: 但是缺点是许多应用程序同时运行并使用来自同一个静态库的函数时,内存中就会有一个函数的多份副本,而且程序文件自身也有多份同样的副本,这将消

Linux下Gcc生成和使用静态库和动态库详解

参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主要是编译器.汇编器和连接器的不同),因此二者库的二进制是不兼容的. 本文仅限于介绍linux下的库. 1.2库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同

linux学习 建立静态库,动态库,写简单的makefile

建立静态库 建立四个文件 bin(可执行文件),lib(库),include(头文件),src(放源文件) 这里的起的库明为add 在src文件中执行 1)gcc -c add.c //编译add.c源文件生成add.o目标文件 2)ar crsv ../lib/ libadd.a add.o //对目标文件*.o进行归档,生成lib*.a, 把这个生成文件放在lib里 3)gcc -o main main.c -L(大些的爱偶,放库的路径)../lib   –l(小写的爱偶,库名为add) a

【转】Linux下gcc生成和使用静态库和动态库详解

一.基本概念 1.1 什么是库 在Windows平台和Linux平台下都大量存在着库. 本质上来说,库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同(主要是编译器.汇编器和连接器的不同),因此二者的库的二进制是不兼容的. 本文仅限于介绍linux下的库. 1.2 库的种类 linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同. 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大. 共享库的代码是在可

Linux 如何生成静态库和动态库

1.引言 1.linux下的库 静态库和共享库(动态库),二者的不同点在于代码被载入的时刻不同. 静态库的代码在编译过程中已经被载入可执行程序,因此体积较大. 共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小. 2.库存在的意义 库是别人写好的现有的,成熟的,可以复用的代码,你可以使用但要记得遵守许可协议. 现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 共享库的好处是,不同的应用程序如果调用相同的库,那么

Linux学习笔记7——linux中的静态库和动态库

一.静态库的编译 静态库的编译过程如下: 1.编译成目标文件 这里有一个可选项-static,调用格式:gcc -c -static 代码文件名.c 2.归档成静态库 A.归档的工具是ar工具,使用ar -r可以将文件归档成静态库,调用格式:ar -r 静态库文件 被归档的文件 例如:我们这有两个C文件,分别为test1.c和test2.c 首先我们将它编译成目标文件:gcc -c -static test1.c gcc -c -static test2.c 此时会产生两个文件,分别为test1

linux成长之路(gcc编译器、静态库、动态库)

Jeremy Lin GCC简介 GCC(GNU Complier Collection)是GNU推出的功能强大.性能优越的多平台编译器套件,它包括了C.C++.Objective-C.Fortran.Java.Ada和Go语言的前端,也包括了这些语言的库,当前最新的版本是GCC 5.1.GCC可以在多种硬件平台上编译出可执行程序,其执行效率与一般的编译器相比平均效率要高20%-30%.GCC编译器能将C.C++语言源程序.汇程式程序和目标程序编译.连接成可执行文件,如果没有给出可执行文件的名字

g++编译使用生成静态库和动态库(Linux)

参考文献: Linux下g++编译与使用静态库和动态库 用g++编译生成动态链接库*.so的方法及连接(多个.cc生成一个*.so) 占坑

(笔记)Linux下的静态库和动态库使用详解

库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 一.静态库和动态库的区别 1. 静态函数库 这类库的名字一般是libxxx.a:利用静态函数库编译成的文件比较大,因为整个 函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了.当 然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译. 2. 动态函数库 这类库的名字一般是libxxx.so;相对于