假设我的执行档中有四个源码文件分别是main.c haha.c sin_value.c cos_value.c,这四个文件的目的是:
· main.c :主要的目的是让用户输入角度数据与呼叫其他三支子程序; · haha.c :输出一堆有的没有的讯息而已; · sin_value.c :计算使用者输入的角度(360) sin 数值; · cos_value.c :计算使用者输入的角度(360) cos 数值。
我们需要对其进行别编译执行,很麻烦。我们可以利用make工具将以上文件一次性编译。
1. 先编辑 makefile 这个规则文件,内容只要作出 main 这个执行档 [root@study ~]# 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@study ~]# rm -f main *.o <==先将之前的目标文件去除 [root@study ~]# 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@study ~]# make make: `main' is up to date. # 看到了吧!是否很方便呢!只会进行更新 (update) 的动作而已。或许你会说:『如果我建立一个 shell script 来将上面的所有动作都集结在一起,不是具有同样的效果吗?』呵呵! 效果当然不一样,以上面的测试为例,我们仅写出 main 需要的目标文件,结果 make 会主动的去判断每个目标文件相关的原始码文件,并直接予以编译,最后再直接进行连结的动作! 真的是很方便啊!此外,如果我们更动过某些原始码文件,则 make 也可以主动的判断哪一个原始码与相关的目标文件文件有更新过, 并仅更新该文件,如此一来,将可大大的节省很多编译的时间呢! 要知道,某些程序在进行编译的行为时,会消耗很多的 CPU 资源, make 有这些好处: · 简化编译时所需要下达的指令; · 若在编译完成之后,修改了某个原始码文件,则 make 仅会针对被修改了的文件进行编译,其他的 object file 不会被更动; · 最后可以依照相依性来更新 (update) 执行档。
2、makefile的基本语法与变量
基本规则
目标(target): 目标文件 1 目标文件 2 <tab> gcc -o 欲建立的执行文件 目标文件 1 目标文件 2目标 (target) 就是我们想要建立的信息,而目标文件就是具有相关性的 object files ,那建立执行文件的语法就是以 <tab> 按键开头的那一行,『命令行必须要以 tab 按键作为开头』才行!他的规则基本上是这样的:
· 在 makefile 当中的 # 代表批注; · <tab> 需要在命令行 (例如 gcc 这个编译程序指令) 的第一个字符; · 目标 (target) 与相依文件(就是目标文件)之间需以『:』隔开。
如果我想要有两个以上的执行动作时, 例如下达一个指令就直接清除掉所有的目标文件与执行文件,该如何制作呢?
# 1. 先编辑 makefile 来建立新的规则,此规则的目标名称为 clean : [root@study ~]# 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@study ~]# 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』
利用shell scripts的相关规则简化makefile
[root@study ~]# vi makefile LIBS = -lm OBJS = main.o haha.o sin_value.o cos_value.o main: ${OBJS} gcc -o main ${OBJS} ${LIBS} clean: rm -f main ${OBJS}
与 bash shell script 的语法有点不太相同,变量的基本语法为: (1)变量与变量内容以『=』隔开,同时两边可以具有空格; (2)变量左边不可以有 <tab> ,例如上面范例的第一行 LIBS 左边不可以是 <tab>; (3) 变量与变量内容在『=』两边不能具有『:』; (4)在习惯上,变数最好是以『大写字母』为主; (5)运用变量时,以 ${变量} 或 $(变量) 使用; (6)在该 shell 的环境变量是可以被套用的,例如提到的 CFLAGS 这个变数! (7) 在指令列模式也可以给予变量。 由于 gcc 在进行编译的行为时,会主动的去读取 CFLAGS 这个环境变量,所以,你可以直接在 shell 定义出这个环境变量,也可以在 makefile 文件里面去定义,更可以在指令列当中赋予
[root@study ~]# CFLAGS="-Wall" make clean main # 这个动作在上 make 进行编译时,会去取用 CFLAGS 的变量内容! 也可以这样: [root@study ~]# 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}我可以利用指令列进行环境变量的输入,也可以在文件内直接指定环境变量,那万一这个CFLAGS 的内容在指令列与 makefile 里面并不相同时,以那个方式输入的为主?环境变量取用的规则是这样的: (1)make 指令列后面加上的环境变量为优先 (2)makefile 里面指定的环境变量第二; (3)shell 原本具有的环境变量第三。 特殊的变量: (4)$@:代表目前的目标(target)
[root@study ~]# vi makefile LIBS = -lm OBJS = main.o haha.o sin_value.o cos_value.o CFLAGS = -Wall main: ${OBJS} gcc -o $@ ${OBJS} ${LIBS} <==那个 $@ 就是 main ! clean: rm -f main ${OBJS}