从开始学C语言写第一个"hello world"历程到现在,我依然困惑于到底这个程序完整的执行流程是什么样的。不过,现在我正在尝试一点一点的揭开它的面纱。现在,我尝试分析linux中C语言静态库和动态库生成和调用的方法,这可以算作实现最终愿望的一小步。
    首先说明的是,本文参考于linux 静态库、共享库,这篇文章写的的确不错。笔者结合自己的学习过程,稍作修改。
一、什么是库
  
 本质上说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。由于windows和linux本质的不同,因此二者的二进制库是不兼容的。linux操作系统支持的函数库可分为静态库和动态库,动态库又称为共享库。linux系统有几个重要的目录存放着相应的函数库,如/lib、/usr/lib。

二、静态库和动态库

A.静态库

    这类库的名字一般是libxxx.a,利用静态库编译生成的可执行文件比较大,因为整个函数库的所有数据都被整合进了可执行文件中。
    它的优点就是程序执行时不需要外部的函数库支持,它的装载速度要比动态库快。它的缺点因为它的优点而产生,静态库升级后,那么你的程序就必须重新编译。当多个应用程序都用到相同的库中,执行这些程序时,会把静态库重复调入内存,而造成内存的浪费。

B.动态库

     这类库的名字一般是libxxx.so,动态库又称共享库。相对于静态函数库,动态函数库在编译的时候没有被编译进可执行文件中,所以动态函数看所生成的可执行文件比较小。程序执行过程中,需要动态申请并调用相应的库才能运行,所以程序的运行环境中必须提供相应的库。
    它的优点是多个应用程序可以使用一个共享的动态库,启动多个应用程序的时候,只需要动态库加载到内存一次即可,自然比较节省内存。它的缺点是启动加载时候速度比较慢。

三、函数库的创建

实验的所有文件及内容如下:

add.c
#include "heads.h"
int add(int a,int b)
{
        return a+b;
} sub.c
#include "heads.h"
int sub(int a,int b)
{
        return a-b;
} heads.h
#ifndef _HEADS_H_
#define _HEADS_H_
extern int add(int,int);
extern int sub(int,int);
#endif test.c
#include <stdio.h>
#include "heads.h"
int main()
{
        int a=5,b=6;
        printf("a+b=%d\n",add(a,b));
        printf("a-b=%d\n",sub(a,b));
        return 0;
}

注意:不管是静态库还是动态库,原材料都是目标文件(*.o),所以先将源文件做成目标文件。

A.静态库的创建

ar -cr libaddsub.a add.o sub.o

ar       静态函数库创建命令
    -c   不管库是否存在,都将创建
    -r    在库中插入模块

B.动态库的创建

gcc -shared -pic -o libaddsub.so add.o sub.o

-shared    生成共享库
-pic         产生位置无关代码

四、函数库的使用

A.静态库的使用

gcc test.c -static -L. -laddsub -o test1 

static    使用静态库连接

-llibrary 用lib和.a把library包裹起来,并且在系统的标准搜索目录和L指定的目录中搜素该库文件

-Ldir       在l选项搜素目录中添加dir目录


可以看到程序编译通过并可以执行

    当删除了静态库文件libaddsub.a,发现程序依然能够执行,也就是说使用静态库连接生成的程序执行时不依赖于静态库

B.动态库的使用

gcc test.c -L. -laddsub -o test2

通过这个命令可以看见仅仅是去掉了static选项。这种情况,gcc优选选择连接动态库,当没有合适动态库的动态库连接时才连接静态库。下边的实验做之前,在/work目录下已经生成了动态库libaddsub.so。


    可以看到生成的test2明显比test1小很多,即证明了动态库连接可以使可执行文件比较小

    但是,直接运行却提示找不到库,这是因为动态库libaddsub.so所在目录/work并没有添加到执行时搜索动态库的目录中去。

五、动态库的运行

(1) 第一种解决的办法是使用环境变量LD_LIBRARY_PATH,这个环境变量就可以指定执行时搜索动态库的目录,这里把/work目录添加进去。

(2)把动态库libaddsub.so拷贝到/lib或者/usr/lib中去,这种办法将在第七部分实验

(3)修改配置文件

#cd /etc/ld.so.conf.d  进入配置文件夹

#vi mylib.conf   建立一个配置文件*.conf,这里以mylib.conf为例,并添加动态库所在目录,这里是/work

#ldconfig         使配置生效,实际上是更新ld.so.cache文件

实验过程及结果如下:

再查看test2所有依赖的动态库

可以看到,test2依赖的动态库有三个,包含libaddsub.o和两个系统标准的动态库。可执行文件test2的大小为12037Bytes。

当删除动态库libaddsub.so后,再来运行test2,不能执行,说明动态库在运行过程中还需要动态库libaddsub.so。

六、查看库

nm 可以打印出动态库或者静态库中涉及到的所有符号

ldd 可以查看一个可执行程序依赖的共享库

七、连接和运行选项

A.将静态库libaddsub.a移动到系统标准库目录中测试编译

编译可以通过,执行也可以通过,说明系统标准库目录中的静态库可以被连接。另外,注意这时的test1大小是423629Bytes

将static去掉重现编译,发现test1大小变成了11817Bytes,莫非此时libaddsub.a是被动态连接上的?

但是,将libaddsub.a删除之后,重新运行test1,仍然可以执行,可以得知libaddsub.a是被静态连接的。查看,test1的构造,可以看到它依赖于两个标准动态库。说明,没有static连接器选项时,默认找的是动态库,但是没有动态库时就连接静态库。

