在GNU/Linux环境下, 使用make编译程序是个不错的选择. 较之IDE, make更灵活, 更健壮, 尤其对平台适应力强.  实际上, make在上实际七十年代就出现了, 它的年纪可比你我大许多. 许多大型项目(最著名的恐怕就是linux内核)都使用make进行管理.

在众多的make版本中, GNU make是最突出的, 它已成了当前的"标准"make. 所有的GNU/Linux平台上都有提供, 一些BSD的变种, Mac OS X甚至cygwin也都使用GNU Make. 所以选择GNU make学习, 编写makefile是不二选择.

关于GNU Make, 可以看看这篇文章 . 它摘录自 o'reilly的《GNU Make项目管理》, 这本书china-pub上有得卖, 薄薄280面, 定价却要¥58, 在此鄙视一下东南大学出版社

OK, 现在步入正题, 这里假设你使用C语言进行编程.

预备知识


首先我们必须具有一些预备知识: 你知道什么叫编译, 什么叫连接吗? 目标文件和可执行文件有什么区别? 一个C源程序是如何转化为可执行程序的? 以往的IDE往往对C初学者隐藏了这些基础概念. 要使用Make, 这些概念是要清楚的.

另外, 你需要对GNU/Linux上的编译器具有一定的了解——当然是gcc啦! 因为Makefile中的命令实际上是针对编译器的命令.

可以参考本人blog的这两篇文章:
GNU/Linux平台的C程序开发及程序运行环境 
GCC笔记

几个要说明的词汇 
目标(target): 在makefile指定要生成的目标,  它可以是可执行文件,  目标文件,  也可以只是一个标签.

先决条件(prerequisite): makefile中指定的针对要生成某个target所依赖的文件或标号.

命令(command): Make针对target利用makefile中指定的规则所调用的命令. 它可以是你在shell中能够指定的所有命令.

GNU Make的工作原理


Make 通过 makefile文件被告知它的工作: 要生成怎样的目标文件?  由哪些代码编译生成?所以学习GNU Make实际上就是学习Makefile的写法. 下面是一个简单的makefile:

hello: hello.c
    gcc hello.c -o hello

我们熟悉的hello程序,
$ make 
gcc hello.c -Wall -o hello

这样我们的hello可执行程序就出来了!

make的规则: 
target: prereq1 prereq2
    commands

target就是目标文件 , 它可能是,o文件, 可执行文件或标签中的一种.

关于target,有这样的约定: 
如果某target被包含在执行make的命令行参数中, 则更新该target; 如果make没带参数, 则将第一个target作为默认目标进行更新.

prerequisites是生成target所需要的文件.

command是make调用gcc执行的指令. 注意, command以Tab键打头 , 不能是空格!

到了这里, 就可以理解Make的原理了:

make的基本思想: 对于一个target (由命令行所指定或默认第一个target), 如果它不存在, 或者它的prerequisites中有比它更新的, 那么执行command所指定的命令.
所谓"更新", 是指比别的文件更晚被修改, make通过timestamp来记录谁更新.

makefile文件名


  1. 默认情况下, make命令会在当前目录下按顺序找寻文件名为“GNUmakefile”、“makefile”、“Makefile”的文件.

  2. 最好不要用“GNUmakefile”, 这个文件只被GNU make识别. 虽然有些Make只对全小写的“makefile”文件名敏感, 但大多数的make都支持“makefile”和“Makefile”这两种默认文件名.

  3. 可以使用别的文件名来书写makefile, 比如: "Make.Linux", “Make.Solaris”, “Make.AIX”等. 如果要指定特定的Makefile,你可以使用make的“-f”或者“--file”参数,如:make -f Make.Linux 或 make --file Make.AIX.

推荐以 Makefile 作为文件名!

命令行中调用Make命令


(1) $ make target-name
(2) $ make
(3) $ make non-exist-target
(4) $ make -n   or  $ make --just-print

(1) 如果在命令行中指定了target, 则make针对该target进行工作
(2) 如果未指定target, 则make对默认target进行操作.(Makefile中出现的第一个target)
(3) 如果指定的target不存在, 则make报错:

