1. 目标 依赖 命令

make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的话,那么,make就会执行后续定义的命令。

2. 示例一

在Makefile中的命令,必须要以[Tab]键开始。

#include<stdio.h>
#include"add.h" int main()
{
int result=0;
result = add(2, 3);
printf("2+3=%d\n", result);
}
main: main.o add.o
gcc -o main main.o add.o
main.o : main.c add.h
gcc -c main.c
add.o : add.c add.h
gcc -c add.c
clean:
rm *.o

在默认的方式下,也就是我们只输入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了。

3. 示例二(变量申明)

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

 4. 自动推导,隐晦规则

只要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)

5.

GNU的make工作时的执行步骤入下:(想来其它的make也是类似)

    1、读入所有的Makefile。

    2、读入被include的其它Makefile。

    3、初始化文件中的变量。

    4、推导隐晦规则,并分析所有规则。

    5、为所有的目标文件创建依赖关系链。

    6、根据依赖关系,决定哪些目标要重新生成。

    7、执行生成命令。

当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。

VPATH = src:../headers

上面的的定义指定两个目录,“src”和“../headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)

%.c是GUNmake语法层,表示的是所有以".c"结尾的文件,而*.c则是linux shell 语法层的,比如:rm -f *.o 类似的。

objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@

上面的例子中,指明了我们的目标从$object中获取,“%.o”表明要所有以“.o”结尾的目标,也就是“foo.o bar.o”,也就是变量$object集合的模式,而依赖模式“%.c”则取模式“%.o”的“%”,也就是“foo bar”,并为其加下“.c”的后缀,于是,我们的依赖目标就是“foo.c bar.c”。而命令中的“$<”和“$@”则是自动化变量,“$<”表示所有的依赖目标集(也就是“foo.c bar.c”),“$@”表示目标集(也就是“foo.o
bar.o”)。于是,上面的规则展开后等价于下面的规则:

foo.o : foo.c
$(CC) -c $(CFLAGS) foo.c -o foo.o
bar.o : bar.c
$(CC) -c $(CFLAGS) bar.c -o bar.o

有些时候,命令的出错并不表示就是错误的。例如mkdir命令,我们一定需要建立一个目录,如果目录不存在,那么mkdir就成功执行,万事大吉,如果目录存在,那么就出错了。我们之所以使用mkdir的意思就是一定要有这样的一个目录,于是我们就不希望mkdir出错而终止规则的运行。

为了做到这一点,忽略命令的出错,我们可以在Makefile的命令行前加一个减号“-”(在Tab键之后),标记为不管命令出不出错都认为是成功的。如:

clean:

-rm -f *.o

6. 定义命令包

如果Makefile中出现一些相同命令序列,那么我们可以为这些相同的命令序列定义一个变量。定义这种命令序列的语法以“define”开始,以“endef”结束,如:

define run-yacc
yacc $(firstword $^)
mv y.tab.c $@
endef

这里,“run-yacc”是这个命令包的名字,其不要和Makefile中的变量重名。在“define”和“endef”中的两行就是命令序列。这个命令包中的第一个命令是运行Yacc程序,因为Yacc程序总是生成“y.tab.c”的文件,所以第二行的命令就是把这个文件改改名字。还是把这个命令包放到一个示例中来看看吧。

foo.c : foo.y
$(run-yacc)

我们可以看见,要使用这个命令包,我们就好像使用变量一样。在这个命令包的使用中,命令包“run-yacc”中的“$^”就是“foo.y”,“$@”就是“foo.c”(有关这种以“$”开头的特殊变量,我们会在后面介绍),make在执行命令包时,命令包中的每个命令会被依次独立执行。

