一、Makefile的基本规则

GNU make 规则:

target ... : prerequisites ...
    command
    ....
    ....

target —
目标文件, 可以是Object File 也可以是可执行文件,还可也是标签Label(标签内容在“伪目标”章节);

prerequisites—生成target所需的文件或目标;

command—make需要执行的命令,可以是任何shell命令。

二、一个简单的例子

创建一个名为count_word.c的文件,代码如下

  1. #include <stdio.h>
  2. extern int fee_count, fie_count, foe_count, fum_count;
  3. extern int yylex( void );
  4. int main( int argc, char ** argv ){
  5. yylex( );
  6. printf( "%d %d %d %d\n", fee_count, fie_count, foe_count, fum_count );
  7. return( 0 );
  8. }

另外创建一个lexer.l文件,其中所有的空白均为tab键

  1. int fee_count = 0;
  2. int fie_count = 0;
  3. int foe_count = 0;
  4. int fum_count = 0;
  5. %%
  6. fee     fee_count++;
  7. fie     fie_count++;
  8. foe     foe_count++;
  9. fum     fum_count++;

最后创建makefile文件,内容为:

  1. count_words: count_words.o lexer.o -lfl
  2. gcc count_words.o lexer.o -lfl -o count_words
  3. count_words.o: count_words.c
  4. gcc -c count_words.c
  5. lexer.o: lexer.c
  6. gcc -c lexer.c
  7. lexer.c: lexer.l
  8. flex -t lexer.l > lexer.c
  9. clean:
  10. rm lexer.c lexer.o count_words.o count_words

以上内容保存在Makefile或者是makefile都可以,直接输入make命令就可以生成可执行文件count_words了;

gcc -c count_words.c
flex -t lexer.l > lexer.c
gcc -c lexer.c
gcc count_words.o lexer.o -lfl -o count_words

如果要删除执行文件和中间的目标文件,那么就执行一下make
clean。



注意1: 当依赖关系定好后,下面一行就是如何生成目标文件的操作系统命令了,一定要以一个Tab键开头。 另外,make会比较targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期比targets文件新,或者targets不存在,那么make就会执行这下面一行的系统命令。

注意2: clean不是一个文件,它是一个动作名,冒号后面什么都没有,make就不会自动去找它的依赖性,也不会执行它后面的系统命令。因此,要执行clean就需要显式的指出make clean。

注意3: 如果报错,可能需要先安装flex:

[plain] view
plain
copy

  1. sudo apt-get install flex

注意4: 运行count_works后,它会回显你的输出并统计'fee','fie','foe','fum'的次数。结束统计需要按Ctrl+d,然后会输出四个单词出现的次数。

三、make 如何工作

默认方式

直接输入make,则

  1. make会在当前的目录下找到名为“Makefile”或者“makefile”的文件。
  2. 如果找到,它会把文件中第一个target作为最终的目标文件(如上面例子中的count_words)。
    1. 首先,make会检查目标count_words的prerequisite文件count_words.o, lexer.o 和 -lfl。
    2. count_words.o通过编译count_words.c生成
    3. lexer.o通过编译lexer.c 生成,但是lexer.c 并不存在,因此会继续寻找lexer.c的生成方式,并找到了通过flex程序将lexer.l生成为lexer.c。
    4. 最后,make会检查-lfl,-l是gcc的一个命令选项,表示将系统库链接到程序。而"fl"对应的是libfl.a的库。(GNU make 可以识别这样的命令,当一个prerequisite是以这种-l<name>的形式表示出来的时候,make会自己搜索lib<name>.so的库文件,如果没找到则继续搜索lib<name>.a的库文件)。这里make找到的是/usr/lib/libfl.a文件,并将它与程序进行连接。
  3. 如果count_words文件不存在,或者count_words所依赖的后面的.o文件的修改时间比count_words本身更加新,那么,它会执行后面定义的命令来生成这个count_words文件。如果count_words所依赖的.o文件也不存在,那么make会继续按照前面的方式生成.o文件。
  4. 找到相应的.c和.h,用来生成.o,然后再用.o完成make的最终任务。

