Makefile是由一系列的rule规则组成,这些rule都遵循以下形式:

target ... : prerequisites ...

    command

    ...

    ...

target(目标)

一般来说是需要生成的程序(模块)的名字,也可以是要执行的动作的名字,这种情况叫做(Phony Target)

prerequisites(依赖)

用于生成target,一个target一般会依赖于多个文件

command(命令)

由make来执行的动作,一个规则下可以包含多个command,需要注意的一点是command前必须有一个tab用于区分command所在的行与Makefile的其他行

rule

表明了如何(command)以及何时(prerequisites)生成指定文件(target)。一旦prerequisites新加入到工程或者更新后,则会调用command来生成target。

rule的形式是以prerequisites为原料并通过调用command来生成target文件。不过并不是所有的target都是文件,在这种情况下就不需要prerequisites了(如make clean)。

Makefile可能会包含除了rule以外的其他文本,不过再复杂的Makefile,rule都是其核心部分。

以下有个简单的Makefile,我们可以对他展开分析:

edit : main.o kdb.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 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 utiles.c clean :
rm edit main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

在该Makefile中,

  • target                 有edit,main.o等各种“.o”文件,最后还有clean
  • prerequisites       有main.c等各种“.c”文件,defs.h等各种“.h”文件,以及main.o等各种“.o”文件
  • command            有cc -o ..., cc -c ...等命令

当prerequisites文件被改变的时候,会重新调用command来生成新的target。command表明该如何由prerequisites生成新的target文件。但是实际上make并不知道command所做的是什么动作,因为command都是shell命令,最终会由shell调用,因此理论上command可以是任何的shell命令。

在Makefile中,clean不是一个文件,而仅仅是一个动作的名字。由于clean不是其他target的prerequisites,因此除非你手动指定make来调用clean(make clean),否则它不会被调用。另外,由于clean也没有任何的prerequisites,因此调用clean只会执行到其下方的command,这种只为执行某种动作的target叫做phony target。

make如何处理Makefile

对于上方的那个简单Makefile,当我们敲make的时候,make会首先确定Makefile的goal(目标),默认goal就是该Makefile文件中第一个不包含‘.’前缀的target,即edit。

但是make不会立即去执行edit下的command,因为它的rule规定了edit依赖于它的.o,而.o文件的rule又规定了它们依赖于.h,.c文件,因此会先由.c文件先生存.o文件,后再由.o文件生成edit。

clean这种不在edit分支内的target则需要手动执行(make clean)。

command只在特定情况下才会被执行:

  • target文件不存在
  • prerequisites文件时间比target文件新

使Makefile更简洁

1.使用变量

上方的Makefile在edit的prerequisites处列出来一串.o文件,并且需要在command中再次列出来。这种长列表的重复会带来维护艰难的问题。因此可以用变量来取代长列表。变量允许一次定义,多次调用。

对于上方的.o长串,可以写成如下方式:

objects = main.o kbd.o command.o display.o \

              insert.o search.o files.o utils.o

在需要调用的时候写成“$(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)

2.让make推导command

make有一条隐性规则:由.c文件生成相应文件名的.o文件所用的command “cc -c”可以省略,因为make可以自动识别并调用该command。

.c文件也可以省略,因为make会自动加载.o相应的.c文件到prerequisites。

因此,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 command.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 .PHOMY : clean
clean :
rm edit $(objects)

3.multi target one prerequisites

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

但是这种方式相对于上面的one target multi prerequisite 的方式没那么直观。可以根据自己喜好选择。

clean 的方式

clean有两种写法:

1.

clean :
rm edit $(objects)

一般我们都采用这种方式,但是这会引起一个问题,如果存在一个clean文件的话,那么make clean会被混淆,以实际存在的clean文件为target来执行,而不会去rm。所以下面这种方式就是避免了这种问题而存在的。

2.

.PHONY : clean

   clean :
rm edit $(objects)

.PHONY声明了clean是一个虚拟的目标,并不包含实际文件,当执行make clean时就会把clean当做虚拟目标来执行,不会影响实际存在的文件。

另外需要注意的是,不要把clean写在Makefile的开头,因为我们一般不会把clean当做Makefile的默认goal