如何编写 Makefile的更多相关文章

  1. 如何自己编写Makefile

    如何自己编写Makefile   相信很多朋友都有过这样的经历,看着开源项目中好几页的makefile文件,不知所云.在日常学习和工作中,也有意无意的去回避makefile,能改就不写,能用ide就用 ...

  2. 教会你如何编写makefile文件

    最近一直在学习makefile是如何编写的.当我们写的程序文件比较少的时候,敲入gcc /g++,当你在大型工程中,在一个个编译文件的话,你可能就会很郁闷.linux有一个自带的make命令,它让你的 ...

  3. 如何编写makefile

    一:Makefile介绍: Makefile是为自动化编译而生.我们写好makefile文件后,只需要一个make命令,就可以完成整个项目的编译工作,大大提高了开发效率. 也许刚开始学习编程时,你不会 ...

  4. 如何编写Makefile,一份由浅入深的Makefile全攻略

    本文转载整理自陈浩大大的文章(跟我一起写 Makefile),由于原文内容庞大,故梳理出目录结构以便于学习及查阅参考. 一.概述 —— 什么是makefile?或许很多Winodws的程序员都不知道这 ...

  5. 如何编写makefile文件

    最近一直在学习makefile是如何编写的.       当我们写的程序文件比较少的时候,敲入gcc /g++,当你在大型工程中,在一个个编译文件的话,你可能就会很郁闷.linux有一个自带的make ...

  6. 根据给定文件编写Makefile文件 两种方法编译

    实例一 1.分析源文件代码依赖关系 mian.c #include "test1.h" #include "test2.h" #include <stdi ...

  7. 转:教会你如何编写makefile文件

    最近一直在学习makefile是如何编写的.当我们写的程序文件比较少的时候,敲入gcc /g++,当你在大型工程中,在一个个编译文件的话,你可能就会很郁闷.linux有一个自带的make命令,它让你的 ...

  8. Linux下编写 makefile 详细教程

    原文地址: https://www.cnblogs.com/mfryf/p/3305778.html 近期在学习Linux下的C编程,买了一本叫<Linux环境下的C编程指南>读到make ...

  9. 如何编写Makefile?

    //swap.c #include<stdio.h> int swap(int *x,int *y) {printf("a=%d b=%d\n",*x,*y); int ...

  10. 为多个文件夹下的C源代码编写Makefile文件

    上一篇文章写了如何为在同一个文件夹下的C源代码,本篇文章为多个文件夹下的C源代码编写Makefile文件. 建立两个文件夹,分别为abs与src.其最终目录结构如下: 1 $ ls * 2 jun.c ...

随机推荐

  1. boost::lockfree::spsc_queue

    #include <boost/thread/thread.hpp> #include <boost/lockfree/spsc_queue.hpp> #include < ...

  2. POJ1751 Highways

    题目链接    http://poj.org/problem?id=1751 题目大意:输入n:然后给你n个点的坐标(任意两点之间皆可达):输入m:接下来m行每行输入两个整数x,y表示 点x与点y 已 ...

  3. On the fly test

    on the fly test就是边开发边测试的意思.test code不是早就生成好的,在一边生成code的同时一边做test running,最大的好处是,flexiable ,每一次可以选择不同 ...

  4. Springboot 热部署中存在冲突的问题

    SpringBoot热部署有2中: 1.使用 Spring Loaded 2.使用 spring-boot-devtools 具体怎么用.自己百度! 在使用第一种时候,整合SpringBoot和通用M ...

  5. PHP定界符{}的作用

    说明: PHP解析一个字符串为"Hello,$World"时会自动解析$World. {}是方便让PHP更快的查找,它告诉PHP这里面就是变量,不用再判断是否是变量了. 例子: $ ...

  6. javascript之冒泡排序

    Array.prototype.bubble = function () { var temp; //第1轮比较求第一,第二轮求第二,以此类推(i<=数组成员的个数); for (var i = ...

  7. 让VisualStudio Profiler捕捉执行的sql语句

    启动Profiler之前设置一下Targets的属性就行,图中有说明.

  8. linux下查看cpu,内存,硬盘等硬件信息的方法

    说明:Linux下可以在/proc/cpuinfo中看到每个cpu的详细信息.但是对于双核的cpu,在cpuinfo中会看到两个cpu.常常会让人误以为是两个单核的cpu. 一.linux CPU大小 ...

  9. Could not create ServerSocket on address 0.0.0.0/0.0.0.0:9083

    遇到这种情况大家都找不到头绪,是因为你开始运行了hive的metastore,可以输入jps 然后出现如下: 红线所示就是hive metastore的进程 为了重新启动,需要把这个进杀掉: kill ...

  10. sql server扫盲系列

    本系列为入门级,不会介绍过于深入的知识.为防止不道德转载(特别是红黑联盟,把我原文地址删掉,其他照搬,无节操无道德),尽可能打上水印和加上原文地址,读者看的不爽请见谅.原文地址:http://blog ...