关于依赖关系

make会一层一层的去找文件的依赖关系,最终编译出第一个目标文件。

关于重新编译

只要任何prerequisite 比 target新,那么这个目标文件就会被下面的命令重新生成。每一个命令都会被传递到shell中,并在自己的子shell里面执行。

关于错误

如果在寻找过程中出现错误,如文件找不到,则make会直接退出并报错。对于所定义的命令错误或者编译不成功,make是不会理会的,它只负责文件的依赖性。

四、变量使用

上面的例子可以看到,文件或者目标的名字几乎都毫无例外的出现了至少两次,甚至如果算上clean的内容,有些文件名出现了三次。然而,在一个大型的工程中这种情况会更加复杂,任何不经意的错误都会导致编译失败。为了让makefile更容易维护,在makefile中我们可以使用变量,或者更确切的说是一个字符串,类似c语言中的宏。例如:

  1. CC = gcc
  2. object = lexer.o count_words.o
  3. count_words: $(object) -lfl
  4. $(CC) $(object) -lfl -o count_words
  5. count_words.o: count_words.c
  6. $(CC) -c count_words.c
  7. lexer.o: lexer.c
  8. $(CC) -c lexer.c
  9. lexer.c: lexer.l
  10. flex -t lexer.l > lexer.c
  11. clean:
  12. rm lexer.c $(object) count_words

五、自动推导依赖关系

GNU make可以根据.o文件的文件名自动推导出同名的.c文件并加入依赖关系,不需要我们手动注明。并且gcc -c也会被自动推导出来,于是我们的makefile就变成了

  1. CC = gcc
  2. object = lexer.o count_words.o
  3. count_words: $(object) -lfl
  4. $(CC) $(object) -lfl -o count_words
  5. count_words.o:
  6. lexer.o:
  7. lexer.c: lexer.l
  8. flex -t lexer.l > lexer.c
  9. clean:
  10. rm lexer.c $(object) count_words

这种方法也叫“隐式规则”。

六、关于Clean

一个好习惯是每个makefile都要写clean规则,这样不仅可以方便重编译,也有利于保持文件路径的清洁。一般的风格是:

  1. clean:
  2. rm lexer.c $(object) count_words

但是,更为稳妥的做法是:

  1. .PHONY: clean
  2. clean:
  3. -rm lexer.c $(object) count_words

.PHONY表示clean是一个“伪目标”,而rm命令前面的减号则表示,不管出现什么问题都要继续做后面的事情。

注意:clean规则不要放在makefile的开头,不然就会变成make的默认目标了。

