http://blog.csdn.net/ghostyu/article/details/6866863

在我前一篇写的【 linux驱动学习(一)Makefile基础】中,Makefile写的中规中矩,其实Makefile写法很灵活,可以写得很简洁,而且减少出错的可能,现在就把之前写的Makefile改进一下。

  1. main: main.o hello.o word.o
  2. gcc main.o hello.o word.o -o main
  3. main.o:main.h hello.h word.h
  4. hello.o:hello.h
  5. word.o:word.h
  6. clean:
  7. echo "cleanning project"
  8. -rm main *.o
  9. echo "clean completed"
  10. .PHONY:clean
main: main.o hello.o word.o
gcc main.o hello.o word.o -o main main.o:main.h hello.h word.h
hello.o:hello.h
word.o:word.h clean:
echo "cleanning project"
-rm main *.o
echo "clean completed" .PHONY:clean

这是不是比以前简单多了,但是main.o hello.o word.o这三个目标的编译命令都没有,怎么会编译呢,执行make试试看

  1. <localhost.localdomain:/data/ghostyu/linuxc> make
  2. cc    -c -o main.o main.c
  3. cc    -c -o hello.o hello.c
  4. cc    -c -o word.o word.c
  5. gcc main.o hello.o word.o -o main
  6. <localhost.localdomain:/data/ghostyu/linuxc>
<localhost.localdomain:/data/ghostyu/linuxc> make
cc -c -o main.o main.c
cc -c -o hello.o hello.c
cc -c -o word.o word.c
gcc main.o hello.o word.o -o main
<localhost.localdomain:/data/ghostyu/linuxc>

cc是什么呢,执行下which cc


  1. <localhost.localdomain:/data/ghostyu/linuxc> which cc
  2. /usr/bin/cc
<localhost.localdomain:/data/ghostyu/linuxc> which cc
/usr/bin/cc

事实上cc指向的也是gcc

其实,这是Makefile的内建隐含规则,然后make时,调用这些隐含规则。

  1. # default
  2. OUTPUT_OPTION = -o $@
  3. # default
  4. CC = cc
  5. # default
  6. COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
  7. %.o: %.c
  8. #  commands to execute (built-in):
  9. $(COMPILE.c) $(OUTPUT_OPTION) $<
# default
OUTPUT_OPTION = -o $@ # default
CC = cc # default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c %.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<

以上是内建规则中关于隐含规则的部分

‘#’为注释符,跟‘//’一样

‘CC’为Makefile变量

'$@'与‘$<’为特殊变量,'$@'的取值为规则的目标,‘$<’取值为规则的第一个条件。

%.o: %.c是一种特殊的规则,称为模式规则(Pattern Rule)。
CFLAG CPPFLAG TARGET_ARCH未定义,展开为空,

现在来分析一下,隐含规则是怎样解析Makefile的。

首先,OUTPUT_OPTION是一个变量,

  1. OUTPUT_OPTION = -o $@
OUTPUT_OPTION = -o $@

这边变量展开为:“-o main.o”

其次,展开COMPILE变量

  1. # default
  2. COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

为:“cc    -c”。中间有四个空格。

然后

  1. %.o: %.c
%.o: %.c

这就相当于 main.o:main.c

最后

  1. $(COMPILE.c) $(OUTPUT_OPTION) $<
        $(COMPILE.c) $(OUTPUT_OPTION) $<

注意开头的空白为tab键,8个字符,这是Makefile规定的,gcc命令等必须tab开头识别

展开为:

  1. cc    -c -o main.o main.c
        cc    -c -o main.o main.c

完整的:

  1. main.o:main.h hello.h word.h
  2. main.o:main.c
  3. cc    -c -o main.o main.c
main.o:main.h hello.h word.h
main.o:main.c
cc -c -o main.o main.c

这就隐含的包含了各个条件的编译

注意:上面之所以可以写成两行,是应为条件并不是一定要写在一行,可以分开写,但只能存在一条命令:

比如下列:

  1. main.o: main.c main.h hello.h word.h
  2. gcc -c main.c
main.o: main.c main.h hello.h word.h
gcc -c main.c

可以写成:

  1. main.o:main.h hello.h word.h
  2. main.o:main.c
  3. gcc -c main.c
main.o:main.h hello.h word.h
main.o:main.c
gcc -c main.c

写规则的目的是让make建立依赖关系图,不管怎么写,只要把所有的依赖关系都描述清楚了就行。


****************************Makefile 变量**************************
  1. var = $(gho)
  2. gho = yu
  3. all:
  4. @echo $(var)
var = $(gho)
gho = yu all:
@echo $(var)

make all时,输出 yu

  1. <localhost.localdomain:/data/ghostyu/linuxc/test> make all
  2. yu
<localhost.localdomain:/data/ghostyu/linuxc/test> make all
yu

这就是Makefile中的变量,与TCL脚本的变量很类似

