Makefile基础学习

Makefile基础学习

理论知识

  • makefile关系到了整个工程的编译规则。一个工程中的源文件不计其数,并且按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为makefile就像一个 Shell脚本一样,其中也可以执行操作系统的命令。
  • makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

书写规则和语法

  • 规则包含两个部分,一个是依赖关系,一个是生成目标的方法。

makefile写法为:

targets : prerequisites
	command
	...

或是这样

targets : prerequisites ; command
	command
	...

targets是文件名,以空格分开,可以使用通配符。一般来说,我们的目标基本上是一个文件,但也有可能是多个文件。
command是命令行,如果其不与“targets:prerequisites”在一行,那么,必须以[Tab键]开头,如果和prerequisites在一行,那么可以用分号做为分隔。(见上)
prerequisites也就是目标所依赖的文件(或依赖目标)。

实例学习

  • 参考GCC基础知识学习中『一个实例:-I参数的使用』,写出编译例子中vi编辑代码的makefile,编译出来的目标文件为testmymath, 只用显式规则就可以。

首先,我们可以vim Makefile或者vim makefile来新建打开一个makefile。

我们先得到几个文件的依赖关系:testmymath依赖五个.o文件,五个.o文件分别依赖相应的.c文件和head.h文件。

第一步要写出最终目标:

testmymath: main.o add.o sub.o mul.o div.o //最终目标文件:依赖文件
    gcc main.o add.o sub.o mul.o div.o -o testmymath//以tab键开头,写出命令行,即得到testmymath的命令

接下来是各个.o文件的生成(规则同上):

main.o: main.c head.h
    gcc -c main.c
add.o: add.c head.h
    gcc -c add.c
sub.o: sub.c head.h
    gcc -c sub.c
mul.o: mul.c head.h
    gcc -c mul.c
div.o: div.c head.h
    gcc -c div.c

最后就可以完整的得到makefile文件啦!

testmymath: main.o add.o sub.o mul.o div.o 
    gcc main.o add.o sub.o mul.o div.o -o testmymath
main.o: main.c head.h
    gcc -c main.c
add.o: add.c head.h
    gcc -c add.c
sub.o: sub.c head.h
    gcc -c sub.c
mul.o: mul.c head.h
    gcc -c mul.c
div.o: div.c head.h
    gcc -c div.c

makefile中使用变量

  • 在上面的例子中,我们可以看到[.o]文件的字符串被重复了两次,如果我们的工程需要加入一个新的[.o]文件,那么我们需要在两个地方加。当然,我们的makefile并不复杂,所以在两个地方加也不累,但如果makefile变得复杂,那么我们就有可能会忘掉一个需要加入的地方,而导致编译失败。所以,为了makefile的易维护,在makefile中我们可以使用++变量++。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。

比如,我们声明任意一变量名,叫objects, OBJECTS, objs, OBJS, obj, 或OBJ,只要能够表示obj文件即可。我们在makefile起始处按如下定义此变量:

objects = main.o add.o sub.o mul.o div.o

于是,我们就可以很方便地在我们的makefile中以“$(objects)”的方式来使用这个变量了,于是我们的改良版makefile变为如下:

objects = main.o add.o sub.o mul.o div.o

testmymath : $(objects)
    gcc -o testmymath $(objects)
main.o: main.c head.h
    gcc -c main.c
add.o: add.c head.h
    gcc -c add.c
sub.o: sub.c head.h
    gcc -c sub.c
mul.o: mul.c head.h
    gcc -c mul.c
div.o: div.c head.h
    gcc -c div.c

make是如何工作的

  • 在默认的方式下,也就是我们只输入make命令。那么,
  1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
  2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“testmymath”这个文件,并把这个文件作为最终的目标文件。
  3. 如果testmymath文件不存在,或是testmymath所依赖的后面的 .o 文件的文件修改时间要比testmymath这个文件新,那么,他就会执行后面所定义的命令来生成testmymath这个文件。
  4. 如果testmymath所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
  5. 当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生成make的终极任务,也就是执行文件testmymath了。
  • 我们还可以在makefile中写一条clean的命令来一次性删除所有.o文件和testmymath,以便进行重新编译:
clean:
    rm testmymath *.o

像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,因此,我们可以显式要make执行,即命令make clean

如果使用变量,也可以写为:

clean:
    rm testmymath $(objects)

这样我们可以得到一个比较完整的makefile:

objects = main.o add.o sub.o mul.o div.o

testmymath : $(objects)
    gcc -o testmymath $(objects)
main.o: main.c head.h
    gcc -c main.c
add.o: add.c head.h
    gcc -c add.c
sub.o: sub.c head.h
    gcc -c sub.c
mul.o: mul.c head.h
    gcc -c mul.c
div.o: div.c head.h
    gcc -c div.c
clean:
    rm testmymath $(objects)

接下来我们测试一下写的makefile,这里建议大家到head.h所在的目录下使用mv head.h /src所在的路径,也就是把头文件和.c文件放到一个目录下。因为如果不在一个目录下,会出现make找不到头文件不成功的情况。

  • 我们make一下,可以看到make在自动执行了,并产生了.o文件和 testmymath。
  • 也可以使用 make clean一下子删除了想删除的文件。

  • 那么如果不把头文件放到src下,该怎么做呢?
  • 我们可以在makefile中加一句:
CFLAGS = -I/(头文件所在路径)

然后在相应执行语句中加入$(CFLAGS)即可,如:

main.o: main.c head.h
    gcc $(CFLAGS) -c main.c
原文地址:https://www.cnblogs.com/haoliberale/p/7955315.html