GNU Make chapter 2 —— Makefile 介绍的更多相关文章

  1. GNU autotools自动生成Makefile 介绍

    一.目的 使用autotools工具来帮助我们自动地生成符合自由软件惯例的makefile(这样就可以像常见的GNU程序一样,只要使用"./configure", "ma ...

  2. 跟我一起写Makefile:MakeFile介绍

    makefile 介绍 make命令执行时,需要一个 makefile 文件,以告诉make命令如何去编译和链接程序. 首先,我们用一个示例来说明makefile的书写规则.以便给大家一个感性认识.这 ...

  3. (转)Makefile介绍

    2. Makefile介绍 make命令执行时,需要一个Makefile文件,以告诉make命令需要怎么样的去编译和链接程序. 首先,我们用一个示例来说明Makefile的书写规则.以便给大家一个感性 ...

  4. [转] Makefile 基础 (1) —— Makefile 介绍

    该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...

  5. Makefile 介绍

    makefile:是告诉编译器(交叉工具链)如何去编译.链接一个工程的规则.   一.概述 什 么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为 ...

  6. GNU C 内联汇编介绍

    GNU C 内联汇编介绍 简介 1.很早之前就听说 C 语言能够直接内嵌汇编指令.但是之前始终没有去详细了解过.最近由于某种需求,看到了相关的 C 语言代码.也就自然去简单的学习了一下如何在 C 代码 ...

  7. 一个简单的执行程序的GNU automake自动生成Makefile的方法及案例

    一个简单的执行程序的GNU automake自动生成Makefile的方法及案例 在GNU的世界里,存在Automake这样的工具进行自动生成Makefile文件,automake是由Perl语言编写 ...

  8. 第一篇 make与makefile介绍

    我们在Linux系统中学习C语言或者C++语言时,大多数时候只是用gcc命令或者g++命令在命令行进行简单的编译.链接即可得到最终的可执行文件,进一步即可验证所写C/C++语言的正确性.但是,在大型工 ...

  9. make和makefile介绍

    <strong>先附上一个比较简单的,测试代码用的Makefile</strong> </pre><pre code_snippet_id="463 ...

随机推荐

  1. vs2008 多人同时开发项目时的代码注释规范格式 分类: C#小技巧 2014-04-23 14:12 297人阅读 评论(0) 收藏

    多人同时开发一个项目,区分项目的那个窗体是谁开发的,例:下面的格式 /************************************************       模块:服务器设置   ...

  2. LinearLayout增加divider分割线

    在android3.0及后面的版本在LinearLayout里增加了个分割线 1 2 android:divider="@drawable/shape"<!--分割线图片-- ...

  3. 给想上MIT的牛学生说几句

    [来信] 老师您好! 非常冒昧的来打搅您,仅仅是在学习上实在有些困惑才来向您求教一番. 我是计算机科学与技术的大一学生,我非常喜欢我自己的专业,可是学校里讲的东西太慢,太浅,所以我一般都是自学,我在自 ...

  4. FACTORY设计模式【让吃货也能理解的程序】

    一个人要有思想,技术再牛的人,如果没有一点点文化气氛,那么也是个码农,不能追到女朋友滴. 我这个人文化真心不多,但是比较喜欢读古诗文.虽然读完之后,记在脑海里的不多,不过,就讨一个喜欢[读]. Lee ...

  5. Qt 学习之路:视图选择 (QItemSelectionModel)

    选择是视图中常用的一个操作.在列表.树或者表格中,通过鼠标点击可以选中某一项,被选中项会变成高亮或者反色.在 Qt 中,选择也是使用了一种模型.在 model/view 架构中,这种选择模型提供了一种 ...

  6. [转] 用PDB库调试Python程序

    Python自带的pdb库,发现用pdb来调试程序还是很方便的,当然了,什么远程调试,多线程之类,pdb是搞不定的. 用pdb调试有多种方式可选: 1. 命令行启动目标程序,加上-m参数,这样调用my ...

  7. Http API设计

    Heroku团队根据heroku platform api和他们自己内部系统的实践经验总结了一些http api设计的准则,发布到了github上. 地址:https://github.com/int ...

  8. servlet 配置到服务器

    最近写了个安卓项目,服务端用的servlet.因为第一次写java项目,写完如何发布不是太清除,于是把这回经理写出来,一来做个记录,二来也给和我同样经历的朋友一点启示. 首先配置你的java主机和你的 ...

  9. vertical-align各属性对比

    测试用代码 <!DOCTYPE html> <html> <head> <style> #dd { //line-height: 300px; back ...

  10. ASP.NET 日志

    ASP.NET5已经内建集成了日志系统,你也可以用第三方的日志框架. 1. 在你的应用程序中实现日志 在Startup.cs文件中,在Configure里可以把ILoggerFactory注入进去,然 ...