主程序子程序的编译和链接
- 主程序 hello.c
#include<stdio.h>⇠
int main(void)⇠
{⇠
printf("Hello World\n");
thanks();⇠
}⇠
- 子程序 thanks.c
#include<stdio.h>⇠
void thanks(void)⇠
{⇠
printf("Thanks\n");⇠
}⇠
- 编译
gcc -c hello.c thanks.c
-c 是免去链接,否则主程序调用 thanks那行会报错。
-c 同时会自动生成 hello.o 与 thanks.o
- 链接
gcc -o main hello.o thanks.o
部分编译
在上面的基础上,假如我们修改了 thanks.c, 我们不需要全部重新编译, 只需要生成新的thanks.o 再与其他目标文件重新链接即可。 节省时间。
调用动态函数库
记得用pthread写程序的时候,编译时总要在后面加上 -lpthread 选项,这是什么原因呢?
- 写一个程序
#include <stdio.h>⇠
int main()
{⇠
float val;⇠
val = sin (3.14/2);⇠
printf("%f\n",val);⇠
}
- 动态链接
gcc -o main lib.c -lm -L /lib -L /usr/lib
- sin() 函数在 libm.so 函数库当中,-lm的意思是 :
- l: 链接函数库 lib的意思
- m: libm.so 去掉 lib 和 so后的部分。 由此可以联想到 pthread 应该在 libpthread.so
函数库当中定义。
-L 指定函数库的位置, 默认在/lib 和 /usr/lib 当中,所以不写也没关系。
静态函数库和动态函数库
静态函数库
- 扩展名 .a , 全名为libxxx.a
- 这类函数库在编译的时候就会整合到执行程序当中。
- 函数库的升级将导致所有包含它的程序的升级。
动态函数库
扩展名 .so, 全名为 libxxx.so
这类函数在编译的时候只添加一个 函数库的指针。在执行的时候才需要加载。
函数库的升级不需要修改其他程序。
动态函数库解析
ldd xxx.o 可以分析程序涉及哪些动态函数库。
gcc 的常用选项
- E : 预处理, 从 main.c 到 main.i 木的是加载静态函数库
- -S: 编译, 从 xxx.i 到 xxx.s 得到汇编语言代码。
- c: 生成机器代码 .o文件
- -o: 链接, 生成可执行文件
- -O[0:3] : 进行不同程度的优化。
- -std=c99 : 支持 c99 标准
- -std=c++11: 支持c++11
- -Wall: 编译更加严格
- -g: 产生用于gdb调试的信息
make的使用
为什么使用make
假如我们的一个项目又很多程序,这些程序相互引用,一些程序还使用到动态函数库。那么我们编译的时候将分很多步进行,特别麻烦。 当我们需要重新编译的时候,所有步骤还是得重新来一遍。能不呢省略呢?
make的基本用法
target: 目标文件1 目标文件2 ...
<tab> gcc -o 目标文件1 目标文件2
举例说明
还是以上面hello.c, thanks.c 为例, 忘了的朋友可以翻页上去看一下。下面是我们makefile:
main: hello.o thanks.o
gcc -o main hello.o thanks.o
clean:
rm -f hello.o thanks.o
可以看到,我有两个target,这两个可以在调用make的时候进行选择:
make main
make clean
其中:
- main : 是生成目标文件 main。
- clean: 是用于清理生成的多余的目标文件。
- <tab> 是必须的,后面加命令。
makefile的优化
makefile当中也可以进行变量的定义,可以简化makefile的编写:
OBJS = main.o thanks.o
main:
gcc -o $@ ${OBJS}
clean:
rm -f ${OBJS}
- 与bash类似但优点不同, 变量的定义中 ,’=’两边可以有空格。
- $@ 代表当前target, 在这里是 main
Tarball软件的安装
经常我们需要通过源码安装软件,那么它们安装的步骤是怎样的呢?
- ./configure: 用于生成 Makefile
- make clean 用于清除之前的 目标文件
- make 编译
- make install 将编译完成的数据安装到默认目录中。