makeFile总结

makefile总结

1.简介

makefile主要作用实现程序的“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,用于解释makefile中指令的命令工具,make命令执行的时候需要一makefile文件,告诉make命令如何工作。
使用make进行编译的时候,我们希望能够做到以下三点(三点规则):

  1. 如果这个工程没有编译过,那么我们的所有文件都要编译并被链接。
  2. 如果这个工程的某几个文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
  3. 如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的文件,并链接目标程序。

makefile设计的好,可以实现只用一个make命令就完成编译和链接工作。

2. 规则基础组成

makefile语句由三部分组成:目标体(target)、生成目标体所依赖的文件(dependency_files)、形成目标体所需要的命令(command)。其格式如下:

target:dependency_files
	command  #注意:在command前有一个 tab 

例:

hello.o:hello.c hello.h
	gcc -c hello.c -o hello.o

基础实例:
文件组成:f1.c、f2.c、main.c、head.h

  • f1.c内容如下:

    #include <stdio.h>
    
    void print1(){
        printf("Message:f1.c\n");
    }
    
  • f2.c内容如下:

    #include <stdio.h>
    
    void print2()
    {
        printf("Message:f2.c\n");
    }
    
  • head.h内容如下:

    void print1();
    void print2();
    
  • main.c内容如下:

    #include <stdio.h>
    #include "head.h"
    
    int main()
    {
            print1();
            print2();
    
            printf("end main\n");
            return 0;
    }
    

此项目在不用makefile的进行编译,则需要先生成f1.o、f2.o和main.o,然后再使用生成的这些.o文件,生成最后的执行文件。使用makefile,可将此编译命令和流程写进makefile,用make命令编译。
makefiel文件内容如下:

test:f1.o f2.o main.o
    gcc f1.o f2.o main.o -o test
f2.o:f2.c
    gcc -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息
f1.o:f1.c
    gcc -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o”
main.o:main.c
    gcc -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里
clean:
	rm *.o test#删除.o和执行文件

3.make工作原理

在输入make命令后,系统执行了以下几步:

  1. make会在当前目录下找名字叫**“Makefile”或“makefile”**的文件。

  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test”这个文件,并把这个文件作为最终的目标文件。

  3. 如果test文件不存在,或test所依赖的后面的 .o文件的文件修改时间要比test这个文件新(根据时间判断),那么他就会执行后面所定义的命令来生成test这个文件。

  4. 如果test所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(类似堆栈的过程)

  5. 当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件声明make的终极任务,也就是执行文件test了。

注:这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件

补充:clean部分,没有被第一个目标文件(test)直接或间接关联,那么它后面所定义的命令将不会被自动执行。我们可以显示要make执行,通过命令——“make clean”,以此来清除所有的目标文件,以便重编译。

4.makefile变量

makefile中定义变量,就像是C/C++语言中定义宏一样,它代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。此变量可以用在“目标”体,“依赖文件”, “命令”任何一部分中。通过变量对上述的例子改进,在上述例子中”f1.o f2.o main.o“这部分重复使用了两个,如果,我们需要增加文件时,需要改变这两个地方,我们可以用变量来代替此部分,在改变的时候只改变变量处即可。实现如下:

obj = f1.o f2.o main.o
test:$(obj)
    gcc $(obj) -o test
f2.o:f2.c
    gcc -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息
f1.o:f1.c
    gcc -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o”
main.o:main.c
    gcc -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里
clean:
	rm *.o test#删除.o和执行文件

补充:

  • makefile的预定义变量
变量名变量含义
AR库文件维护程序名称,默认为ar.AS汇编程序名称,默认值为as。
CCC编译器的名称,默认为cc。CPP C预编译器的名称,默认值为$(CC) -E
CXXC++编译器的名称,默认为g++
FCFORTRAN编译器的缩写,默认值为f77
RM文件删除程序名称,默认为rm -f

例:用CC改写上述例子

obj = f1.o f2.o main.o
test:$(obj)
    &(CC) $(obj) -o test
f2.o:f2.c
    &(CC) -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息
f1.o:f1.c
    &(CC) -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o”
main.o:main.c
    &(CC) -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里
clean:
	rm *.o test#删除.o和执行文件
  • makefile的自动变量
变量名变量含义
$*不包含扩展名的目标文件名称
$+所有的依赖文件,以空格分开,并以出现后的先后为序,可能包含重复依赖文件
$<第一个依赖文件的名称
$?所有时间戳比目标文件晚的依赖文件,并以空格分开目标文件的完整名称
$@目标文件的完整名称
$^所有不重复的目标依赖文件,以空格分开
$%如果目标是归档成员,则该变量表示目标的归档成员的目标名称

