Knowing makefile in linux

来源:互联网 发布:6x6摇头矩阵灯 编辑:程序博客网 时间:2024/05/01 20:49

 

1. compilation and linking

 

compilation (object file): .obj files in windows; .o files in linux

 

编译时, 编译器会检查语法, 函数, 及变数的宣告正确与否, 正确则编译成功, 反之则失败!

 

linking: 告知编译器 head file 的位置, 链接函数和全局变数, so 可使用 object files 来链接应用程式.

 

当 object file 太多时通常习惯将其打包, 如 .lib in windows; .a in linux.

 

2. makefile rule

 

target : prerequisites

<Tab>command

 

或是

 

target : prerequisites ; command

 

prerequisites 中如果有一个以上的档案比 taget 还新, command 就会被执行, command 是一个 linux shell script.

 

 

3. The example of GNU make user guild

 

supposed that we have an application with 8 c files and 3 head files, we can write a makefile to meet below condictions.

 

1) All c files have to be compliered and linked if the application was never complied.

 

2) Just complie these c files and link them to the application if some c files were modified.

 

3) Just complie those c files that included these head files and link them to the application if some head files were modified.

 

makefile -

 

 

 4. 隐晦规则与变量使用

 

make 可自动识别寻找 <filename>.c 来编译 <filename>.o,这称为 makefile 的隐晦规则.

 

将上例的所有的 object files 都以一个变量 objects 表示, 相当于 string variable. 于是 makefile 可简化成:

 

 

 

上例中 ".PHONY" 的用法表示 clean 是一个伪目标文件, 上例中的 makefile 也可以写成:

 

  

 

clean 一个比较 safe 的写法是: ("-" 表示当文件出现问题时, ignore 继续作后面的事)

 

 

5. 引用其他的 makefile

 

若要引用其他的 makefile, 可用 "include <filename>", 如 include a.mk b.mk c.mk

 

mak 执行时, 有 "-I" or "--include-dir" 参数, 则 make 会在指定的目录寻找, 如果有 <prefix>/include, 通常是 /usr/include or /usr/local/bin 存在的话, 也会寻找.

 

若希望忽略这个错误可用 "-include <filename>", 在其他 make 版本兼容的语法为 sinclude.

 

另环境变数 MAKEFILES, 亦等同此作用, 不同的是不同的档案以 "," 分开表示.

 

6. 搜寻的目录

 

vpath, 如 vpath %.h foo:bar, 表示先在 foo 目录下寻找, 若找不到, 再到 bar 下寻找

 

7. 多目标与自动化变量

 

往下看一个例子:

 

 

等价于

 

$< 表示所有依赖的文件, 而 $@ 表示需生成的目标

 

$%: 目标中的规则成员名, 如目标是 foo.a, 则 $% = foo.a, 如果目标不是库文件,  则 $% 为空

 

$?: 所有比目标新的依赖文件集合

 

$^: 所有依赖目标的集合

 

$+: 不去除重复的依赖目标

 

$*: 目标样式中 "%" 及 "%" 之前的部分, 如目标是 "dir/a.foo.c", 样式为 "a.%.c",  则 $* = "dir/a.foo"

 

可以在自动化变量中指定是目录还是档案, 使用关键字 "D" 与 "F", 如 $(@D) 列举所有目标的目录

 

8. 调试

使用 "@" 在命令之前, 则命令将不会被 make 显示出来, 只会执行.

 

另 make -n or make --just-print, 只会显示命令, 而不执行命令, 而 make -s or make --silent, 则不显示命令.

 

有时候的命令出错, 并不一定是真正的错误, 如 mkdir, 此时则可在命令前加个 "-", 另外有个全局的做法, make -i or make --ignore-errors.

 

还有一个用法是 make -k or make --keep-going, 指的是若某个规则出错, 则往下执行其他规则.

 

9. 嵌套与变量传递

 

 如有一个子目录为 subdir, 要进入 subdir 执行 make, 则 makefile 可写为:

 

subsystem:

 

cd subdir && $(MAKE)

 

相等于

 

subsystem:

 

$(MAKE) -C subdir

 

在此的 makefile 所定义的变量是不会覆盖到下层 makefile 所使用的变量, 除非用 "-e" (如果是 make -e, 系统环境变量将覆盖 makefile 所定义的变量)

 

如果要传递变量到下层 makefile, 可以用 "export", 反之为 "unexport", 意思是不传递参数到下层 makefile.

 

export var = val

 

等同于

 

var = val

export var

 

也同于

 

var := val

export var

 

(export var := val)

 

":=" 与 "=" 差别的地方是前面不能使用后面的变量, 即时后面被重复赋值, 如下: $y = bar, 而不是 "foo bar"

 

y := $(x) bar
x := foo

 

再看另外一个 export 的例子:

 

export var += val

 

亦等同于

 

var += val

export var

 

如果要传递所有的变量, 只要声明 "export" 后面啥么都不用加.

 

特别要注意的是 MAKEFLAGS, 这是一个环境变量, 将会将上层的 makefile 所使用的参数传递到下层, 所以如果不想传递的话, 可以这样使用:

 

subsystem:

cd subdir && $(MAKE) MAKEFLAGS=

 

另外还有 make -w or make --print-subdirectory, 会在 make 的过程中显示目录的进入及离开:

 

