GNU Make manual 学习笔记 C语言 / c++ 构建工具
3-2.变量
3-2-1.变量的定义
Makefile
.PHONY: print
Immediate_var := _immediate_$(var) # 将右边的值赋值给Immediate_var变量,
#立即量,马上赋值,就是会在解析这个文件的时候找到变量$(var)的值,然后将完整的右边的值赋值到左边
#如果运行到这里var没有值,就没有值了,下面的语句,可以重新使用 = 为这个变量赋值
Lazy_var =_lazy_$(var) # 将value赋值给Lazy_var的变量,
#如果后面改变了这个中,引用这个变量的recipe在调用的时候会更新为最新的值,就是最下面定义的值
var =_value_to_be_change
Immediate :=$(var)_immediate#这个立即量就会有值
setIfAbsent ?= _set_if_absent # 如果变量没有值,就赋值,如果有值了,就不再赋值,就是不再更新值
setIfAbsent ?= _can_not_revise
append_var =_want_to_be_append
append_var +=_this_is_append_message. #相当于字符串append
print:
@echo var___________________=__________$(var) ;
@echo lazy_var______________=_________$(Lazy_var);
@echo immediate_var_________=__________$(Immediate_var);
@echo setIfAbsent_var_______=________$(setIfAbsent);
@echo append_var____________=__________$(append_var);
var =_value_changed #在执行的语句后面变更变量的值,值依然可以改变
3-2-2.Secondary Expansion $$
GNU make also has the ability to enable a second expansion of the prerequisites (only) for some or all targets defned in the makefle.
Makefile
.PHONY: all clean
all: main lib
#这里是定义了用于依赖的变量,简单说就是有两组源文件
.SECONDEXPANSION:
main_OBJS := src/main.o src/try.o src/test.o
lib_OBJS := lib/lib.o lib/api.o
#这里是写了两个target,这两个target的规则是模式相同的
# $@引用的是target,例如将main带入,就是$$(main_OBJS)
main lib : $$($$@_OBJS)
gcc $^ -o $@
#将规则中的依赖作为源文件,使用gcc编译为一个可执行文件,文件的名字是target,
#这里的target是在使用的时候的target,例子make main或者make lib
clean:
rm -rf *.o *.exe
需要项目结构
执行后的结果是,在当前文件生成了两个exe文件,并且在每个源文件都生成了.o文件,自动生成的.o文件是make有pattern rule
3-2-3.特殊的变量VPATH
VPATH可以理解为,指定prerequires的查找路径
例如上面的例子可以改为
VPATH =src lib #VPATH可以设定多个值,相当于一个path list
指定了查找路径就可以直接写文件的名字,不用写路径
.SECONDEXPANSION:
main_OBJS := main.o try.o test.o
lib_OBJS := lib.o api.o
main lib : $$($$@_OBJS)
gcc $^ -o $@
但是如果VPATH的多个路径中,存在同名的文件,那么是会报错的。
例如 , 下面两个main.o是会造成错误的。
main_OBJS := main.o try.o test.o
lib_OBJS := main.o lib.o api.o
是否使用VPATH,可以根据需要确定
3-2-4.make缓存的变量
使用make -p 命令,会将这些变量打印出来
下面是摘出来的一些变量
=========C语言编译的语句==========
# default 定义使用的编译器cc有说法就是原来的gcc
CC = cc
# default 预编译
PREPROCESS.S = $(CC) -E $(CPPFLAGS)
# default 编译成二进制,就差链接
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
# default 链接
LINK.o = $(CC) $(LDFLAGS) $(TARGET_ARCH)
# default 编译
COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_MACH) -c
# default 链接
LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_MACH)
# default 链接
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
# default 链接
LINK.s = $(CC) $(ASFLAGS) $(LDFLAGS) $(TARGET_MACH)
===============================命令和参数====================================================
# default make的命令
MAKE_COMMAND := make
# default make的版本
MAKE_VERSION := 4.2.1
# default make的命令
MAKE = $(MAKE_COMMAND)
# default 库的文件名样式
.LIBPATTERNS = lib%.dll.a %.dll.a lib%.a %.lib lib%.dll %.dll
# default 查找include的路径
.INCLUDE_DIRS = /usr/include /usr/include
# default 输出的选项,简单理解是gcc -o $@可以写为 gcc $(OUTPUT_OPTION)
OUTPUT_OPTION = -o $@
# default Linux下删除文件的命令,window下需要cygwin或者mingw
RM = rm -f
# default 使用的shell的位置
SHELL := /bin/sh
# default 静态库的打包命令
AR = ar
# makefile 当前工作目录
CURDIR := /cygdrive/f/temp/makeLearning/HelloWorld
# environment 系统的环境变量
TEMP = /cygdrive/c/Users/JimmyLee/AppData/Local/Temp
===========================================自动变量======================================
# automatic
$@ 当前target的名字,是实际执行recipe的target ,如果target是一个库的target,那么就是这个库的名字
# automatic
$< 第一个prerequires的名字
# automatic
$^ 所有prerequires的名字,如果有重复将会去除
# automatic
$? 表示prerequires中变化了的值
#lib: foo.o bar.o lose.o win.o
# ar r lib $? #foo.o bar.o lose.o win.o的文件发生变化的才被选中打包
# automatic
$% foo.a(bar.o):bar.o
recipe
# 文档上写 $@就是foo.a $%就是bar.o 如果target不是archive那么返回空
#试不出来
# automatic
$* 需要是make识别的后缀,最好不要使用了例如target是mylib.a,那么$*就是mylib,可是make不识别就返回空
# automatic
$+ 类似$^,不同的是没有去重
# automatic
$| The names of all the order-only prerequisites, with spaces between them.??????
=================使用上面自动变量的方式匹配prerequires来表示路径(D)或者文件(F)=======================
# automatic
$(@D) 当前target文件的所在路径,例如$@表示dir/foo.o,那么$(@D)就是dir
# automatic
$(@F) 当前target的文件名字,例如$@表示dir/foo.o,那么$(@F)就表示foo.o
# automatic
$(*D) 路径的名字,使用$*的方式匹配prerequirs
# automatic
$(*F) 文件的名字,使用$*的方式匹配prerequires
# automatic
$(%D)
# automatic
$(%F)
# automatic
$(<D)
# automatic
$(<F)
# automatic
$(^D)
# automatic
$(^F)
# automatic
$(+D)
# automatic
$(+F)
# automatic
$(?D)
# automatic
$(?F)
自动变量的例子
Makefile
test_target : src/main.o test.o
@echo $@ #当前target的名字
@echo $< #第一个prerequires的名字
@echo $^ #全部prequires的名字,使用空格分隔,去重
@echo $? #prequires中出现了变化的内容,
@echo $+ #不去重的 $^
@echo $(@D) #target的路径
@echo $(@F) #target的文件名
@echo $(<D) #第一个prequires的路径
@echo $(<F) #第一个prequires的文件名
@echo $(^D) #全部prequires的路径,使用空格分隔
@echo $(^F) #全部prequires的文件名
@echo $(?D) #prequires中变化的内容的路径
@echo $(?F) #prequires中变化的内容的文件名
@echo $(+D) #不去重的$(^D)
@echo $(+F) #不去重的$(^F)
项目的简单结构
∗ 和 *和 ∗和%
Makefile
#这里的target使用的是Archive Members as Targets的写法 archive(member)
foolib.a$(libsource.o):libsource.o
@echo "%="$% "@="$@ "*="$*
3-2-5.变量在不同Makefile中的传递
Makefile
include lib/nestFile
makefile_var ="on top"
export makefile_var
lib/nestFile
print :
@echo "in nest file "$(makefile_var)
3-2-6变量的代换substritution
语法
$(var:a=b)或者${var:a=b}
例子,可以用来改后缀
.PHONY: print clean
foo = a.c b.c c.c d.o e.b
print :
@echo $(foo:.c=.o) #将.c后缀改为.o后缀,:后面不能有空格
3-2-7 取消一个变量
例子
foo =value
undefine foo #使用undefine来取消一个变量的定义,这样下面$(foo)就是空
print :
@echo $(foo)