zoukankan      html  css  js  c++  java
  • 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
    
  • 相关阅读:
    react的50个面试题
    什么是宏队列跟微队列
    宏队列与微队列
    数组都有哪些方法
    vuex 跟 vue属性
    高阶组件
    如何创建视图簇(View cluster)-SE54/SM34
    ◆◆0如何从维护视图(Maintenace view)中取数据-[VIEW_GET_DATA]
    ◆◆0如何在SM30维护表时自动写入表字段的默认值-事件(EVENT)
    ◆◆0SAP Query 操作教程
  • 原文地址:https://www.cnblogs.com/haoliberale/p/7955315.html
Copyright © 2011-2022 走看看