3静态库

摘自:Linux C编程一站式学习

透过本节可以学会编译静态链接库的shell脚本!

有时候需要把一组代码编译成一个库,这个库在很多项目中都要用到,例如libc就是这样一个库,我们在不同的程序中都会用到libc中的库函数(例如printf),也会用到libc中的变量(例如以后要讲到的environ变量)。本节介绍怎么创建这样一个库。

我们继续用stack.c的例子。为了便于理解,我们把stack.c拆成四个程序文件(虽然实际上没太大必要),把main.c改得简单一些,头文件stack.h不变,本节用到的代码如下所示:

/* stack.c */
char stack[512];
int top = -1;
/* push.c */
extern char stack[512];
extern int top; void push(char c)
{
stack[++top] = c;
}
/* pop.c */
extern char stack[512];
extern int top; char pop(void)
{
return stack[top--];
}
/* is_empty.c */
extern int top; int is_empty(void)
{
return top == -1;
}
/* stack.h */
#ifndef STACK_H
#define STACK_H
extern void push(char);
extern char pop(void);
extern int is_empty(void);
#endif
/* main.c */
#include <stdio.h>
#include "stack.h" int main(void)
{
push('a');
return 0;
}

这些文件的目录结构是:

$ tree
.
|-- main.c
`-- stack
|-- is_empty.c
|-- pop.c
|-- push.c
|-- stack.c
`-- stack.h 1 directory, 6 files

我们把stack.cpush.cpop.cis_empty.c编译成目标文件:

$ gcc -c stack/stack.c stack/push.c stack/pop.c stack/is_empty.c

然后打包成一个静态库libstack.a

$ ar rs libstack.a stack.o push.o pop.o is_empty.o
ar: creating libstack.a

库文件名都是以lib开头的,静态库以.a作为后缀,表示Archive。ar命令类似于tar命令,起一个打包的作用,但是把目标文件打包成静态库只能用ar命令而不能用tar命令。选项r表示将后面的文件列表添加到文件包,如果文件包不存在就创建它,如果文件包中已有同名文件就替换成新的。s是专用于生成静态库的,表示为静态库创建索引,这个索引被链接器使用。ranlib命令也可以为静态库创建索引,以上命令等价于:

$ ar r libstack.a stack.o push.o pop.o is_empty.o
$ ranlib libstack.a

然后我们把libstack.amain.c编译链接在一起:

$ gcc main.c -L. -lstack -Istack -o main

-L选项告诉编译器去哪里找需要的库文件,-L.表示在当前目录找。-lstack告诉编译器要链接libstack库,-I选项告诉编译器去哪里找头文件。注意,即使库文件就在当前目录,编译器默认也不会去找的,所以-L.选项不能少。编译器默认会找的目录可以用-print-search-dirs选项查看:

$ gcc -print-search-dirs
install: /usr/lib/gcc/i486-linux-gnu/4.3.2/
programs: =/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/:/usr/libexec/gcc/i486-linux-gnu/4.3.2/:/usr/libexec/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../i486-linux-gnu/bin/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../i486-linux-gnu/bin/
libraries: =/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../i486-linux-gnu/lib/i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../i486-linux-gnu/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../i486-linux-gnu/4.3.2/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../lib/:/lib/i486-linux-gnu/4.3.2/:/lib/../lib/:/usr/lib/i486-linux-gnu/4.3.2/:/usr/lib/../lib/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../../i486-linux-gnu/lib/:/usr/lib/gcc/i486-linux-gnu/4.3.2/../../../:/lib/:/usr/lib/

其中的libraries就是库文件的搜索路径列表,各路径之间用:号隔开。编译器会在这些搜索路径以及-L选项指定的路径中查找用-l选项指定的库,比如-lstack,编译器会首先找有没有共享库libstack.so,如果有就链接它,如果没有就找有没有静态库libstack.a,如果有就链接它。所以编译器是优先考虑共享库的,如果希望编译器只链接静态库,可以指定-static选项。

那么链接共享库和链接静态库有什么区别呢?在第 2 节 “main函数和启动例程”讲过,在链接libc共享库时只是指定了动态链接器和该程序所需要的库文件,并没有真的做链接,可执行文件main中调用的libc库函数仍然是未定义符号,要在运行时做动态链接。而在链接静态库时,链接器会把静态库中的目标文件取出来和可执行文件真正链接在一起。我们通过反汇编看上一步生成的可执行文件main

$ objdump -d main
...
08048394 <main>:
8048394: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048398: 83 e4 f0 and $0xfffffff0,%esp
804839b: ff 71 fc pushl -0x4(%ecx)
...
080483c0 <push>:
80483c0: 55 push %ebp
80483c1: 89 e5 mov %esp,%ebp
80483c3: 83 ec 04 sub $0x4,%esp

有意思的是,main.c只调用了push这一个函数,所以链接生成的可执行文件中也只有push而没有popis_empty。这是使用静态库的一个好处,链接器可以从静态库中只取出需要的部分来做链接。如果是直接把那些目标文件和main.c编译链接在一起:

