linux 静态库 动态库 编译C程序

dfsdf

一. 编译C程序 

1. 后缀名及涵义。

.a  静态对象库(文档) 
.c   需要预处理的C 语言源代码 
.h   C 语言源代码的头文件 
.i   无需预处理的C 语言源代码。该类文件是编译过程的中间产物 
.o   目标文件,格式和应用的连接相符。该类文件是编译过程的中间产物 
.s   汇编语言代码(assembly language code )。该类文件是编译过程的中间产物 

.so   共享对象库(shared object library) 


2.  gcc的默认编译(单源程序到可执行程序)

通过检查命令行中的文件名后缀,编译程序可以确定所编译的是 C 语言源文件。GCC
采取的默认动作是将源文件编译为目标文件,然后将目标文件连接到可执行文件,最后再
删除目标文件。由于该命令没有指定生成的可执行文件的名字,所以编译程序会用当前目
录下的默认文件名a.out。在命令行中键入该程序名,会运行该程序并显示结果。 
$ a.out 
hello, world 

3. gcc 的 -c选项(源文件到目标文件)

 选项-c 会明确指示GCC去编译源代码,但不在硬盘上留下目标文件,且跳过将目标文
件连接到可执行程序这一步。
这种情况下的默认输出文件名和输入文件名一样,但以.o 作
后缀。例如,下面的命令会生成目标文件helloworld.o: 
$ gcc -c helloworld.c 
选项-o 可用于修改生成的目标文件名。下面的命令会生成目标文件,名为 harumph.o: 
$ gcc -c helloworld.c -o harumph.o 

在构造目标库的过程中,或在创建目标文件集合的时候,其中的目标文件可用于之后
的连接操作,有条命令可由多个源文件创建出目标文件。下面的命令会创建目标文件
arglist.o、ponder.o 和listsort.o : 
$ gcc -c arglist.c ponder.c listsort.c

4.  多源文件到可执行文件。

GCC编译程序可以自动处理连接,甚至在编译多个源文件的时候也可以自动连接。例
如,下面保存在文件hellomain.c 中的源代码,调用函数 sayhello(): 

/* hellomain.c */ 
void sayhello(void); 
int main(int argc,char *argv[]) 
{ 
    sayhello(); 
    return(0); 
} 


而以下源代码保存在文件sayhello.c中,定义了函数sayhello() : 
/* sayhello.c */ 
#include stdio.h 
void sayhello() 
{ 
    printf("hello, world\n"); 
} 


下面的命令将两个程序编译成一个目标文件,并将它们连接到一个可执行程序 hello
上,最后删掉目标文件: 
$ gcc hellomain.c sayhello.c -o hello


5. 预处理以及汇编

$ gcc -E helloworld.c -o helloworld.i  (-E为预处理选项)

$ gcc -S helloworld.c     (-S为汇编选项)


二. 静态库与动态库

1. 静态库

静态库是一些.o 文件的集合,它们是由编译程序按照通常的方式生成的。将程序连接
到库中的目标文件和将程序连接到目录中的目标文件是一样的。静态库的另一个名字是文
档(archive ),而管理这些文档内容的工具叫做ar 。

 
要构造一个库,最基本的一步是要编译库中的目标模块。例如,以下两个源文件名为

hellofirst.c 和hellosecond.c: 
/* hellofirst.c */ 
#include <stdio.h> 
void hellofirst() 
{ 
    printf("The first hello\n"); 
} 
/* hellosecond.c */ 
#include <stdio.h> 
void hellosecond() 
{ 
    printf("The second hello\n"); 
} 

可用下面命令将这两个源文件编译成目标文件: 
$ gcc -c hellofirst.c hellosecond.c 


使用工具ar 的-r 选项,可以创建新的库,并会将目标文件插入其中。选项-r 会创建库,
如果库中不存在所命名的目标模块,就会将它加入文档(如果必要,也会替换原来的目标
模块)。下面的命令创建名为 libhello.a 的库,其中包含本例的两个目标模块: 
$ ar -r libhello.a hellofirst.o hellosecond.o 
现在该库已经完成,可以使用了。下面的程序twohellos.c 会调用新库中的这两个函数: 

/* twohellos.c */ 
void hellofirst(void); 
void hellosecond(void); 

int main(int argc,char *argv[]) 
{ 
    hellofirst(); 
    hellosecond(); 
    return(0); 
} 


如下所示,通过在命令行中指定库,用一条命令就能够编译并连接程序twohellos : 
$ gcc twohellos.c libhello.a -o twohellos 

静态库的命名习惯是以字母lib 开头,以后缀.a 结束。所有系统库都使用这种命名规则,
并且允许通过选项-l (ell),在命令行中使用库名的缩写形式。下面命令和前面命令的惟一
区别在于期望gcc 对库进行查找的位置有所不同: 
$ gcc twohellos.c -lhello -o twohellos  (缩写形式)
明确指出完全路径名会令编译程序在所指路径中查找库。库名既可指明绝对路径(例
如 /usr/worklibs/libhello.a ),也可以是到当前目录的相对路径(例如../lib/ libhello.a )。选项
-l 不能指明路径(-L可指明路径),但是可以指示编译程序在系统库中进行查找。


2. 共享库(动态库)

共享库是目标文件的集合,但是这些目标文件是由编译程序按照特殊方式生成的。
象模块的每个地址(变量引用和函数调用)都是相对地址,不是绝对地址。因此允许在运
行程序的时候,可以动态加载和执行共享模块。
所以最后使用的时候比静态库小得多。 
构造共享库最基本的一步是编译库中的对象模块。例如,下面的两个源文件名为
shellofirst.c 和shellosecond.c : 

/* shellofirst.c */ 
#include <stdio.h> 
void shellofirst() 
{ 
    printf("The first hello from a shared library\n"); 
} 
/* shellosecond.c */ 
#include <stdio.h> 
void shellosecond() 
{ 
    printf("The second hello from a shared library\n"); 
} 

使用下列命令可将这两个源文件编译成一个目标文件: 
$ gcc -c -fpic shellofirst.c shellosecond.c 
 
选项-c 明确指出编译程序要生成的.o  目标文件。而选项-fpic 使得输出的对象模块是
按照可重定位地址(relocatable addressing )方式生成的。缩写pic代表位置独立代码(position 
independent code)。 

 
下面的gcc 命令使用目标文件构造共享库hello.so: 
$ gcc -shared shellofirst.o shellosecond.o -o hello.so 
选项-o 为输出文件命名,而后缀.so  告诉 GCC该目标文件是要连接到共享库的。通常,
连接程序要为主函数main()定位,并用它作为程序的入口,但输出模块没有这样的入口,
选项-shared  对防止出错信息是必要的。 
编译程序将后缀为.c 的文件看作是 C 语言源代码程序,并且知道如何将它编译成目标
文件。因此,可以将前面的两个命令合成一个命令,用下面的命令可以将模块直接编译并
保存为共享库: 
$ gcc -fpic -shared shellofirst.c shellosecond.c -o hello.so 
下面是文件stwohellos.c 中的程序,是主函数,它调用了共享库中的两个函数: 

/* stwohellos.c */ 
void shellofirst(void); 
void shellosecond(void); 
int main(int argc,char *argv[]) 
{ 
    shellofirst(); 
    shellosecond(); 
    return(0); 
} 


可以使用下列命令将该程序编译并连接到共享库: 
$ gcc stwohellos.c hello.so -o stwohellos 
程序stwohellos 已经可以运行了,但要运行程序必须也要能够定位共享库 hello.so,因
为库中的函数必须在运行的时候载入。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值