跟我一起写 Makefile(二)

跟我一起写 Makefile(二)三、make是如何工作的在默认的方式下,也就是我们只输入make命令。那么,   1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。   2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。   3、如果edit文件不存在,或是edit所依赖的后面的.o文件的文

大家好,又见面了,我是你们的朋友全栈君。

三、make是如何工作的

在默认的方式下,也就是我们只输入make命令。那么,

    1、make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
    2、如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“edit”这个文件,并把这个文件作为最终的目标文件。
    3、如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件。
    4、如果edit所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程)
    5、当然,你的C文件和H文件是存在的啦,于是make会生成 .o 文件,然后再用 .o 文件生命make的终极任务,也就是执行文件edit了。

这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。

通过上述分析,我们知道,像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。

于是在我们编程中,如果这个工程已被编译过了,当我们修改了其中一个源文件,比如file.c,那么根据我们的依赖性,我们的目标file.o会被重编译(也就是在这个依性关系后面所定义的命令),于是file.o的文件也是最新的啦,于是file.o的文件修改时间要比edit要新,所以edit也会被重新链接了(详见edit目标文件后定义的命令)。

而如果我们改变了“command.h”,那么,kdb.o、command.o和files.o都会被重编译,并且,edit会被重链接。

四、makefile中使用变量

在上面的例子中,先让我们看看edit的规则:

      edit : main.o kbd.o command.o display.o /
                  insert.o search.o files.o utils.o
            cc -o edit main.o kbd.o command.o display.o /
                       insert.o search.o files.o utils.o

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

比如,我们声明一个变量,叫objects, OBJECTS, objs, OBJS, obj, 或是 OBJ,反正不管什么啦,只要能够表示obj文件就行了。我们在makefile一开始就这样定义:

     objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

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

    objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)
    main.o : main.c defs.h
            cc -c main.c
    kbd.o : kbd.c defs.h command.h
            cc -c kbd.c
    command.o : command.c defs.h command.h
            cc -c command.c
    display.o : display.c defs.h buffer.h
            cc -c display.c
    insert.o : insert.c defs.h buffer.h
            cc -c insert.c
    search.o : search.c defs.h buffer.h
            cc -c search.c
    files.o : files.c defs.h buffer.h command.h
            cc -c files.c
    utils.o : utils.c defs.h
            cc -c utils.c
    clean :
            rm edit $(objects)


于是如果有新的 .o 文件加入,我们只需简单地修改一下 objects 变量就可以了。

关于变量更多的话题,我会在后续给你一一道来。

五、让make自动推导

GNU的make很强大,它可以自动推导文件以及文件依赖关系后面的命令,于是我们就没必要去在每一个[.o]文件后都写上类似的命令,因为,我们的make会自动识别,并自己推导命令。

只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件。并且 cc -c whatever.c 也会被推导出来,于是,我们的makefile再也不用写得这么复杂。我们的是新的makefile又出炉了。

    objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)

    main.o : defs.h
    kbd.o : defs.h command.h
    command.o : defs.h command.h
    display.o : defs.h buffer.h
    insert.o : defs.h buffer.h
    search.o : defs.h buffer.h
    files.o : defs.h buffer.h command.h
    utils.o : defs.h

    .PHONY : clean
    clean :
            rm edit $(objects)

这种方法,也就是make的“隐晦规则”。上面文件内容中,“.PHONY”表示,clean是个伪目标文件。

关于更为详细的“隐晦规则”和“伪目标文件”,我会在后续给你一一道来。

六、另类风格的makefile

即然我们的make可以自动推导命令,那么我看到那堆[.o]和[.h]的依赖就有点不爽,那么多的重复的[.h],能不能把其收拢起来,好吧,没有问题,这个对于make来说很容易,谁叫它提供了自动推导命令和文件的功能呢?来看看最新风格的makefile吧。

    objects = main.o kbd.o command.o display.o /
              insert.o search.o files.o utils.o

    edit : $(objects)
            cc -o edit $(objects)

    $(objects) : defs.h
    kbd.o command.o files.o : command.h
    display.o insert.o search.o files.o : buffer.h

    .PHONY : clean
    clean :
            rm edit $(objects)