之所以输出yu 而非 gho,是因为‘=’不用立即展开,若果在第一等号前加‘:’,试试。
  1. <PRE style="BACKGROUND-COLOR: rgb(240,240,240); MARGIN: 4px 0px" class=plain name="code">var := $(gho)
  2. gho = yu
  3. all:
  4. @echo $(var)</PRE>
  5. <PRE></PRE>
  6. <PRE></PRE>
  7. <PRE></PRE>
  1. var := $(gho)
  2. gho = yu
  3. all:
  4. @echo $(var)
var := $(gho)
gho = yu all:
@echo $(var)
这样make all 后输出为空,这是因为var:=$(gho),遇到‘:’将立即展开,gho此时又为定义,因此输出空,若gho=yu放在前面,则依然输出yu
还有一个比较有用的赋值运算符是?=,例如var ?= $(gho)的意思是:如果var没有定义过,那么?=相当于=,定义var的值是$(gho),但不立即展开;如果先前已经定义了var,则什么也不做,不会给var重新赋值。

+=运算符可以给变量追加值
  1. var = main.o
  2. var += $(gho)
  3. gho = hello.o word.o
var = main.o
var += $(gho)
gho = hello.o word.o

这是var的值为 main.o hello.o word.o

常用的特殊变量有四个,出去之前用的$@与$<,还有$? 和$^
  • $@,表示规则中的目标。

  • $<,表示规则中的第一个条件。

  • $?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。

  • $^,表示规则中的所有条件,组成一个列表,以空格分隔。

因此

  1. main: main.o hello.o word.o
  2. gcc main.o hello.o word.o -o main
main: main.o hello.o word.o
gcc main.o hello.o word.o -o main

可以改写为:

  1. main: main.o hello.o word.o
  2. gcc $^ -o $@
main: main.o hello.o word.o
gcc $^ -o $@

这样的好处是,即使以后又往条件里加了新的目标,编译命令也不需要修改,既省事,又减少出错。

$?也很有用,有时候希望只对更新过的条件进行操作。

之前我们看到make的隐含规则数据库中用到了很多变量,有些变量没有定义(例如CFLAGS),有些变量定义了缺省值(例如CC),我们写Makefile时可以重新定义这些变量的值,也可以在缺省值的基础上追加。以下列举一些常用的变量。

AR

静态库打包命令的名字,缺省值是ar

ARFLAGS

静态库打包命令的选项,缺省值是rv

AS

汇编器的名字,缺省值是as

ASFLAGS

汇编器的选项,没有定义。

CC

C编译器的名字,缺省值是cc

CFLAGS

C编译器的选项,没有定义。

CXX

C++编译器的名字,缺省值是g++

CXXFLAGS

C++编译器的选项,没有定义。

CPP

C预处理器的名字,缺省值是$(CC) -E

CPPFLAGS

C预处理器的选项,没有定义。

LD

链接器的名字,缺省值是ld

LDFLAGS

链接器的选项,没有定义。

TARGET_ARCH

和目标平台相关的命令行选项,没有定义。

OUTPUT_OPTION

输出的命令行选项,缺省值是-o $@

LINK.o

.o文件链接在一起的命令行,缺省值是$(CC) $(LDFLAGS) $(TARGET_ARCH)

LINK.c

.c文件链接在一起的命令行,缺省值是$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)

LINK.cc

.cc文件(C++源文件)链接在一起的命令行,缺省值是$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)

COMPILE.c

编译.c文件的命令行,缺省值是$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

COMPILE.cc

编译.cc文件的命令行,缺省值是$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

RM

删除命令的名字,缺省值是rm -f

***************************自动处理头文件的依赖关系*************************
  1. all:main
  2. main: main.o hello.o word.o
  3. gcc main.o hello.o word.o -o main
  4. main.o:main.h hello.h word.h
  5. hello.o:hello.h
  6. word.o:word.h
  7. clean:
  8. echo "cleanning project"
  9. -rm main *.o
  10. echo "clean completed"
  11. .PHONY:clean
all:main
main: main.o hello.o word.o
gcc main.o hello.o word.o -o main main.o:main.h hello.h word.h
hello.o:hello.h
word.o:word.h clean:
echo "cleanning project"
-rm main *.o
echo "clean completed" .PHONY:clean

现在Makefile写成上面的形式,默认make all,这样有个确定,写Makefile时要查个每个源文件,确定其包含的头文件,很容易出错,为了解决这个问题,可用用gcc -M查看源文件的依赖关系,-M选项会把系统头文件也找出来,如果不需要,可以用-MM选项。

  1. <localhost.localdomain:/data/ghostyu/linuxc> gcc -MM *.c
  2. hello.o: hello.c hello.h
  3. main.o: main.c main.h hello.h word.h
  4. word.o: word.c word.h
<localhost.localdomain:/data/ghostyu/linuxc> gcc -MM *.c
hello.o: hello.c hello.h
main.o: main.c main.h hello.h word.h
word.o: word.c word.h

现在的问题是怎样将上述依赖包含在Makefile中。

