甲. 让make 每次都执行特定的命令
例子:
all:
date
说明:
- all 是第一个目标,所以成为默认的目标.DEFAULT_GOAL
- 由于all文件不存在,所以必须重新制作目标all,制作的方法是,执行date命令
乙. 让make 每次都更新文件
例子: 热热身.
假如文件名是test.txt,
每次执行make都更新test.txt
最简单写法当然是:
all:
date > test.txt
但是, 为了增强功能,这里决定要使用宏, 例如把文件名用一个宏变量来表示.
同时引入依赖, 这样更便于控制, 用以判断是否需要更新.
file = test.txt
all: $(file)
$(file) :
date > $@
分析: 上述写法,
- all依赖于$(file), 生成all的配方是空, 所以对"all"无需做任何事
- 生成$(file)的配方是执行date 命令.
- 如果$(file)已经存在, 则不必在执行配方命令.
- 如果想让$(file)每次都更新,可以让它依赖于一个伪目标,如下示例
file = test.txt
all: $(file)
$(file) : FORCE
date > $@
.PHONY FORCE
说明:
- 由于FORCE是不存在的,所以必须重新制作FORCE,但FORCE 是伪目标,所以总是可以制作成功.
- FORCE 更新了,所以要更新$(file), 其处方是date 命令, 所以$(file)被更新.
丙. 让make 每次都判断,更新版本文件version.h
例子: 来源于linux Makefile, 有自己的更改,我们考察一些其中的一些概念.
当makefile 中三个变量改变的时候,就会更新version.h, version.h 就是这三个变量的变体.
如果3个变量没有改变,则不必更新version.h,保留旧的时间戳.
VERSION = 2
PATCHLEVEL = 3
SUBLEVEL = 1
# filechk 用来检查产生的文件内容是否需要更新
# 使用:
# $(call filechk,sample)
# 实现:
# 定义的规则会输出到新文件
# 存在的文件会与新文件比较
# - 如果 旧文件不存在,使用新文件
# - 如果 旧文件和新文件内容不同,使用新闻界
# - 如果 旧文件和新文件内容相同,使用旧文件,这样时间戳就不会改变.
define filechk
@set -e; \
echo ' CHK $@'; \
mkdir -p $(dir $@); \
$(create_$(1)) > $@.new; \
if [ -r $@ ] && cmp -s $@ $@.new; then \
rm -f $@.new; \
else \
echo ' UPD $@'; \
mv -f $@.new $@; \
fi
endef
# 该函数向屏幕输出 "版本信息", Makefile 竟能直接调用 shell 函数?!
define create_version.h
(echo \#define LINUX_VERSION_CODE $(shell expr $(VERSION) \* 65536 + $(PATCHLEVEL) \* 256 + $(SUBLEVEL)); \
echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';)
endef
.PHONY: FORCE
version.h: FORCE
$(call filechk,version.h)
说明,
- 定义了2个函数,filechk, filechk_version.h
- filechk_version.h 只是简单的向控制台输出两行 define 字符串. 可被重定向生成version.h
- filechk 函数, 比较两个文件是否相同并决定是否替换文件.
set -e 表示执行出错时立即退出
调用了filechk_version.h 并把输出重定向到文件
调用了cmp 程序,比较两个文件的内容,相同则保留旧的,不同则替换旧的.
当你把主版本号, 或次版本号,build 号一改, 生成的文件与原文件不同,就替换原来的文件了.
Makefile 中命令语句就是tab 开头的 shell 命令.
Makefile 中定义的命令包又与纯bash_script 有区别, 例如$() 在bash中是执行命令而不是变量引用, ${}是变量引用, 无shell 命令, dir 与这里的
dir 含义不同, 在这里写的命令包难以跟踪,难以调试, 最好别用!!!
另一种写法,供参考
VERSION = 2
PATCHLEVEL = 3
SUBLEVEL = 1
VERSTR=$(shell printf "0x%x" $$((($(VERSION)<<16)+($(PATCHLEVEL)<<8)+$(SUBLEVEL))))
define filechk
@set -e; \
echo ' CHK $@'; \
$(filechk_$(1)) > $@.tmp; \
if [ -r $@ ] && cmp -s $@ $@.tmp; then \
rm -f $@.tmp; \
else \
echo ' UPD $@'; \
mv -f $@.tmp $@; \
fi
endef
define filechk_version.h
(echo '#define KERNEL_VERSION(a,b,c) (a << 16) + (b << 8) + (c))'; \
echo '#define KERNEL_VERSION' $(VERSTR); \
)
endef
.PHONY: FORCE
version.h: FORCE
$(call filechk,version.h)