这种风格,让我们的makefile变得很简单,但我们的文件依赖关系就显得有点凌乱了。鱼和熊掌不可兼得。还看你的喜好了。我是不喜欢这种风格的,一是文件的依赖关系看不清楚,二是如果文件一多,要加入几个新的.o文件,那就理不清楚了。

七、清空目标文件的规则

每个Makefile中都应该写一个清空目标文件(.o和执行文件)的规则,这不仅便于重编译,也很利于保持文件的清洁。这是一个“修养”(呵呵,还记得我的《编程修养》吗)。一般的风格都是:

        clean:
            rm edit $(objects)

更为稳健的做法是:

        .PHONY : clean
        clean :
                -rm edit $(objects)

前面说过,.PHONY意思表示clean是一个“伪目标”,。而在rm命令前面加了一个小减号的意思就是,也许某些文件出现问题,但不要管,继续做后面的事。当然,clean的规则不要放在文件的开头,不然,这就会变成make的默认目标,相信谁也不愿意这样。不成文的规矩是——“clean从来都是放在文件的最后”。

上面就是一个makefile的概貌,也是makefile的基础,下面还有很多makefile的相关细节,准备好了吗?准备好了就来。

<-上一页  下一页->

(版权所有,转载时请注明作者和出处)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/136550.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JavaScript 设计模式之组合模式

    JavaScript 设计模式之组合模式引我们知道地球和一些其他行星围绕着太阳旋转,也知道在一个原子中,有许多电子围绕着原子核旋转。我曾经想象,我们的太阳系也许是一个更大世界里的一个原子,地球只是围绕着太阳原子的一个电子。而我身上的每个原子又是一个星系,原子核就是这个星系中的恒星,电子是围绕着恒星旋转的行星。一个电子中也许还包含了另一个宇宙,虽然这个宇宙还不能被显微镜看到,但我相信它的存在。也许这个想法有些异想天开,但在程序设计中,…

    2022年7月12日
    16
  • Navicat Premium 15激活码(最新序列号破解)

    Navicat Premium 15激活码(最新序列号破解),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月18日
    711
  • discuz php接口文档,Discuz二次开发手册.doc[通俗易懂]

    discuz php接口文档,Discuz二次开发手册.doc[通俗易懂]Discuz二次开发手册Discuz文件说明,有助于discuz爱好者,进行自己的开发,在这里提供方便admincp.php——后台系统设置主程序文件,一般只处理菜单的显示的访问权限,不处理管理控制。ajax.php——论坛模板的ajax判断及数据返回都在这里进行attachment.php——附件文件,仅仅处理附件下载的功能。announcement.php——论坛公告的显示,一般很少改con…

    2022年5月19日
    41
  • markdown语法大全(日语一共多少语法)

    最全的Markdown语法Markdown是Github最常见的文档说明。Markdown的语法简洁明了、学习容易。按照官方MarkdownCheatSheet逐个操作一遍自然就会了。[TOC]这个语法在markdown工具里能够识别,但是在这里不能识别。目录代码:文章目录一级标题##二级标题#####多级标题[MENU]效果显示如上多级标题代码:一级标题##二级标题#####多级标题效果一级标题二级标题多级标题引用与注释代码:一级引用>>二级引

    2022年4月15日
    72
  • 千分位的写法_千分位格式

    千分位的写法_千分位格式之前看到一道面试题,要求使用js写千分位,当时面试时有点懵逼,但是后来参考网上的写法与自己的思考,写出了千分位。以下是通过网上的代码,本人进行了进一步优化后的代码,仅供参考。相比较与网上的方法,我

    2022年8月2日
    5
  • MFC 键盘钩子「建议收藏」

    MFC 键盘钩子「建议收藏」一、前言一日,看见我妈正在用电脑练习打字,频频低头看键盘,我想:要是键盘能发音的话,不就可以方便她养成”盲打”的好习惯吗?光想不做可不行,开始行动(您可千万别急着去拿工具箱啊^_^)…按键能发音,其关键就是让程序能够知道当前键盘上是哪个键被按下,并播放相应的声音,自己的程序当然不在话下,那么其它程序当前按下哪个键如何得知呢?利用键盘钩子便可以很好地解决。下载本文的全部源代码大

    2022年6月7日
    56

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号