test1中libaddsub.a是被动态连接,而另外两个标准库是被动态连接的。

B.用类似的方法分析动态库

   

可以看到系统标准库目录中的动态库可以被连接,而且在执行时可以被搜索到。

从第五部分可以知道,使用环境变量LD_LIBRARY_PATH可以指定执行时搜索动态库的目录,那么它是否能指定连接器的搜索目录呢?

从上边的实验,可以看出环境变量LD_LIBRARY_PATH不能指定连接器的搜索目录。

参考博客:linux 静态库、共享库

静态链接与动态链接的区别

Linux 共享库: LD_LIBRARY_PATH 与ld.so.conf

linux中C的静态库和动态库分析的更多相关文章

  1. 在Linux中创建静态库和动态库

    我们通常把一些公用函数制作成函数库,供其它程序使用. 函数库分为静态库和动态库两种. 静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库. 动态库在程序编译时并不会被连接到目标代码中 ...

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

    一.静态库的编译 静态库的编译过程如下: 1.编译成目标文件 这里有一个可选项-static,调用格式:gcc -c -static 代码文件名.c 2.归档成静态库 A.归档的工具是ar工具,使用a ...

  3. 在Linux中创建静态库和动态库 (转)

    我们通常把一些公用函数制作成函数库,供其它程序使用.函数库分为静态库和动态库两种.静态 库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库.动态库在程序编译时并不会被连接到目标代码中,而 ...

  4. Linux中的静态库与动态库

    什么是库文件? 库文件是事先编译好的方法的合集.比如:我们提前写好一些数据公式的实现,将其打包成库文件,以后使用只需要库文件就可以,不需要重新编写. Linux系统中: 1.静态库的扩展名为.a:2. ...

  5. linux中创建静态库和动态库

    1. 函数库有两种:静态库和动态库. 静态库在程序编译的时候会被连接到目标代码中,程序运行时将不再需要改静态库. 动态库中程序编译的时候并不会连接到目标代码中,而是在程序运行时才被载入,因此在程序运行 ...

  6. Linux下Gcc生成和使用静态库和动态库详解(转)

    一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行. 由于windows和linux的平台不同( ...

  7. 在Linux下如何使用GCC编译程序、简单生成 静态库及动态库

      最近在编写的一个Apache  kafka 的C/C++客户端,,在看他写的 example中,他的编译是用librdkafka++.a和librdkafka.a    静态库编译的,,,而我们这 ...

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

    参考文章:http://blog.chinaunix.net/uid-23592843-id-223539.html 一.基本概念 1.1什么是库 在windows平台和linux平台下都大量存在着库 ...

  9. C语言中静态库和动态库笔记

    库 库,故名思议,是存放东西的地方,其中存放的东西可以被多个人公用. 程序中借用库的概念,描述将代码进行抽取,这种代码被大多数程序使用, 其过程具有一定的模块化.封装.抽象的特征. 按照库的使用方式, ...

随机推荐

  1. C++实现建立和一二进制树的三个递归遍历

    说明:这篇文章是学习交流,转载请注明出处,欢迎转载! 二叉树是一种常见的数据结构.二叉树的遍历也是家常便饭的事了,这里仅仅写出一个完整的能够执行的C++代码来随便建立一个例如以下图所看到的的二叉树,建 ...

  2. Centos下的IO监控与分析

        近期要在公司内部做个Linux IO方面的培训, 整理下手头的资料给大家分享下 各种IO监视工具在Linux IO 体系结构中的位置 源自 Linux Performance and Tuni ...

  3. asp.net下载的方法1

    1. 首先新建一个用于进行下载处理的page页,如download.aspx,里面什么东西也没有. 2. 添加一个DownloadHandler类,它继承于IHttpHandler接口,可以用来自定义 ...

  4. extjs6整合到web项目中

    最近有一个项目需要应用extjs作为前端界面,因此研究了一下如何将extjs 6引入到项目中.以下是操作步骤 extjs6下载地址 extjs 6有gpl版本的,下载地址https://www.sen ...

  5. 清除Eclipse和Myeclipse中的工作空间目录

    打开Eclipse或者Myeclipse后,选择功能菜单里的Windows->Preferences->, 弹出对话框后,选择General->Startup and Shutdow ...

  6. Android开发环境搭建(2015年8月更新)

    1.  下载和安装Android SDK Android的官方站点是http://www.android.com: 登录https://developer.android.com/intl/zh-cn ...

  7. java新手笔记17 参数

    package com.yfs.javase; public class ParamDemo { public static void main(String[] args) { int a = 3, ...

  8. Java中ArrayList类详解

    1.什么是ArrayList ArrayList就是传说中的动态数组,用MSDN中的说法,就是Array的复杂版本,它提供了如下一些好处: 动态的增加和减少元素 实现了ICollection和ILis ...

  9. SGU 260.Puzzle (异或高斯消元)

    题意: 有n(<200)个格子,只有黑白两种颜色.可以通过操作一个格子改变它和其它一些格子的颜色.给出改变的关系和n个格子的初始颜色,输出一种操作方案使所有格子的颜色相同. Solution: ...

  10. gcc命令以及makefile文件

    (一)makefile里涉及到的gcc命令 gcc -I./inc:指定头文件寻找目录 将按照 ./inc --> /usr/include --> /usr/local/include的 ...