自动化编译脚本工具make,它通过各种规则来控制你的源代码如何生成目标程序。要使用make编译一个程序,需要提供一个makefile文件让make知道如果构造你的程序,makefile的内容就是一系列的规则,这些规则其实就像一种脚本,它有变量、函数、宏、表达式,分支结构等,而make主要靠文件依赖性这种方式对源文件编译。
比如,首先告诉make我需要目标A,然后make去找对应A的规则,如果A存在(一般是文件)就返回,如果不存在就根据A中定义的规则来产生A,A中的规则也可能需要目标B(A依赖B)或多个其它目标,而B也可能也需要目标C等等,这样就会有一个递归调用,make会一直找下去,当然规则也可以是调用一个cl来产生obj或link生成exe。直到所有文件全部生成最终产生目标A整个过程才完成。
Make is a tool which controls the generation of executables and other non-source files of a program from the program's source files
Make gets its knowledge of how to build your program from a file called the makefile, which lists each of the non-source files and how to compute it from other files. When you write a program, you should write a makefile for it, so that it is possible to use Make to build and install the program.
微软VC中使用的是nmake,turbo C中也有个make,free pascal也有。很多编译器都自带make工具。不同家的make语法也不一样。
用得最多的估计就是GNU make。它是免费开源产品,我现在用的版本是3.75.
以下是GNU make中的一些常用函数。
.SUFFIXES:
.SUFFIXES: .c .o
.PHONY: all
# 先编译后清除不需要的文件。
all: ${OUT} clean_temp
# 获取当前目录下所有.c文件。
src := $(wildcard ${CURDIR}*.c)
# 获取.c文件对应一个.o文件名。
obj := $(addsuffix .o, $(basename ${src}))
${OUT}: ${obj}
gecho $<>$@
# 设定指定文件的编译规则。
%.o: %.c
$(CC) $< $@
.PHONY: clean_all
# 清除所有生成的文件。
clean_all: clean_temp clean_out
.PHONY: clean_temp
# 清除除目标文件之外的生成文件。
clean_temp:
if exist *.o del *.o
.PHONY: clean_out
# 清除目标文件。
clean_out:
if exist ${OUT} del ${OUT}
test:
# make 函数测试。
gecho $(wildcard ${CURDIR}*) # 使用通配符列出指定目录下的文件或目录。
gecho $(dir $(wildcard ${CURDIR}*)) # 列出每个文件路径的目录路径名。
gecho $(notdir $(wildcard ${CURDIR}*)) # 列出每个文件路径的全文件名。
gecho $(realpath $(wildcard ${CURDIR}*)) # 列出每个文件的真实路径名。
gecho $(abspath $(wildcard ${CURDIR}*)) # 列出每个文件的绝对路径名。
gecho $(suffix $(wildcard ${CURDIR}*)) # 列出每个文件路径的文件扩展名。
gecho $(basename $(wildcard ${CURDIR}*)) # 列出每个文件路径的文件名。
gecho $(addsuffix X2, $(wildcard ${CURDIR}*)) # 给每个文件路径追加后缀。
gecho $(addprefix PFX, $(wildcard ${CURDIR}*))# 给每个文件路径插入前缀。
gecho $(join 1 2 3 4 5, .c .c .c .c .h) # 将两个列表合并,变成1.c 2.c 3.c 4.c 5.h
gecho $(shell echc) # 执行一个Shell命令并将输出返回。
gecho $(foreach d, 1 2 3 4 5 6 7 8 9 10, ${d})# 枚举一个列表并返回处理的结果。foreach var,set,expression
gecho $(subst 1, 2, 1 2 3 4 5 6 7 8 9 10) # 返回文本替换后的结果。subst old, new, string
gecho $(patsubst %x, y, flex xor sex fixed) # 返回文本替换后的结果。subst pattern,replacement, string
gecho $(src:%.c = %.o) # 返回文本替换后的结果。var:suffix = replacement
gecho $(strip . start ... c = end of . ) # 移除文本前后的空白字符。
gecho $(findstring end, .end of . ) # 返回文本中是否包含指定的字符串。没找到返回空。
gecho $(filter %d, .end of . ) # 从列表中移除未匹配的字符串。
gecho $(filter-out %d, .end of . ) # 从列表中移除匹配的字符串。
gecho $(sort 8 2 1 4 3 0 7 14 6 10 32 5) # 按字母排序列表。
gecho $(word 5, 8 2 1 4 3 0 7 14 6 10 32 5) # 返回列表中指定序号的元素。
gecho $(wordlist 2, 3, X8 X2 X1 X4 X3 X0 X7) # 返回列表部分的元素。
gecho $(words X8 X2 X1 X4 X3 X0 X7) # 返回列表的元素数量。
gecho $(firstword X8 X2 X1 X4 X3 X0 X7) # 返回列表的第一个元素。
gecho $(lastword X8 X2 X1 X4 X3 X0 X7) # 返回列表的最后一个元素。
# call a complex expression.
# 调用一个表达式
override A = $(info $(origin foo))
override A = $(info $(flavor bar))
# condition directives. 条件指令。
# style 1 for the ifeq statement.
ifndef A
override A = B
gecho ${A}
endif
ifeq (${A}, B)
gecho ifeq (${A}, B) == YES
endif
ifneq (${A}, C)
gecho ifneq (${A}, C) == YES
endif
# style 2 for the ifeq statement.
ifeq '${A}' 'B'
gecho ifeq '${A}' 'B' == YES
endif
ifneq '${A}' 'C'
gecho ifneq '${A}' 'C' == YES
endif
# style 3 for the ifeq statement.
ifeq "${A}" 'B'
gecho ifeq "${A}" 'B' == YES
endif
ifneq "${A}" 'C'
gecho ifneq "${A}" 'C' == YES
endif
# style 4 for the ifeq statement.
ifeq "${A}" "B"
gecho ifeq "${A}" "B" == YES
endif
ifneq "${A}" "C"
gecho ifneq "${A}" "C" == YES
endif