makefile 学习(一)的更多相关文章

  1. [转]Windows平台下Makefile学习笔记

    Windows平台下Makefile学习笔记(一) 作者:朱金灿 来源:http://blog.csdn.net/clever101 决心学习Makefile,一方面是为了解决编译开源代码时需要跨编译 ...

  2. makefile 学习归纳

    makefile 学习归纳 一直希望 好好整理下 makefile的写法,这在linux编程界是必备技能.下面就好好的说道说道. 可以参考的大神总结 整理 makefile是供make命令执行的 脚本 ...

  3. <转>Windows平台下Makefile学习笔记(二)

    本文转自:http://blog.csdn.net/clever101/article/details/8286066 上次我们学习了怎么用Makefile编译一个控制台工程.这次我们学习一下如何使用 ...

  4. makefile学习(1)

    GNU Make / Makefile 学习资料 GNU Make学习总结(一) GNU Make学习总结(二) 这篇学习总结,从一个简单的小例子开始,逐步加深,来讲解Makefile的用法. 最后用 ...

  5. (二)我的Makefile学习冲动&&编译过程概述

    前言 一 年轻的冲动 二 学习曲线 1 Makefile基本语法 2 bash基础 3 world 三 编译过程概述 1 主机预装工具 2 编译host工具 3 编译交叉工具链 4 编译内核模块 5 ...

  6. Makefile学习笔记

    ls -l 查看文件详细信息 1.gcc -E test.c -o test.i//预编译gedit test.i //查看:高级C 2.gcc -Wall -S test.i -o test.s// ...

  7. makefile学习笔记(多目录嵌套调用、变量使用)

    http://blog.csdn.net/leexiang_han/article/details/9274229   学习了几天的makefile的嵌套调用编写也有一些心得,先声明,我也是初学者写文 ...

  8. Makefile学习(一)变量

    鉴于之前有一些了解,还有自己的学习习惯,我一上来就看Makefile的变量这一章.主要脉络是根据GNU make中文手册. 第六章:Makefile中的变量 6使用变量 定义:变量是一个名字,代表一个 ...

  9. makefile 学习一

    近期在学习nginx,由于实在linux下,一些代码须要用makefile文件来编译,比較节省时间. 由于在nginx中加入一个新的模块假设用./configure方法来加入,特别是当你的代码有错时, ...

  10. Makefile学习总结

    Makefile用法分析     在linux开发中,应用程序的编译基本都采用GNU的make工具,而make搭配Makefile来实现工程代码的编译,在越是大型复杂的项目中,make的强悍之处越是明 ...

随机推荐

  1. thinkphp在为图片添加png水印不足的处理

    thinkphp在为图片加水印的时候.如果水印图片是png图片,透明度处理很不理想,与是做以下处理 在Image.class.php中新增 static function imagecopymerge ...

  2. 验证视图状态 MAC 失败

    起因: 最近在做一个项目需要用到生成多个Html页,采用一下方法动态生成. WebRequest request = WebRequest.Create(pageurl); WebResponse r ...

  3. 黄聪:WebBrowser执行和安装jQuery脚本(IEBrowse)

    上一文章说明了如何让 js 脚本访问 .NET 中的类, 这次希望给大家说明一下在任意页面中安装 jQuery 脚本, 并操作页面上的元素. 其实在第一篇关于 IEBrowser 的文章当中, 已经有 ...

  4. 6. redis持久化,认证

    一. RDB 快照持久化 (默认) rdb机制,在满足redis.conf中配置的持久化策略后, 自动持久化数据, 默认存储在dump.rdb文件中 策略 : save 900 1 : 900秒内,一 ...

  5. BIP_开发案例06_以RB.RDF为数据源BIP.RTF为模板的简单例子(案例)

    2014-05-31 Created By BaoXinjian

  6. POJ 3261 Milk Patterns (求可重叠的k次最长重复子串)+后缀数组模板

    Milk Patterns Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 7586   Accepted: 3448 Cas ...

  7. 51nod 1120 机器人走方格 V3 卡特兰数 lucas定理

    N * N的方格,从左上到右下画一条线.一个机器人从左上走到右下,只能向右或向下走.并要求只能在这条线的上面或下面走,不能穿越这条线,有多少种不同的走法?由于方法数量可能很大,只需要输出Mod 100 ...

  8. RabbitMQ介绍2 - AMQP协议

    这一节介绍RabbitMQ的一些概念,当然也是AMQP协议的概念.官方网站也有详细解释,包括协议的命令: http://www.rabbitmq.com/tutorials/amqp-concepts ...

  9. C++模板元编程 - 1 基本数据类型和运算

    这是博客开通前几天做的,C++的模板没办法存方便的浮点数,算了. 基本类型的设计参考了vczh轮子叔模仿boost的MPL的设计. 话说template和typename写多了真是无限烦人啊,不得已定 ...

  10. C语言中,数组名作为参数传递给函数时,退化为指针

    C语言中,数组名作为参数传递给函数时,退化为指针   C语言中,数组名作为参数传递给函数时,退化为指针:需要数组大小时, 需要一个参数传数组名,另一个传数组大小. 数组名做函数参数时,就相当于指针了. ...