$ gcc main.c stack.o push.o pop.o is_empty.o -Istack -o main

则没有用到的函数也会链接进来。当然另一个好处就是使用静态库只需写一个库文件名,而不需要写一长串目标文件名。

linux c 链接详解3-静态库的更多相关文章

  1. linux c 链接详解4-共享库

    4. 共享库 4.1. 编译.链接.运行 组成共享库的目标文件和一般的目标文件有所不同,在编译时要加-fPIC选项,例如: $ gcc -c -fPIC stack/stack.c stack/pus ...

  2. 详解UE4静态库与动态库的导入与使用

    转自:http://blog.csdn.net/u012999985/article/details/71554628 一.基本内容概述   最近做项目时经常看到build.cs文件,就想研究一下UE ...

  3. linux ln链接详解

    1.序 Linux具有为一个文件起多个名字的功能,称为链接.被链接的文件可以存放在相同的目录下,但是必须有不同的文件名,而不用在硬盘上为同样的数据重复备份.另外,被链接的文件也可以有相同的文件名,但是 ...

  4. linux c 链接详解5-虚拟内存管理

    5. 虚拟内存管理 我们知道操作系统利用体系结构提供的VA到PA的转换机制实现虚拟内存管理.有了共享库的基础知识之后,现在我们可以进一步理解虚拟内存管理了.首先分析一个例子: $ ps PID TTY ...

  5. linux c 链接详解1-多目标文件链接

    1. 多目标文件的链接 摘自:linux c编程一站式学习 http://learn.akae.cn/media/index.html 可以学会在linux下将多个c语言文件一起编译. 现在我们把例  ...

  6. linux c 链接详解2-定义和声明

    2定义和声明 摘自:linux c编程一站式学习 可以学会extern和static用法,头文件知识. 2.1. extern和static关键字 在上一节我们把两个程序文件放在一起编译链接,main ...

  7. Linux 软硬链接详解

    软链接 软链接: 类似于windows的快捷方式,—>文本文件,但是包含了真实文件的地址               源文件删除,则软连接也删除               软链接可以放在任何文 ...

  8. Linux 链接详解----静态链接实例分析

    由Linux链接详解(1)中我们简单的分析了静态库的引用解析和重定位的内容, 下面我们结合实例来看一下静态链接重定位过程. /* * a.c */ ; void add(int c); int mai ...

  9. GCC 指令详解及动态库、静态库的使用

    GCC 指令详解及动态库.静态库的使用 一.GCC 1.1 GCC 介绍 GCC 是 Linux 下的编译工具集,是「GNU Compiler Collection」的缩写,包含 gcc.g++ 等编 ...

随机推荐

  1. 获取<a>标签值</a>的标签值及更改

    html代码: <a id="catelogue_div1_h5" onclick="catelogue_div1(event)">隐藏</a ...

  2. PLSQL导出表的数据insert语句

    “Where clause”可以设置查询条件.设置好文件导出的路径(“Output file”),点击[Export]按钮,就可以导出INSERT语句了. 导出之后使用nodepad打开: 但是如果我 ...

  3. [pipenv]Warning: Python 3.7 was not found on your system…

    前置条件: 切换到pipfile文件所在目录gotest_official 问题描述: 使用pipenv install创建虚拟环境,报错 wangju@wangju-HP--G4:~/Desktop ...

  4. 【MAC】安装chrome浏览器

    step1:下载dmg安装包 chrome下载地址 点击[下载Chrome] step2:安装chrome 下载好googlechrome.dmg文件后,像其它程序一样安装就可以了 打开访达--> ...

  5. Unity3D 打包成Exe文件

    Unity发布后一般都会一个exe文件和_data文件以及UnityPlayer.dll,如果把这三个文件整合成一个exe就可以(装逼)了 首先打开Winrar将这三个压缩: 压缩文件名设置为需要启动 ...

  6. apache虚拟目录配置实例

    apache虚拟目录配置实例 一.首先,开启虚拟主机配置 在文件httpd.conf中找到: include conf/extra/httpd-vhosts.conf #开启 二.对httpd-vho ...

  7. IDEA工具创建项目并提交码云和一些基本使用

    https://blog.csdn.net/autfish/article/details/52513465https://blog.csdn.net/zsyoung/article/details/ ...

  8. 转载 STM32 使用Cubemx 建一个USB(HID)设备下位机,实现数据收发

    STM32 使用Cubemx 建一个USB(HID)设备下位机,实现数据收发  本文转载自 https://www.cnblogs.com/xingboy/p/9913963.html 这里我主要说一 ...

  9. JS获取表单元素的value

    <!-- 1.option selected属性,如果我们在下拉列表里面选择了一个option那么他的selected="true" ,如果我们想设置当前的option是选中 ...

  10. 一张图包含SEO一切要点

    看到一张好图 from http://www.rongyipiao.com/?p=8