Makefile是Linux中很常用的一个工具,会不会写makefile可以显示出一个人是否具备完成大型工程的能力。
通常,我们一个工程中的源文件可能还会很多很多,可能放在不同的目录中,那么这时我们要怎么编译程序呢,Makefile就可以帮助我们解决这个问题,makefile定义了一系列的规则来指定哪些文件需要先编译,哪些文件后编译,甚至更复杂的动作,一旦将makefile文件写好,只需要一个make命令,整个工程完全自动编译,极大地提高了软件开发的效率。
Makefile文件如何编写呢?Makefile文件:包括依赖关系和依赖方法,具体如下:
依赖关系
(Tab键)依赖方法 (这里必须是Tab键,而不能是空格)
举一个例子:
这是一段C语言的代码:
//main.c
#include<stdio.h>
int main()
{
printf("This is main()\n");
fun1();
fun2();
return 0;
}
//fun1.c
#include<stdio.h>
void fun1()
{
printf("This is fun1()\n");
}
//fun2.c
#include<stdio.h>
void fun2()
{
printf("This is fun2()\n");
}
这段代码本身没有什么意义,在此只是为了方便,我们需要将三句话都打印到屏幕上。
编写Makefile文件,内容如下:
main:main.o fun1.o fun2.o
gcc -o main main.o fun1.o fun2.o
main.o:main.c
gcc -c main.c -o main.o
fun1.o:fun1.c
gcc -c fun1.c -o fun1.o
fun2.o:fun2.c
gcc -c fun2.c -o fun2.o
.PHONY:clean
clean:
rm -f fun1.o fun2.o main.o main
其中main依赖于main.o, fun1.o, fun2.o,而依赖方法就是gcc -o main main.o fun1.o fun2.o;main.o依赖于main.c,依赖方法是gcc -c main.c -o main.o…….后面的类似。关于.PHONY具体后面内容。
保存后,在bash中输入命令make,就可以得到可执行的程序了,如下所示:
有的人可能会觉得这么写有些太麻烦了,如果有成百上千个文件怎么办?没关系,我们可以用$@代表所有的目标文件,$^代表所有的依赖文件
,这样,我们就可以简化以上所写的内容:
main:main.c fun1.c fun2.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f main
可能有的同学会有些分不清makefile和make。makefile是一个文件,make是一条命令,解释makefile中指令的命令工具。
有的同学可能会问:这么神奇的make是如何工作的呢?
1. make会在当前目录下找名字为makefile或Makefile的文件。
2. 如果找到,他会找文件中第一个目标文件,并把这个文件作为最终的目标。
3. 如果hello文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个文件。
4. 如果hello所依赖hello.o文件不存在,那么make会在当前文件中找目标为hello.o文件的依赖性,如果找到则在根据那一个生成hello.o文件,以此类推。
5. make一层一层的去找文件的依赖关系,直到最终编译出第一个目标文件。
6. 如果出现错误,或者没找到,make会退出并报错。
以上就是Makefile的基础使用方法了,在此再介绍几个其他的点:
- 我们之前的代码中
.PHONY:clean
,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令不会自动执行,需要“make clean”以清除所有的目标文件,一般这种clean的目标文件,我们将它设置为伪目标,用.PHONY修饰,它的特点是总是被执行的。 - 如果我们要同时生成两个可执行的文件,需要怎么办?
假设两个函数是test1.c和test2.c,那么Makefile文件可以如下编写:
.PHONY:all
all:test1 test2
test1:test1.c
gcc -o $@ $^
test2:test2.c
gcc -o $@ $^
- 在Makefile中还可以定义变量
举一个例子:我们定义一个变量cc让它等于gcc,在下面的代码中,就可以使用$(cc)来代替gcc了。
cc=gcc
mytest:mytest.c
$(cc) -o $@ $^
.PNONY:clean
clean:
rm -f mytest