用 make 进行巨集编译

为什么要用 make

假设一个运行档里包含了多个原始码文件,并且这些原始码都有相关性,如果想要让这个程序跑就需要把每个原始码都分别用gcc编译,使用make就可以一个步骤就完成所有的工作。

# 1. 先编辑 makefile 这个守则档,内容只要作出 main 这个运行档
[root@www ~]# vim makefile
main: main.o haha.o sin_value.o cos_value.o
    gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 注意:第二行的 gcc 之前是 <tab> 按键产生的空格喔!

# 2. 尝试使用 makefile 制订的守则进行编译的行为:
[root@www ~]# rm -f main *.o   <==先将之前的目标档去除
[root@www ~]# make
cc    -c -o main.o main.c
cc    -c -o haha.o haha.c
cc    -c -o sin_value.o sin_value.c
cc    -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm
# 此时 make 会去读取 makefile 的内容,并根据内容直接去给他编译相关的文件罗!

# 3. 在不删除任何文件的情况下,重新运行一次编译的动作:
[root@www ~]# make
make: `main' is up to date.
# 看到了吧!是否很方便呢!只会进行升级 (update) 的动作而已。

make的优点:

  • 简化编译时所需要下达的命令;
  • 若在编译完成之后,修改了某个原始码文件,则 make 仅会针对被修改了的文件进行编译,其他的 object file 不会被更动;
  • 最后可以依照相依性来升级 (update) 运行档。

makefile 的基本语法与变量

基本的 makefile 守则:

标的(target): 目标档1 目标档2
<tab>   gcc -o 欲创建的运行档 目标档1 目标档2
  • 在 makefile 当中的 # 代表注解;
  • 需要在命令行 (例如 gcc 这个编译器命令) 的第一个字节;
  • 标的 (target) 与相依文件(就是目标档)之间需以『:』隔开。
# 1. 先编辑 makefile 来创建新的守则,此守则的标的名称为 clean :
[root@www ~]# vi makefile
main: main.o haha.o sin_value.o cos_value.o
    gcc -o main main.o haha.o sin_value.o cos_value.o -lm
clean:
    rm -f main main.o haha.o sin_value.o cos_value.o

# 2. 以新的标的 (clean) 测试看看运行 make 的结果:
[root@www ~]# make clean  <==就是这里!透过 make 以 clean 为标的
rm -rf main main.o haha.o sin_value.o cos_value.o

上面的makefile 里面就具有至少两个标的,分别是 main 与 clean ,如果我们想要创建 main 的话,输入『make main』,如果想要清除有的没的,输入『make clean』即可啊!而如果想要先清除目标档再编译 main 这个程序的话,就可以这样输入:『make clean main』,如下所示:

[root@www ~]# make clean main
rm -rf main main.o haha.o sin_value.o cos_value.o
cc    -c -o main.o main.c
cc    -c -o haha.o haha.c
cc    -c -o sin_value.o sin_value.c
cc    -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm

用变量简化makefile:

[root@www ~]# make clean main
rm -rf main main.o haha.o sin_value.o cos_value.o
cc    -c -o main.o main.c
cc    -c -o haha.o haha.c
cc    -c -o sin_value.o sin_value.c
cc    -c -o cos_value.o cos_value.c
gcc -o main main.o haha.o sin_value.o cos_value.o -lm

与 bash shell script 的语法有点不太相同,变量的基本语法为:

  1. 变量与变量内容以『=』隔开,同时两边可以具有空格;
  2. 变量左边不可以有 ,例如上面范例的第一行 LIBS 左边不可以是
  3. 变量与变量内容在『=』两边不能具有『:』;
  4. 在习惯上,变量最好是以『大写字母』为主;
  5. 运用变量时,以 ${变量} 或 $(变量) 使用;
  6. 在该 shell 的环境变量是可以被套用的,例如提到的 CFLAGS 这个变量!
  7. 在命令列模式也可以给予变量。

gcc 在进行编译的行为时,会主动的去读取 CFLAGS 这个环境变量,所以,你可以直接在 shell 定义出这个环境变量,也可以在 makefile 文件里面去定义,更可以在命令列当中给予,例如:

[root@www ~]# CFLAGS="-Wall" make clean main
# 这个动作在上 make 进行编译时,会去取用 CFLAGS 的变量内容!

或者:

[root@www ~]# vi makefile
LIBS = -lm
OBJS = main.o haha.o sin_value.o cos_value.o
CFLAGS = -Wall
main: ${OBJS}
    gcc -o main ${OBJS} ${LIBS}
clean:
    rm -f main ${OBJS}

环境变量取用的守则是这样的:

  1. make 命令列后面加上的环境变量为优先;
  2. makefile 里面指定的环境变量第二;
  3. shell 原本具有的环境变量第三。
  • $@:代表目前的标的(target)