常用:$ @、$ ^、$<

  • $ @:表示目标集,“集”的意思就是组合,全部,有多个目标,$ @就是目标集合。
    上例中第一句话 $ @ 等价于 test,即可改写如下:

     test:$(obj)
        &(CC) $(obj) -o $@
     # 注:同样其他的规则都可以改写。
    
  • $^: 所有依赖目标的集合,注意,这里说的是“依赖”,也就是目标的组成元素。
    上例中第一句话的 $ (obj)表示所有的依赖, $^可表示此全部的依赖,即可改写如下:

    obj = f1.o f2.o main.o
    test:$(obj)
    	&(CC) $^ -o test #此处的$^等于 f1.o f2.o main.o
    
    以上例子的第一句话,用$@、$^可以写为:
    obj = f1.o f2.o main.o
    test:$(obj)
    	&(CC) $^ -o $@ #此处的$^等于 f1.o f2.o main.o
    
  • $ <依赖目标中的第一个目标名字,也就是上面说的$^中的第一个元素。

5.隐含规则

1.规则一:编译C语言的隐含规则

.o的目标的依赖会自动推导为.c文件,所以在写makefile时可以省略 .o到 .c的规则。

根据以上规则以上例子可以改为(f1.o,f2.o,main.o会因为隐含规则自动执行):

obj = f1.o f2.o main.o
test:$(obj)
    &(CC) $(obj) -o test

clean:
	rm *.o test#删除.o和执行文件

2.规则二:链接目标体的隐含规则

目标体依赖于.o文件,且.c文件存在时,链接命令可以隐含。

根据此规则,以上(规则一前的)makefile可以改写如下:

obj = f1.o f2.o main.o
main: $(obj) #此处的main可以换为f1 f2.必须是存在的c文件的名字

clean:
	rm *.o test#删除.o和执行文件

此处包含的隐含规则有:

#根据规则二省略的
$(CC)   &(obj)  -o main 

#根据规则一省略的
f2.o:f2.c
    gcc -c f2.c -o f2.o
f1.o:f1.c
    gcc -c  f1.c -o f1.o
main.o:main.c
    gcc -c  main.c -o main.o

6.伪目标

在此规则中clean就是一个伪目标,

clean:
	rm *.o test#删除.o和执行文件

此规则是为了清除我们生成的中间文件,以备重新编译,执行命令 make clean”。

因为此规则并不生成“clean”这个文件,所以“伪目标”并不是一个文件,只是一个标签,由于“伪目标”不是文件,所以make无法生成它的依赖关系和决定它是否要执行。我们只有通过显示地指明这个“目标”才能让其生效。当然,“伪目标”的取名不能和文件名重名,否则会报错。
在这里插入图片描述
有此文件还必须用此伪目标,不报错的解决方法:使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。

   .PHONY : clean

以上makefile可以改写为:

obj = f1.o f2.o main.o
main: $(obj) #此处的main可以换为f1 f2.必须是存在的c文件的名字

.PHONY : clean
clean:
	rm *.o test#删除.o和执行文件

7.VPATH

在一些大的工程中,有大量的源文件,我们通常的做法是把许多的源文件分类,存放在不同的目录下。所以,当make需要找文件依赖关系时,可以在文件前加上路径,最好的办法就是把一个路径告诉make,让make在自动的去找。makefile文件中的特殊变量VPATH就是完成这么一个功能。如果没有指明这个变量,make只会在当前目录中去寻找依赖文件和目标文件。如果定义了这个变量,make就会在当前目录找不到的情况下,到指定的目录中去找寻文件了。

VPATH = src ../headers

上面的定义指定两个目录,‘src’和‘…/headers’,make会按照这个顺序进行搜索。当前目录永远是最高优先级搜索的地方。
例:以上例子的f1.c放在src1中,f2.c放在src2中,其他的在当前目录。则上述makefile文件如下:

0 VPATH = src1 src2 
1 obj = f1.o f2.o main.o
2 test:$(obj)
3     &(CC) $(obj) -o test
4 f2.o:f2.c
5     &(CC) -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息
6 f1.o:f1.c
7     &(CC) -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o”
8 main.o:main.c
9     &(CC) -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里
10 .PHONY : clean
11 clean:
12	  rm *.o test#删除.o和执行文件

# 根据隐含规则4-9行可以省略。

按照这样写,生成的中间文件和执行文件都在当前目录下。可以显示指定生成的目录,如下:

0 VPATH = src1 src2 
1 obj = f1.o f2.o main.o
2 test:$(obj)
3     &(CC) $(obj) -o test
4 src2/f2.o:f2.c
5     &(CC) -c -Wall f2.c -o f2.o# -Wall允许发出gcc所有有用的报警信息
6 src1/f1.o:f1.c
7     &(CC) -c -Wall f1.c -o f1.o#-c表示只编译不链接,生成目标文件“.o”
8 main.o:main.c
9     &(CC) -c -Wall main.c -o main.o#-o file表示把输出文件输入到file里
10 .PHONY : clean
11 clean:
12	  rm *.o test#删除.o和执行文件

# 根据隐含规则4-9行可以省略。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值