Linux程序编译链接以及makefile编写

主程序子程序的编译和链接

  • 主程序 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: 是用于清理生成的多余的目标文件。
  • 是必须的,后面加命令。

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 将编译完成的数据安装到默认目录中。