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. springboot+aop+自定义注解,打造通用的全局异常处理和参数校验切面(通用版)

    一.引入相应的maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifa ...

  2. weblogic域,管理服务器,受管服务器,集群和机器的基本知识

    1.域(Domain) •它是什么? –是一个逻辑上管理的WebLogic Server组,这些组从管理上当作一个整体来操作 •域里面有什么? –服务器 –服务器集群 –机器 •规则: –同一个域中的 ...

  3. 分组 vs 联合

    // 分组 function groupBy(groups) { return groups.reduce((pre, cur) => { pre[cur.groupId] = (pre[cur ...

  4. Summernote文本编辑器入门

    1.summernote是一个界面比较简洁美观的富文本编辑器. 2.文件导入(官方下载地址:http://summernote.org/) 下载回来的文件夹是这样的: 插件的核心文件放在 dist 这 ...

  5. 三十九:数据库之SQLAlchemy.relationship方法中的cascade参数

    在SQLAlchemy中,只要将一条数据添加到session中,其它和此条数据相关联的数据都会一起存到数据库中,这是因为在relationship中有一个关键字参数:cascade,默认选项为save ...

  6. opencv、numpy中矩阵转置,矩阵内的固定位置相应的坐标变换

    opencv.numpy中矩阵转置,矩阵内的固定位置相应的坐标变换

  7. gcc编译器创建和使用静态库、动态库

    http://www.cnblogs.com/dyllove98/archive/2013/06/25/3155599.html 目录树结构: test/include/hello.h #ifdef ...

  8. ssm遇到的问题

    1. Caused by: java.lang.IllegalArgumentException at org.springframework.asm.ClassReader.<init> ...

  9. 在Spring容器外调用bean

    这个东西源于这种需求:一个应用丢到服务其后,不管用户有没有访问项目,这个后台线程都必须给我跑,而且这个线程还调用了Spring注入的bean,这样自然就会想到去监听Servlet的状态,当Servle ...

  10. cocos2dx基础篇(23) 粒子系统CCParticleSystem

    [3.x]     (1)去掉"CC"     (2)粒子位置模式 tPositionType 改为强枚举类型 ParticleSystem::PositionType:: // ...