Makefile分析基础
http://blog.csdn.net/ghostyu/article/details/6866863
在我前一篇写的【 linux驱动学习(一)Makefile基础】中,Makefile写的中规中矩,其实Makefile写法很灵活,可以写得很简洁,而且减少出错的可能,现在就把之前写的Makefile改进一下。
- 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: 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试试看
- <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>
<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
- <localhost.localdomain:/data/ghostyu/linuxc> which cc
- /usr/bin/cc
<localhost.localdomain:/data/ghostyu/linuxc> which cc
/usr/bin/cc
事实上cc指向的也是gcc
其实,这是Makefile的内建隐含规则,然后make时,调用这些隐含规则。
- # 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) $<
# 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是一个变量,
- OUTPUT_OPTION = -o $@
OUTPUT_OPTION = -o $@
这边变量展开为:“-o main.o”
其次,展开COMPILE变量
- # default
- COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
为:“cc -c”。中间有四个空格。
然后
- %.o: %.c
%.o: %.c
这就相当于 main.o:main.c
最后
- $(COMPILE.c) $(OUTPUT_OPTION) $<
$(COMPILE.c) $(OUTPUT_OPTION) $<
注意开头的空白为tab键,8个字符,这是Makefile规定的,gcc命令等必须tab开头识别
展开为:
- cc -c -o main.o main.c
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
main.o:main.h hello.h word.h
main.o:main.c
cc -c -o main.o main.c
这就隐含的包含了各个条件的编译
注意:上面之所以可以写成两行,是应为条件并不是一定要写在一行,可以分开写,但只能存在一条命令:
比如下列:
- main.o: main.c main.h hello.h word.h
- gcc -c main.c
main.o: main.c main.h hello.h word.h
gcc -c main.c
可以写成:
- main.o:main.h hello.h word.h
- main.o:main.c
- gcc -c main.c
main.o:main.h hello.h word.h
main.o:main.c
gcc -c main.c
写规则的目的是让make建立依赖关系图,不管怎么写,只要把所有的依赖关系都描述清楚了就行。
- var = $(gho)
- gho = yu
- all:
- @echo $(var)
var = $(gho)
gho = yu all:
@echo $(var)
make all时,输出 yu
- <localhost.localdomain:/data/ghostyu/linuxc/test> make all
- yu
<localhost.localdomain:/data/ghostyu/linuxc/test> make all
yu
这就是Makefile中的变量,与TCL脚本的变量很类似
- <PRE style="BACKGROUND-COLOR: rgb(240,240,240); MARGIN: 4px 0px" class=plain name="code">var := $(gho)
- gho = yu
- all:
- @echo $(var)</PRE>
- <PRE></PRE>
- <PRE></PRE>
- <PRE></PRE>
- var := $(gho)
- gho = yu
- all:
- @echo $(var)
var := $(gho)
gho = yu all:
@echo $(var)
?=,例如var ?= $(gho)的意思是:如果var没有定义过,那么?=相当于=,定义var的值是$(gho),但不立即展开;如果先前已经定义了var,则什么也不做,不会给var重新赋值。+=运算符可以给变量追加值- var = main.o
- var += $(gho)
- gho = hello.o word.o
var = main.o
var += $(gho)
gho = hello.o word.o
这是var的值为 main.o hello.o word.o
$@,表示规则中的目标。$<,表示规则中的第一个条件。$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。$^,表示规则中的所有条件,组成一个列表,以空格分隔。
因此
- main: main.o hello.o word.o
- 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
可以改写为:
- main: main.o hello.o word.o
- 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。
- 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
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选项。
- <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
<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中。
- all:main
- main: main.o hello.o word.o
- gcc main.o hello.o word.o -o main
- sources = main.c hello.c word.c
- include $(sources:.c=.d)
- %.d: %.c
- set -e; rm -f $@; \
- $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
- sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
- rm -f $@.$$$$
Makefile分析基础的更多相关文章
- Android发展的一个重要方面Makefile分析
Android发展的一个重要方面Makefile分析 随着移动互联网的发展,移动开发也越来越吃香了.眼下最火的莫过于android.android是什么就不用说了,android自从开源以来,就受到非 ...
- MAKEFILE 编程基础之一【转】
本文转载自:http://www.himigame.com/gcc-makefile/766.html 概述: 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Wind ...
- makefile 分析 -- 内置变量及自动变量
makefile 分析1 -p 选项,可以打印出make过程中的数据库, 下面研究一下内置的变量和规则. -n 选项, 只运行,不执行, -d 选项,相当于--debug=a, b(basic), ...
- 老李分享:《Java Performance》笔记1——性能分析基础 1
老李分享:<Java Performance>笔记1——性能分析基础 1.性能分析两种方法: (1).自顶向下: 应用开发人员通过着眼于软件栈顶层的应用,从上往下寻找性能优化的机会. ...
- 算法设计与分析基础 (Anany Levitin 著)
第1章 绪论 1.1 什么是算法 1.2 算法问题求解基础 1.2.1 理解问题 1.2.2 了解计算设备的性能 1.2.3 在精确解法和近似解法之间做出选择 1.2.4 算法的设计技术 1.2.5 ...
- 网站分析基础及KPI实践
一:网站分析是什么? 网站分析(Web Analytics)即网站访客行为分析,通过对网站数据进行定量和定性的分析,来不断驱动和提高访问者在网站中的体验,并将访客转化为你的商业目标(在线及离线KPI) ...
- uboot主Makefile分析(t配置和编译过程详解)
1.编译uboot前需要三次make make distcleanmake x210_sd_configmake -j4 make distclean为清楚dist文件. make x210_sd_c ...
- uboot主Makefile分析
VERSION = 1 PATCHLEVEL = 3 SUBLEVEL = 4 EXTRAVERSION = U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(S ...
- RE-1 逆向分析基础
逆向分析基础 0x01-0x0C 本笔记使用汇编指令为x86架构下汇编指令,ARM架构汇编指令不做介绍 0x01. 关于RE 逆向工程(Reverse Engineering RE) 逆向分析方法: ...
随机推荐
- 性能测试之LoardRunner 结果分析
性能结果分析是性能测试中的重中之重,也是难点所在,以下总结了看图的一些顺序: 1.首先可以检查Analysis模块提供的Summary Report,整个测试过程中我们所关心的各业务 2.首先关注性能 ...
- cocos2dx3.2 异步载入和动态载入
半个月没有更新博客,从这个项目開始学习了非常多细节的东西,都不太成系统.可是却是开发上线中必须经历的东西.比方超级玛丽系列(一)中的正确的异步载入,正确的分层.正确的合成和载入plist.及时的移除未 ...
- 【JAVA学习】单例模式的七种写法
尊重版权:http://cantellow.iteye.com/blog/838473 第一种(懒汉.线程不安全): Java代码 public class Singleton { private ...
- Java中的throw和throws的差别
Java中的throw和throws的差别 1.throwkeyword用于方法体内部.而throwskeyword用于方法体部的方法声明部分: 2.throw用来抛出一个Throwable类型的异常 ...
- C++学习之路—继承与派生(四)拓展与总结
(根据<C++程序设计>(谭浩强)整理,整理者:华科小涛,@http://www.cnblogs.com/hust-ghtao转载请注明) 1 拓展部分 本节主要由两部分内容组成,分 ...
- abap优化工具事务代码: ST05
- iTextSharp使用字体设置摘录
用iTextSharp做pdf转换的时候,需要添加水印.文字水印的时候,需要设置字体,查了下文档.摘录下解决方案. iText中输出中文,有三种方式: 1.使用iTextAsian.jar中的字体 ...
- Selenium WebDriver ie,chrome 驱动
在驱动ie,chrome 的时候需要下载驱动 从网上下载IEDriverServer,Chromedriver 然后需要配置下就可以驱动ie,chrome 浏览器了 selenium 驱动ie 和 c ...
- Ubuntu下装QQ2012,让linux小白们不怕脱离windows
嘿嘿,很多人可能跟我一样,QQ上同学群里会通知一些事项,所以我们希望可以在linux下开QQ,但是QQ官网做的QQ For Linux, 实在是烂的不行 那么怎么在linux下装我们平时在window ...
- hadoop学习之ZooKeeper
1. 什么是ZooKeeper? ZooKeeper是一组工具,用来配置和支持分布式调度. 它能处理分布式应用的“部分失败”问题. 什么是部分失败? 部分失败是分布式处理系统的固有特征,即发送者无法知 ...