make: Entering directory `/home/hchen/gnu/make', 会在完成下层的 make 后离开目录

 

make: Leaving directory `/home/hchen/gnu/make'

 

另外值得一提的是, 当使用参数 "-C", 则 "-w" 会被自动打开, 当使用 "-s" or "--no-print-subdirectory", 那么 "-w" 的作用将失效.

 

10. 定义命令

 

"define' 开头, "endef' 结尾.

 

define run-func

func $(firstworld $^)

mv f.temp.c $@

endef

 

11. 变量

 

如果令一个变量的值是一个空格, 可以下列写法,

 

nullstring :=

space := $(nullstring) # end of line

 

或是

 

empty :=

space := $(empty) $(empty)

 

还有一个比较有用的操作符是 "?=", 如果 foo 没有被定义过, 则 foo = bar, 否则忽略.

 

foo ?= bar

 

等同于

 

ifeq ($(origin foo), undefined)

foo = bar

endif

 

回顾一下前面提到的变量值替换: 结尾 .o 换成 .c

 

foo := a.o b.o c.o
bar := $(foo:%.o=%.c)

 

等价于

 

foo := a.o b.o c.o
bar := $(foo:.o=.c)

 

与 Perl 一样具有变量中的变量机制, 看看两个等同例子, 其输出都是 "Hello"

 

 

等同于:

 

 

subst 是把 $x 中的 "1' 替换成 "2".

 

make 预设以接在 make 之后的参数作为预设的参数, 也就是等同于 ":=" 的使用, 如果 makefile 中想在覆盖这些参数, 可以使用 override 指示符:

 

override a = b

override a := b

override a += b

 

override define foo

bar

endef

 

谈谈目标变量,  在规则规则内忽略全局变量, 不管 CFLAGS 全局变量为何, 在 prog 目标内, CFLAGS 永远为 -g

 

 

12. 条件表示式

 

ifeq, ifneq, ifdef, ifndef, 以下为示例:

 

 

13. 函数

 

makefile 中函数的使用以 "$" 来标示, 看看以下示例, 空格以",", 则其结果 bar = 'a,b,c".

 

 

1) 字符串函数

 

subst <arg1> <arg2> <arg>: 将 arg 中的 <arg1> 替换成 <arg2>

 

patsubst <pattern> <replace> <arg>: 将 arg 中符合 <pattern> 替换成 <replace>

 

strip <arg>: 将 <arg> 中开头跟结尾的空格去除

 

findstring <find> <target>: 在 <target> 寻找 <find>, 找到返回 <find>, 反之返回 "" (空字符串)

 

filter <pattern> <arg>: 保留 <arg> 中, 符合 <pattern> 的单词

 

filterout <pattern> <arg>: 与 filter 相反, 保留不符合 <pattern> 的单词

 

sort <list>: 将 <list> 的单词升序排列

 

word <number> <text>: 取第 <number> 个单词, 从 1 开始.

 

wordlist <from>, <to>, <list>: 从第 <from> 到 <to>, 将 <list> 单词取出

 

words <list>: 返回单词个数

 

firstword <list>: 返回第一个单词

 

2) 文件操作函数

 

dir <names>: 取 <names> 中各单词的目录名, 最后一个 "/" 之前的字串, 如果没有 "/", 则返回 "./"

 

notdir <names>: 取 <names> 中单词的档案名

 

suffix <names>: 取 <names> 中单词的副档名, 若无副档名返回空字串, 如 $(suffix a.c) 返回 ".c" 

 

basename <names>: 取 <names> 中单词的前缀部分, 若无前缀返回空字串

 

addsuffix <suffix> <names>: 将 <names> 中的单词加上后缀 <suffix>

 

addprefix <prefix> <names>: 将 <prefix> 加在 <names> 中的单词之前

 

join <list1> <list2>: 将 <list1> 中的单词与 <list2> 中的单词分别连接, 如 $(join aaa bbb, 111 222) 返回 "aaa111 bbb222"

 

3) foreach

 

foreach <var> <list> <text>:

 

将 <list> 的单词取出以 <var> 在 <text> 表示再返回, 如下例: $files = "a.o b.o c.o d.o"

 

names := a b c d
files := $(foreach n, $(names), $(n).o)

 

4) call

 

call <expression> <arg1> <arg2>: 创建参数化的函数

 

reverse = $(1) $(2)
foo = $(call reverse, a, b)

 

则 $foo = "a b"

 

5) origin

 

origin <variable>: 告知 <variable> 是从哪来的, 其返回值有:

 

"undefined": 从没被定义 

 

"default": 默认的的定义

 

"environment": 环境变量, 且 make 执行时, "-e" 没有被打开

 

"file": 定义在 makefile 中

 

"command line": 被命令行定义

 

"override": 被 override 指示符重新定义

 

'automatic": 自动化变量

 

origin 应用的示例如, 我们想判断 foo 这变量如果由环境而来, 则重新定义, 若是其他来源, 则不重新定义.

 

ifdef foo
ifeq "$(origin foo)" "environment"
foo = b, g, etc.
endif
endif

 

6) 控制 make 的函数

 

error & warning: error 会中断 make,  warning 则不会, 用法都是一样.

 

error <text>: 输出错误讯息并中断 make

 

warning <text>: 输出警告不中断 make

 

 

 

 

 

 

 

 

 

 

原创粉丝点击