linux c 链接详解3-静态库
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.c、push.c、pop.c、is_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.a和main.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而没有pop和is_empty。这是使用静态库的一个好处,链接器可以从静态库中只取出需要的部分来做链接。如果是直接把那些目标文件和main.c编译链接在一起:
$ gcc main.c stack.o push.o pop.o is_empty.o -Istack -o main
则没有用到的函数也会链接进来。当然另一个好处就是使用静态库只需写一个库文件名,而不需要写一长串目标文件名。
linux c 链接详解3-静态库的更多相关文章
- linux c 链接详解4-共享库
4. 共享库 4.1. 编译.链接.运行 组成共享库的目标文件和一般的目标文件有所不同,在编译时要加-fPIC选项,例如: $ gcc -c -fPIC stack/stack.c stack/pus ...
- 详解UE4静态库与动态库的导入与使用
转自:http://blog.csdn.net/u012999985/article/details/71554628 一.基本内容概述 最近做项目时经常看到build.cs文件,就想研究一下UE ...
- linux ln链接详解
1.序 Linux具有为一个文件起多个名字的功能,称为链接.被链接的文件可以存放在相同的目录下,但是必须有不同的文件名,而不用在硬盘上为同样的数据重复备份.另外,被链接的文件也可以有相同的文件名,但是 ...
- linux c 链接详解5-虚拟内存管理
5. 虚拟内存管理 我们知道操作系统利用体系结构提供的VA到PA的转换机制实现虚拟内存管理.有了共享库的基础知识之后,现在我们可以进一步理解虚拟内存管理了.首先分析一个例子: $ ps PID TTY ...
- linux c 链接详解1-多目标文件链接
1. 多目标文件的链接 摘自:linux c编程一站式学习 http://learn.akae.cn/media/index.html 可以学会在linux下将多个c语言文件一起编译. 现在我们把例 ...
- linux c 链接详解2-定义和声明
2定义和声明 摘自:linux c编程一站式学习 可以学会extern和static用法,头文件知识. 2.1. extern和static关键字 在上一节我们把两个程序文件放在一起编译链接,main ...
- Linux 软硬链接详解
软链接 软链接: 类似于windows的快捷方式,—>文本文件,但是包含了真实文件的地址 源文件删除,则软连接也删除 软链接可以放在任何文 ...
- Linux 链接详解----静态链接实例分析
由Linux链接详解(1)中我们简单的分析了静态库的引用解析和重定位的内容, 下面我们结合实例来看一下静态链接重定位过程. /* * a.c */ ; void add(int c); int mai ...
- GCC 指令详解及动态库、静态库的使用
GCC 指令详解及动态库.静态库的使用 一.GCC 1.1 GCC 介绍 GCC 是 Linux 下的编译工具集,是「GNU Compiler Collection」的缩写,包含 gcc.g++ 等编 ...
随机推荐
- 【python】windows更改jupyter notebook(ipython)的默认打开工作路径
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...
- spark 笔记 1: 如何着手
必读:从官方的开发者页面着手,包括如何构建spark以及编码规范(强烈建议读读编程规范)等:https://cwiki.apache.org/confluence/display/SPARK/Cont ...
- wls应用命令部署与卸载
1.查看wls节点运行状态 [root@localhost lib]# jps [root@localhost lib]# ss -tnlp|grep 23705 2.配置wls环境变量 [deplo ...
- 使用DBLink方式同步远程数据库中含Blob、Clob字段表的问题解决
在数据库同步中我们经常会用到DBLink方式.DBLink可以将物理上存放于网络的多个数据库在逻辑上当成一个单一的大数据库.开发人员无需关心数据库的网络分布,就能很方便的实现从不同数据库之间读取数据. ...
- BOSCH汽车工程手册————驾驶员辅助系统
根据交通事故统计得出平均每分钟有一人死于交通事故 而辅助驾驶系统能够为驾驶员洞察了解汽车周围情况,识别危险的行驶状况. 提早为驾驶员告诉危险信息,可减少60%汽车驶上主路事故和1/3汽车前碰事故. 有 ...
- kotlin之数组
一.使用arrayOf函数定义可以存储任意值的数组 var arr1 = arrayOf(1,2,3,'a') println(arr1[3]) 二.使用arrayOfNulls函数定义数组 var ...
- flutter runtimeType
通过runtimeType可以获取当前数据类型 var a = 10; var b = 10.0; var c = '10'; var d = true; var e = [12.5,13.1]; v ...
- Java学习之==>JDBC
一.概述 官方解释: JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的 Java API,可以为多种关系型数据库提供统一访问,它由一组用 ...
- Linux下源码安装MySQL-5.6.25
从mysql-5.5起,mysql源码安装开始使用cmake了,因此我们得先安装cmake,配置安装目录./configure --perfix=/.....的时候和以前的会有些区别. 一.安装cma ...
- flex布局使用方法简要汇总
近期因为使用inline-block,在项目部署后出现了一点小问题,几番解决未果,遂使用flex布局,于是借此机会对flex布局的用法做一个简要的汇总. 遇到的bug如下: 本想两个div使用inli ...