makefile的使用

直接开始说怎么使用吧makefile虽然现在直接写比较少,而且笔直一年开发了接触也比较少但是吗不管是什么cmake也好还是qmake也好最后也都是转换成了makerfile了。自己平时写dome的时候如果有多个文件一个一个的编译也确实不方便。

makefile的三要素

Makefile有点类于脚本也可以理解为用于生成目标对象的脚本。
makefile的使用
看上面的图从命令中可以看到要生成的对象是main, 生成main这个程序一共用到了add.c sub.c main.c这三个
文件那么这三个文件就是依赖。实际上在编译的时候他们三都生成了对应的.o文件,那么依赖也可以直接写成这.o文件。当然这取决于生成命令怎么写。
本文中主要讲述makefile的命令的用法。

all: 
	echo "asdasd"

test:
	echo "test"

上面的这段直接make
makefile的使用

all是第一个生成的目标所以执行了生成的命令。直接make打印出来了asdasd,因为all是第一个目标如果没有指定目标默执行第一个目标。
这里也将要执行的命令进行了打印,如果要去除打印可以在命令前面加@

修改makefile如下:

all: test
	@echo "asdasd"

test:
	echo "test"

这时候生成all这个目标时就需要依赖test。所以下面运行的结果如下:
makefile的使用

利用makefile编译多个文件

假设现在有两个.c文件一个为foo.c内容如下:

#include <stdio.h>
void foo ()
{
    printf ("This is foo()!\nsss" );
}

有一个main.c:

 extern void foo();
 int main ()
 {
     foo();
    return 0;
 }

显然编译思路就是先将两个文件编译成foo.o和main.o,之后在进行链接就可以生成最后的可执行程序。

假设要生成的程序为simple就可以使用以下的makefile:

simple: foo.o main.o
	gcc -o simple main.o foo.o

foo.o:
	gcc -o foo.o -c foo.c

main.o:
	gcc -o main.o -c main.c

clean:
	rm foo.o main.o simple

生成simple需要 foo.o 和 main.o,而生成foo.o的main.o的方法又显示的指定出。
执行make之后可以发现simple程序已经生成,运行也正常。
但此时却有一个问题我们修改foo.c文件中的内容然后重新make发现打出的提示是simple是最新的。肯定有问题要问了我之前用的make都是改一下任意一个源文件,再使用make命令的时候就会根据修改的源文件重新编译。

makefile 先决条件

当make 在运行一个规则时即生成目标对象的时候,我们前面已经提到了目标和先决条件之间的依赖关系,make 在检查一个规则时,采用的方法是:如果先决条件中相关的文件的时间戳大于目标的时间戳,即先决条件中的文件比目标更新,则知道有变化,那么需要运行规则当中的命令重新构建目标。这条规则会运用到所有与我们在 make时指定的目标的依赖树中的每一个规。

解释: 上面生成simple需要 foo.o 和 main.o 这两个依赖,当找到foo.o和main.o后就会去寻找它们俩个的依,在上述的makefile中它俩的依赖都是空,所以make就只将foo.o和main.o与simple进行对比。 而此时两者没有修改所以就出现了上述的问题。 可以用touch 刷新foo.o或者main.o就可以看见重新执行了生成simple。

例如将makefile改为下面的:

simple: foo.o main.o
	gcc -o simple main.o foo.o

foo.o:foo.c
	gcc -o foo.o -c foo.c

main.o:main.c
	gcc -o main.o -c main.c

clean:
	rm foo.o main.o simple

将两者的依赖都写上。这样之后当foo.c或者main.c发生改变的时候就会重新进行生成。make会根据依赖关系自动进行重新生成。
makefile的使用
这里有一个小细节,已经生成过的东西如果依赖没有发生修改那么就不会重新生成了即使它以及损坏了。比如说我们将生成的foo.o进行修改,随便删除几行。这时候重新make由于foo.o已经生成,切时间戳比simple新那么就会重新生simple。由于foo.o已经生成且它的依赖 foo.c 没有发生修改那么它就不会自动重新生成。 由于foo.o的值以及被我们修改所以在链接的时候就会报错。

这些东西实际上没有什么难的地方,拷贝下来自己运行一下就知道流程了。 可能开始会觉得这是啥啊,谁发明的这么恶心的东西。 但当明白之后才发现这些设计的优美之处,似乎这就是最优解了。

假目标

在前面的 sample 项目中,现在假设在程序所在的目录下面有一个 clean 文件,这个文件也可以通过touch 命令来创建。创建以后,运行 make clean 命令,你会发现 make 总是提示 clean 文件是最新的,而不是按我们所期望的那样进行文件删除操作,从原理上我们还是可以理解的,这是因为 make 将 clean 当作文件,且在当前目录找到了这个文件,加上 clean 目标没有任何先决条件,所以,当我们要求 make 为我们构建 clean 目标时,它就会认为 clean 是最新的。

假目标可以采用.PHONY 关键字来定义,需要注意的是其必须是大写字母。

自动变量

我们看到的实际工程上的makefile显然不可能这么简单,一堆的各种符号。看的人眼花缭乱,头皮发麻。对于新手来说完全都不想看。其实都是为了方便才有这些符号,这些符号可以简化很多操作。
$@ :用于表示一个规则中的目标。当我们的一个规则中有多个目标时,$@所指的是其中任何造成命令被运行的目标。
$^ : 则表示的是规则中的所有先择条件。
$< :表示的是规则中的第一个先决条件。

说白了就是几个变量,记住变量就行。我们可以将其打印出来。

.PHONY:clean
CC=gcc
LIB=lpthread
simple: foo.o main.o
	gcc -o simple main.o foo.o

foo.o:foo.c
	gcc -o foo.o -c foo.c

main.o:main.c
	gcc -o main.o -c main.c

pint:foo.o main.o
	@echo "\$$@ = $@"
	@echo "$$^ = $^"
	@echo "$$< = $<"
clean:
	rm foo.o main.o simple

makefile的使用
可以看到就是三个变量。正确的使用这三个变量就可以让makefile变的简单很多改起来也会容易很多。
在 Makefile 中‘ ’ 具 有 特 殊 的 意 思 , 因 此 , 如 果 想 采 用 e c h o 输 出 ‘ ’具有特殊的意思,因此,如果想采用 echo 输出‘ ’具有特殊的意思,因此,如果想采用echo输出‘’,则必需用两个连着的‘ ’ 。 还 有 就 是 , ’。还有就是, ’。还有就是,@对于 Shell 也有特殊的意思,我们需要在“$$@”之前再加一个脱字符‘\’。

普通变量
再上述中 CC=gcc 就是一个普通变量

我们看一个简单的用变量的makefile

.PHONY: clean
CC = g++
EXE = JsonTest
Lib = -ljsoncpp
STD = -std=c++11

$(EXE):test1.cpp
	$(CC) test1.cpp -o $(EXE) $(Lib) $(STD)
	
clean:
	rm $(EXE)

$符号用于引用这个变量的值,所以编译指令就是为
g++ test1.cpp -o JsonTest -ljisoncpp -std=c++11
是不是很简单

先说这么多,makefile这才是冰山一脚,后面的后面再补充。

上一篇:Makefile c与c++多后缀自动推导


下一篇:Makefile