Makefile基础
2015-12-23 19:10
267 查看
摘自:http://o0o0o0o.iteye.com/blog/1108171
Makefile基础 :
make命令会自动读取当前目录下的
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
target ... : prerequisites ...
command1
command2
...
例如:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
目标和条件之间的关系是:欲更新目标,必须首先更新它的所有条件;所有条件中只要有一个条件被更新了,目标也必须随之被更新。所谓“更新”就是执行一遍规则中的命令列表,命令列表中的每条命令必须以一个Tab开头,
注意不能是空格,Makefile的格式不像C语言的缩进那么随意,对于Makefile中的每个以Tab开头的命令,
通常Makefile都会有一个
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
clean:
@echo "cleanning project"
-rm main *.o
@echo "clean completed"
把这条规则添加到我们的Makefile末尾,然后执行这条规则:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
$ make clean
cleanning project
rm main *.o
clean completed
如果在
命令前面加
如果
通常
通常
文件名则不一定是
隐含规则和模式规则:
make的隐含规则数据库可以用
#号在Makefile中表示单行注释,就像C语言的
$@和
一个目标依赖于若干条件,现在换个角度,以条件为中心,Makefile还可以这么写:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main.o stack.o maze.o: main.h
main.o maze.o: maze.h
main.o stack.o: stack.h
clean:
-rm main *.o
.PHONY: clean
对于多目标的规则,
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
target1 target2: prerequisite1 prerequisite2
command $< -o $@
这样一条规则相当于:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
target1: prerequisite1 prerequisite2
command prerequisite1 -o target1
target2: prerequisite1 prerequisite2
command prerequisite1 -o target2
注意两条规则的命令列表是一样的,但
变量:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
foo = $(bar)
bar = Huh?
all:
@echo $(foo)
我们执行
有时候我们希望
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
x := foo
y := $(x) bar
all:
@echo "-$(y)-"
运算符是
常用的特殊变量有:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o mainv
可以改写成:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc $^ -o $@
常用的
-C选项可以切换到另一个目录执行那个目录下的Makefile,
在
如果在Makefile中也定义了
Makefile基础 :
make命令会自动读取当前目录下的
Makefile文件,完成相应的编译步骤。Makefile由一组规则(Rule)组成,每条规则的格式是:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
target ... : prerequisites ...
command1
command2
...
例如:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main是这条规则的目标(Target),
main.o、
stack.o和
maze.o是这条规则的条件(Prerequisite)。
目标和条件之间的关系是:欲更新目标,必须首先更新它的所有条件;所有条件中只要有一个条件被更新了,目标也必须随之被更新。所谓“更新”就是执行一遍规则中的命令列表,命令列表中的每条命令必须以一个Tab开头,
注意不能是空格,Makefile的格式不像C语言的缩进那么随意,对于Makefile中的每个以Tab开头的命令,
make会创建一个Shell进程去执行它。
通常Makefile都会有一个
clean规则,用于清除编译过程中产生的二进制文件,保留源文件:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
clean:
@echo "cleanning project"
-rm main *.o
@echo "clean completed"
把这条规则添加到我们的Makefile末尾,然后执行这条规则:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
$ make clean
cleanning project
rm main *.o
clean completed
如果在
make的命令行中指定一个目标(例如
clean),则更新这个目标,如果不指定目标则更新Makefile中第一条规则的目标(缺省目标)。
命令前面加
@和
-字符的效果:
如果
make执行的命令前面加了
@字符,则不显示命令本身而只显示它的结果;
通常
make执行的命令如果出错(该命令的退出状态非0)就立刻终止,不再执行后续命令,但如果命令前面加了
-号,即使这条命令出错,
make也会继续执行后续命令。
通常
rm命令和
mkdir命令前面要加
-号,因为
rm要删除的文件可能不存在,
mkdir要创建的目录可能已存在,这两个命令都有可能出错,但这种错误是应该忽略的。
文件名则不一定是
Makefile。事实上,执行
make命令时,是按照
GNUmakefile、
makefile、
Makefile的顺序找到第一个存在的文件并执行它,不过还是建议使用
Makefile做文件名。除了GNU
make,有些UNIX系统的
make命令不是GNU
make,不会查找
GNUmakefile这个文件名,如果你写的Makefile包含GNU
make的特殊语法,可以起名
GNUmakefile,否则不建议用这个文件名。
隐含规则和模式规则:
make的隐含规则数据库可以用
make -p命令打印,打印出来的格式也是Makefile的格式,包括很多变量和规则。
#号在Makefile中表示单行注释,就像C语言的
//注释一样。
CC是一个Makefile变量,用
CC = cc定义和赋值,用
$(CC)取它的值,其值应该是
cc。
$@和
$<是两个特殊的变量,
$@的取值为规则中的目标,
$<的取值为规则中的第一个条件。
%.o: %.c是一种特殊的规则,称为模式规则(Pattern Rule)。
一个目标依赖于若干条件,现在换个角度,以条件为中心,Makefile还可以这么写:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o main
main.o stack.o maze.o: main.h
main.o maze.o: maze.h
main.o stack.o: stack.h
clean:
-rm main *.o
.PHONY: clean
对于多目标的规则,
make会拆成几条单目标的规则来处理,例如
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
target1 target2: prerequisite1 prerequisite2
command $< -o $@
这样一条规则相当于:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
target1: prerequisite1 prerequisite2
command prerequisite1 -o target1
target2: prerequisite1 prerequisite2
command prerequisite1 -o target2
注意两条规则的命令列表是一样的,但
$@的取值不同。
变量:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
foo = $(bar)
bar = Huh?
all:
@echo $(foo)
我们执行
make将会打出
Huh?。当
make读到
foo = $(bar)时,确定
foo的值是
$(bar),但并不立即展开
$(bar),然后读到
bar = Huh?,确定
bar的值是
Huh?,然后在执行规则
all:的命令列表时才需要展开
$(foo),得到
$(bar),再展开
$(bar),得到
Huh?。因此,虽然
bar的定义写在
foo之后,
$(foo)展开还是能够取到
$(bar)的值。
有时候我们希望
make在遇到变量定义时立即展开,可以用
:=运算符,例如:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
x := foo
y := $(x) bar
all:
@echo "-$(y)-"
运算符是
?=,例如
foo ?= $(bar)的意思是:如果
foo没有定义过,那么
?=相当于
=,定义
foo的值是
$(bar),但不立即展开;如果先前已经定义了
foo,则什么也不做,不会给
foo重新赋值。
常用的特殊变量有:
$@,表示规则中的目标。
$<,表示规则中的第一个条件。
$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。
$^,表示规则中的所有条件,组成一个列表,以空格分隔。
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc main.o stack.o maze.o -o mainv
可以改写成:
Java代码
![](https://oscdn.geek-share.com/Uploads/Images/Content/201505/05/cd0a92bf5c393b1ecb423f576bb13bff.png)
main: main.o stack.o maze.o
gcc $^ -o $@
常用的
make命令行选项
-n选项只打印要执行的命令,而不会真的执行命令,这个选项有助于我们检查Makefile写得是否正确,由于Makefile不是顺序执行的,用这个选项可以先看看命令的执行顺序,确认无误了再真正执行命令。
-C选项可以切换到另一个目录执行那个目录下的Makefile,
在
make命令行也可以用
=或
:=定义变量,如果这次编译我想加调试选项
-g,但我不想每次编译都加
-g选项,可以在命令行定义
CFLAGS变量,而不必修改Makefile编译完了再改回来:
$ make CFLAGS=-g cc -g -c -o main.o main.c cc -g -c -o stack.o stack.c cc -g -c -o maze.o maze.c gcc main.o stack.o maze.o -o main
如果在Makefile中也定义了
CFLAGS变量,则命令行的值覆盖Makefile中的值。
相关文章推荐
- Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
- 左右滑动删除ListView条目Item--第三方开源--SwipeToDismiss
- LeetCode 034
- 各种排序算法比较
- jstl中格式化时间戳
- 【AC自动机+DP】[USACO JAN2012 GOLD Problem 1: Video Game Combos]
- CoreAnimation编程指南
- Java集合类之Set
- Java集合类之Map
- 使用自定义的item、Adapter和AsyncTask、第三方开源框架PullToRefresh联合使用实现自定义的下拉列表(从网络加载图片显示在item中的ImageView)
- 解决快递100普通key不能查询顺丰、申通等快递问题
- Java集合类之List性能比较
- 从一个URL下载原始数据,基于byte字节,得到byte数组
- Material Design UI Widgets
- Git管理多个远程仓库(GitHub和Coding)
- silicon lab ember zigbee学习杂谈 --------- 发送zcl command
- Oracle-单表合并列
- DOM操作-事件对象
- JavaScript中concat不起作用
- Oracle-单表合并列