make: *** No rule to make target `non-exist-target'.  Stop.

(4) 若加上 -n 或者 --just-print选项, make只是列出将要执行的命令, 并不执行它们. 这非常有用!

Makefile 的基本语法


Makefile 采用自上而下 (top-down)的组织, 最开始的target即"终极目标", 也是默认target. 观察make输出的命令可以发现, 它们的顺序与出现在Makefile中的命令刚好相反. 可以把Makefile中针对target的规则想象成C函数. 最开始的是main(), 然后依次调用相关的函数(即针对prereq调用相关的规则).

看看一个比较简单的Makefile规则:

target1 target2 target3 : prereq1 prereq2
    command1
    command2

    command3

  • 第一行列出了targets和prereqs, 注意目标与它们依赖的文件之间以" : "分隔. 目标或prereq之间以空格分隔.

  • 在冒号左边可以有1个或多个targets, 在冒号右边可以有0个或者多个prerequisites. 如果prerequisite的数目为0, 则只有当对应的target不存在时才执行命令.

  • 如果command不和目标, 先决条件在一行,那么它之前必须以Tab开头; 如果command与目标, 先决条件在一行, 那么它要以";"开头. Make将command传递给子shell去执行.

 注意: 不要忘了在命令以Tab开头, 也别在不是命令开头的地方输入Tab, 否则Make会将它之后的字符当作命令.
  • Make中的注释符为 "#". #之前可以有空格, 从#开始到行尾的所有字符都会被忽略. 注意: 如果你把#写在了命令中, 包括#在内的行都会传递给shell, 会有什么样的结果取决于你所用的shell.

  • 可以在Makefile中使用转义字符 /, 我们都知道, 在命令行中, 可以使用 / 在下一行输入命令. 同样的, 在Makefile的所有行中, 都可以使用 / 来分割太长的语句.

学习GNU Make (1)(转)相关推荐

  1. 学习GNU Emacs命令速查表(三)

    博客地址:http://blog.csdn.net/shuxiao9058 原始作者:季亚 第八章简章的文字排版和特效编辑 表8-1:制表位命令速查表 键盘操作 命令名称 动作 (无) edit-ta ...

  2. linux arm 汇编学习,如何在LINUX平台上学习GNU ARM汇编

    本例说明如何在LINUX平台上学习GNU ARM汇编. 1.软件环境 vmware 5.0 + redhat 9.0 + skyeye 1.2.4 + arm-elf 工具 2. 源文件 a.s -- ...

  3. 学习GNU Make (2): 规则

    Makefile中指定了针对某个target的规则(rule). 注意Makefile中可以有多条规则: 即针对Makefile中的一条targets, prerequisites列表, 就有一条对应 ...

  4. ARM学习-GNU ARM汇编

    目录 1.GNU汇编语言语句格式 2.汇编程序中的标号symbol(或label) 3.GNU汇编程序中的分段 3.1 .section伪操作 3.2 汇编系统预定义的段名 4.GNU汇编语言定义入口 ...

  5. USRP调研及学习(GNU Radio)

    USRP(Universal Software Radio Peripheral,通用软件无线电外设)可以使普通计算机能像高带宽的软件无线电设备一样工作.从本质上讲,USRP充当一个无线电通讯系统的数 ...

  6. TQ2440开发板学习纪实(0.1)--- GNU Freestanding(Naked)C ARM交叉开发环境创建与测试

    0 由来 在我的博文 GNU ARM交叉汇编环境的搭建与测试中,详细讲解了GNU ARM汇编环境的创建与使用方法.实际开发中,直接使用汇编语言写的代码往往很少,尽在系统启动和性能要求极其苛刻的时候才会 ...

  7. 介绍使用 GNU Screen 的小技巧

    学习基本的 GNU Screen 终端复用技术,然后下载我们的终端命令备忘录,以便你能够熟悉常用的快捷方式. 学习基本的 GNU Screen 终端复用技术,然后下载我们的终端命令备忘录,以便你能够熟 ...

  8. 嵌入式系统开发-学习路线

    嵌入式系统开发 课程链接 随着嵌入式设备的普及,嵌入式应用的需求量也随之增大,本课程将重点培养基于linux系统下的嵌入式应用开发,包括5个阶段,其中课程涵盖了linux系统下的多进程.多线程嵌入式开 ...

  9. 让这世界再多一份GNU m4 教程 (全文整理)

    作者:garfileo  作者主页 本文整理自:https://segmentfault.com/a/1190000004104696 整理者:Timekeeperl    csdn博客 欢迎转载!请 ...

最新文章

  1. HDU-1268 找新朋友 (素数筛选)
  2. 这个GAN没见过猪,却能把狗变成猪
  3. Spark读取MySQL中的数据为DataFrame
  4. jBPM 流程设计器和查看【包括Web形式】的总结
  5. 128位java_求一个java算法,用128位密钥的AES加密128位明文,得出的密文还是128位...很着急,非常感谢各位大神,求救!...
  6. Python基础01-变量及数据类型
  7. Elasticsearch环境搭建和介绍(Windows)
  8. 热图绘制一个快乐五一
  9. 记录一次分组求和查询优化
  10. 使用mvc时,在视图view中使用强类型视图,在web.config文件中添加命名空间namespace的引用不起作用,解决方法...
  11. fedora 安装chrome
  12. 用亿图软件怎么画数据模型图?
  13. python httpserver 支持ipv6
  14. 怎么用爬虫筛选简历_筛选数据分析师简历全流程
  15. C++控制输出对齐---setw()函数
  16. 进入IT行业,你后悔过吗?
  17. golang做php的中间件,Golang 之 中间件
  18. vue 微信公众号定位+高德地图
  19. 尝试使用sklearn自动进行多模型预测并计算权重
  20. 2017美国计算机专业排名,2017年美国大学计算机专业排名TOP121

热门文章

  1. 一张图了解Spring Cloud微服务架构
  2. EOS Keosd概述
  3. 设计模式系列之「观察者模式」
  4. VS Code创建C项目
  5. M283-bsp包问题
  6. js或jquery如何获取父级、子级、兄弟元素(包括祖级、孙级等)
  7. 一个worker thread服务一个客户端
  8. 将数据库中一张表中数据复制到另一张表
  9. 串口速度,RS232与MAX232的区别
  10. 限制Nagios报警次数