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. 基于visual Studio2013解决面试题之0802数字最多元素

     题目

  2. ARC内存使用注意事项

    官方介绍: https://developer.apple.com/library/mac/#documentation/Performance/Conceptual/ManagingMemory/M ...

  3. Kendo UI开发教程(25): 单页面应用(三) View

    View为屏幕上某个可视部分,可以处理用户事件. View可以通过HTML创建或是通过script元素.缺省情况下View将其所包含的内容封装在一个Div元素中.Kendo创建View有两种方式: 使 ...

  4. .Net 4.0特性 Tuple元组

    Tuple 字面意思:元组.是.net4.0增加的新特性,是干什么的呢?总结一句,个人觉得这个东西 就是用来在有返回很多种类型的值时可以用到.它提供了8种类型的Tuple,直接看最复杂的那种(其实不是 ...

  5. Windows 8 动手实验系列教程 实验7:磁贴和通知

    动手实验 实验7:磁贴和通知 2012年9月 简介 磁贴是Windows应用商店应用用户体验的重要元素.当应用程序被安装后,它的磁贴将在Windows 8开始屏幕被创建.该磁贴(称为主磁贴)作为启动应 ...

  6. clear_logs.py修改

    #!/usr/bin/env python#encoding=utf-8"""清空最后修改时间跑今天7天以前的所有文件"""#指定监控的路径 ...

  7. Delphi的String内存结构(够清楚) good

    变量s的内存结构为(字符串编码)A8 03 (字符宽度)01 00 (引用计数)FF FF FF FF (字符串长度)0A 00 00 00 (实际内容)31 32 33 34 35 36 37 38 ...

  8. iOS UIScrollView 停止滑动 减速

    1.UIScrollView 减速 可能通过decelerationRate的属性来设置,它的值域是(0.0,1.0),当decelerationRate设置为0.1时,当手指touch up时就会很 ...

  9. ASP.NET Aries 开发框架

    开源:ASP.NET Aries 开发框架 前言: 随着岁月的推进,不知不觉已在.NET这领域上战斗了十年了. 青春还没来得急好好感受,却已是步入健忘之秋的老人一枚了. 趁着还有点记忆,得赶紧把硬盘里 ...

  10. HDU 1142 A Walk Through the Forest(dijkstra+记忆化DFS)

    题意: 给你一个图,找最短路.但是有个非一般的的条件:如果a,b之间有路,且你选择要走这条路,那么必须保证a到终点的所有路都小于b到终点的一条路.问满足这样的路径条数 有多少,噶呜~~题意是搜了解题报 ...