编译和链接
-
编译(compile): 将源码(Source Code)编译成中间代码文件(Object File,Windows下的obj文件,Unix下的o文件)
-
打包(pack): 将中间代码文件打包, Windows下的lib文件(库文件, Library File),Unix下的a文件(Archive)
-
链接(link): 将中间代码文件合成执行文件
参考Makefile文件
规则
Makefile的规则如下:
<target> : <prerequisites>
[tab] <commands>
- target: 目标,*必需项。一个目标构成一条规则;
- prerequisites: 前置条件。指定“目标”是否要重建构建的判断标准,只要一个前置文件不存在或者有过更新(前置文件的last-modification时间戳比目标的时间戳新),“目标”就需重新构建;
- [tab]: TAB键,第二行必须以TAB键开头;
- commands:命令行,运行结果通常是目标文件。
伪目标
例如:
.PHONY: all tools shared static deps install uninstall dist depsclean mostlyclean clean distclean
在使用伪目标时,当文件路径下有个all
文件,如果使用命令make all
,则会执行对应目标命令。
关键字Include
例如:
include $(MAKE_DIR)/common.mk
在文件common.mk
中包含全局变量定义和函数定义
在Makefile使用include关键字可以把别的 Makefile 包含进来,这很像C语言的#include
,被包含的文件会原模原样的放在当前文件的包含位置。
内置变量
Make命令提供一系列内置变量,比如,$(CC) 指向当前使用的编译器,$(MAKE) 指向当前使用的Make工具。这主要是为了跨平台的兼容性,详细的内置变量清单见手册
$(LIB_OBJS): %.lo: %.c | deps
$(CC) $(LIB_CFLAGS) $(LIB_CPPFLAGS) -MMD -MF $*.d -c $(OUTPUT_OPTION) $<
deps: $(LIB_RPC_SRCS) $(BUILD_DEFS)
$(MKDIR) -p $(DEPS_DIR)
$(MAKE) -f $(MAKE_DIR)/nvidia-modprobe.mk install
函数
Makefile提供了许多内置函数,可供调用。
- shell函数
UID := $(shell id -u)
GID := $(shell id -g)
- call函数
call函数是唯一一个可以用来创建新的参数化的函数
在makefile中:
ARCH ?= $(call getarch)
其对应的getarch
函数在common.mk
中
getarch = $(shell [ -f /etc/debian_version ] && echo "amd64" || echo "x86_64")
忽略错误
ifeq ($(WITH_LIBELF), no)
-$(MAKE) -f $(MAKE_DIR)/elftoolchain.mk clean
在$(MAKE)
前面加-
,表示出现错误时不停止,继续执行下去。
赋值运算符
# 在执行时扩展,允许递归扩展。
VARIABLE = value
# 在定义时扩展。
VARIABLE := value
# 只有在该变量为空时才设置值。
VARIABLE ?= value
# 将值追加到变量的尾端。
VARIABLE += value
区别可查看What is the difference between the GNU Makefile variable assignments =, ?=, := and +=?
循环
Makefile使用 Bash 语法,完成判断和循环。
ifeq ($(WITH_LIBELF), no)
-$(MAKE) -f $(MAKE_DIR)/elftoolchain.mk clean
endif
ifeq ($(WITH_TIRPC), yes)
-$(MAKE) -f $(MAKE_DIR)/libtirpc.mk clean
endif
使用docker编译
命令:make docker-centos:7 TAG=beta.1
docker-%: SHELL:=/bin/bash
docker-%:
image=$* ;\
$(MKDIR) -p $(DIST_DIR)/$${image/:} ;\
$(DOCKER) build --network=host \
--build-arg IMAGESPEC=$* \
--build-arg USERSPEC=$(UID):$(GID) \
--build-arg WITH_LIBELF=$(WITH_LIBELF) \
--build-arg WITH_TIRPC=$(WITH_TIRPC) \
--build-arg WITH_SECCOMP=$(WITH_SECCOMP) \
-f $(MAKE_DIR)/Dockerfile.$${image%%:*} -t $(LIB_NAME):$${image/:} . ;\
$(DOCKER) run --rm -v $(DIST_DIR)/$${image/:}:/mnt:Z -e TAG -e DISTRIB -e SECTION $(LIB_NAME):$${image/:}
-
docker-%: 目标(target)。可以使用
make docker-centos:7
; -
%: 匹配符。上述
%为centos:7
; -
SHELL:=/bin/bash: 前置条件(prerequisites)。意思为
当符合前置条件的情况下,执行目标。或者先执行前置条件,再执行目标
,该句意思为,在当前SHELL为/bin/bash
时,会执行目标docker-%
- 第二个docker-%,则为目标的主体。
-
- 第二行必须由一个
TAB键
起首,后续跟着命令(commands)
- 第二行必须由一个
-
- 命令中每行在不同进程执行。若要保持连续性,命令之间需要添加
;
。为编写方便,可添加反斜杠转义\
- 命令中每行在不同进程执行。若要保持连续性,命令之间需要添加
-
$*: 指代匹配符
%
匹配的部分, 比如%
匹配docker-centos:7
中的centos:7
,$*就表示centos:7
; - $${image/:}: 在makefile中要引用shell命令中的变量,要使用
$${VAR}
格式
参考博文
本作品由陈健采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。