makefile 使用举例
2026/6/11 9:23:15 网站建设 项目流程

甲. 让make 每次都执行特定的命令

例子:

all: date

说明:

  1. all 是第一个目标,所以成为默认的目标.DEFAULT_GOAL
  2. 由于all文件不存在,所以必须重新制作目标all,制作的方法是,执行date命令

乙. 让make 每次都更新文件

例子: 热热身.
假如文件名是test.txt,
每次执行make都更新test.txt
最简单写法当然是:

all: date > test.txt

但是, 为了增强功能,这里决定要使用宏, 例如把文件名用一个宏变量来表示.
同时引入依赖, 这样更便于控制, 用以判断是否需要更新.

file = test.txt all: $(file) $(file) : date > $@

分析: 上述写法,

  1. all依赖于$(file), 生成all的配方是空, 所以对"all"无需做任何事
  2. 生成$(file)的配方是执行date 命令.
  3. 如果$(file)已经存在, 则不必在执行配方命令.
  4. 如果想让$(file)每次都更新,可以让它依赖于一个伪目标,如下示例
file = test.txt all: $(file) $(file) : FORCE date > $@ .PHONY FORCE

说明:

  1. 由于FORCE是不存在的,所以必须重新制作FORCE,但FORCE 是伪目标,所以总是可以制作成功.
  2. 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 直接调用 命令行函数完成创建. 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)

说明,

  1. 定义了2个函数,filechk, filechk_version.h
  2. filechk_version.h 只是简单的向控制台输出两行 define 字符串. 可被重定向生成version.h
  3. 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)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询