1. makefile中变量定义最后空格的影响
在Makefile中定义变量时,一定要注意最后一定不要有空格
举例如下,
AAA := `pwd` # current path // 经常写注释,习惯在#前加一个或多个空格
obj: $(AAA)/a/b.txt // 此时依赖展开后为: obj: `pwd` /a/b.txt // 显然变成了两个依赖
@echo xxxx
2. “order only”依赖
举例:
LIBS = libtest.a
foo : foo.c | $(LIBS)
$(CC) $(CFLAGS) $< -o $@ $(LIBS)
“|” 左边是常规依赖(正常前提目标(Normal Prerequisites)),右边是order only依赖(命令前提目标(order-only Prerequisites))。
当常规依赖有变化时,目标被重新编译
但当order only依赖更新时,目标不会被重新编译,即libtest.a被更新时,foo不被给更新,但如果libtest.a有无到有时,目标重新编译
当我们需要执行某个或某些规则,但不能引起生成目标被重新生成。此时你就需要使用命令前提目标。
3. 赋值
makefile中有两种赋值:递归赋值(或延时赋值)和直接赋值
= 延时赋值,使用时才能确定变量的值,即使用的时候才递归展开来得到变量的值,所以也称递归赋值
?= 延时赋值,但只能定义第一次的延时变量,即如果之前没有定义该变量,则有=赋值相同,如果以前定义过,则不再重新定义
:= 直接赋值,即直接展开变量,不能使用后面定义变量的值,只能用前面定义好的变量的值
define来定义变量,实质定义命令包,使用eval函数来使用,它属于递归展开式变量
makefile执行过程:两次扫描makefile,然后执行目标。扫描是一行一行进行的,如果需要变量的值,只会查找之前变量的值,而不会查找后面。所以两次扫描后变量值的改变只会在生成目标时才是用到,也就是说递归赋值和直接赋值只对生成目标时才有效,而扫描过程中没有影响(例如使用ifeq ($(AAA),)中变量AAA的值并不会使用该语句后面的AAA的值,如果该语句之前没有对AAA赋值,则$(AAA)就时空)),举例如下:
$(warning $(AAAA)) // 输出: 空
ifeq ($(AAAA),"aaaa") // 不成立
$(error "Abort! ...")
endif
AAAA = aaaa
$(warning $(AAAA)) // 输出: aaaa
all: $(LOCAL_PATH)/a/b/c/a.txt b.txt //此时LOCAL_PATH为空,因为之前没有定义,在后面才有定义
@echo "AAAA=$(AAAA)" // 输出: aaaa
LOCAL_PATH=`pwd`
变量有重名时,后面的变量覆盖前面的变量。
下面例子也说明延时赋值只是在命令行中其作用
AAA=a
BBB=b
$(AAA):$(BBB)
@echo "$(AAA)---$(BBB) //输出aaa-bbb
@echo "$@---$<" // 输出a-b 所以 依赖是可以保存值的,而不会因为后面值的改变而改变。
AAA=aaa
BBB=bbb
4. -Wl,--no-undefined用处
一般情况下,编译so文件时,允许没有定义的函数,只需要有函数声明即可。但在android中使用so就不能出现函数未定义了。所以android-ndk中编译出来的so总是可以被使用的,而不用担心函数未定义。原因就是编译时使用了该参数。
5. call函数
1> error: *** commands commence before first target. Stop.
举例:
define print
@echo "Log: $1"
endef
target: abc:=$(call print,Hello)
$(abc)
提示error,如标题红色部分
如下修改可以解决,但是不知道为什么,在此注释一下,待解决
target: abc:=$(call print,Hello) // print函数位置必须在该调用之前,否则没定义,也就无输出
target:
$(abc)
或者直接直接调用
target:
$(call print,Hello) // print函数位置任意
6. gcc 编译时与位置有关(为什么啊??????)
gcc main.c -o test -lGLU -lglut // 正确
gcc -lGLU -lglut main.c -o test // 出现link error