GNUlinux建议这样:
  1. all:main
  2. main: main.o hello.o word.o
  3. gcc main.o hello.o word.o -o main
  4. sources = main.c hello.c word.c
  5. include $(sources:.c=.d)
  6. %.d: %.c
  7. set -e; rm -f $@; \
  8. $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
  9. sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
  10. rm -f $@.$$$$

Makefile分析基础的更多相关文章

  1. Android发展的一个重要方面Makefile分析

    Android发展的一个重要方面Makefile分析 随着移动互联网的发展,移动开发也越来越吃香了.眼下最火的莫过于android.android是什么就不用说了,android自从开源以来,就受到非 ...

  2. MAKEFILE 编程基础之一【转】

    本文转载自:http://www.himigame.com/gcc-makefile/766.html 概述: 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Wind ...

  3. makefile 分析 -- 内置变量及自动变量

    makefile 分析1  -p 选项,可以打印出make过程中的数据库, 下面研究一下内置的变量和规则. -n 选项, 只运行,不执行, -d 选项,相当于--debug=a,  b(basic), ...

  4. 老李分享:《Java Performance》笔记1——性能分析基础 1

    老李分享:<Java Performance>笔记1——性能分析基础   1.性能分析两种方法: (1).自顶向下: 应用开发人员通过着眼于软件栈顶层的应用,从上往下寻找性能优化的机会. ...

  5. 算法设计与分析基础 (Anany Levitin 著)

    第1章 绪论 1.1 什么是算法 1.2 算法问题求解基础 1.2.1 理解问题 1.2.2 了解计算设备的性能 1.2.3 在精确解法和近似解法之间做出选择 1.2.4 算法的设计技术 1.2.5 ...

  6. 网站分析基础及KPI实践

    一:网站分析是什么? 网站分析(Web Analytics)即网站访客行为分析,通过对网站数据进行定量和定性的分析,来不断驱动和提高访问者在网站中的体验,并将访客转化为你的商业目标(在线及离线KPI) ...

  7. uboot主Makefile分析(t配置和编译过程详解)

    1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_c ...

  8. uboot主Makefile分析

    VERSION = 1 PATCHLEVEL = 3 SUBLEVEL = 4 EXTRAVERSION = U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(S ...

  9. RE-1 逆向分析基础

    逆向分析基础 0x01-0x0C 本笔记使用汇编指令为x86架构下汇编指令,ARM架构汇编指令不做介绍 0x01. 关于RE 逆向工程(Reverse Engineering RE) 逆向分析方法: ...

随机推荐

  1. 程序实现LayoutAnimationController

    在res/anim下新建anim_set.xml: <?xml version="1.0" encoding="utf-8"?> <set x ...

  2. static作用

    C程序一直由下列部分组成:      1)正文段——CPU运行的机器指令部分:一个程序仅仅有一个副本:仅仅读,防止程序因为意外事故而改动自身指令:      2)初始化数据段(数据段)——在程序中全部 ...

  3. MS Server中varchar与nvarchar的区别

    很多时候我们在创建数据库时在给字段设置数据类型时会选择varchar或是nvarchar.当然还可以选择别的数据类型,本文只对varchar和nvarchar两种类型做说明.如下测试表Test的表结构 ...

  4. 页面导出生成pdf,使用wkhtmltopdf第三方工具

    把页面导出生成pdf,这里用到第三方的工具,使用方法中文文档没有找到,网上也没找到网友详细的神作.没有深入研究,所以也不赘述了,当然最基本的使用大多数也够用了,详细参数的官网也没介绍,大家使用的时候, ...

  5. nyoj 55 懒省事的小明 优先队列 multiset 还有暴力

    懒省事的小明 时间限制: 3000 ms  |  内存限制: 65535 KB 难度: 3   描述       小明很想吃果子,正好果园果子熟了.在果园里,小明已经将所有的果子打了下来,而且按果子的 ...

  6. 使用mex进行混合编程的一些注意事项

    1.mxGetPr的使用: Use mxGetPr on arrays of type double only. Use mxIsDouble to validate the mxArray type ...

  7. 静态书架和js模拟翻书效果

    书籍图片随便找了个,有点难看,须要的自己替换个好看点的png格式图片 源代码下载:http://download.csdn.net/detail/sweetsuzyhyf/7604091

  8. 屏幕对象的F1/F4输入帮助功能

    1.HELP-REQUST[FOR{LOW|HIGH}]字段的F1帮助 当选择SAP屏幕功能的制定字段按F1键时可以调关注用自定义的程序或者系统帮助文件,该功能通常称为F1帮助. TYPES:syst ...

  9. win32创建控件的一些问题

    在我们使用CreateWindow();像一般控件建Windows扩展控件的时候我们会发现控件没有创建成功 这是因为我们没有对Windows扩展控件库进行初始化,这要我们使用InitCommonCon ...

  10. 键盘游戏之canvas--用OO方式写

    虽然写的不是很好,但 解释权以及版权仍然归13东倍所有!  <!DOCTYPE HTML> <html> <head> <title>canvas-00 ...