2. user_debug 目标是留给用户打印变量使用的。只要在该目标下调用 $(call PRINT, 变量 ) ,就能在执行 makefile 时打印出指定的变量的值。编译时需要指明打印等级, 0- 打印所有变量, 1- 打印内部变量, 2- 打印用户定义的变量。只打印用户变量使用 make all DEBUG_LEVEL=2 。 3. user_clean 目标是留给用户做清理工作的,在 make clean 之前会调用到。 4. user 目标是留给用户编译时使用的。比如可以在编译完成之后自动清理掉生成的不需要的 .o 文件,可以直接在 user 后边加上一个依赖 clean 。 5. 主目录中编译整个工程直接使用 make all ,只清理 .o 和可执行文件使用 make clean ,清理掉所有生成的文件使用 make distclean 。也可以指定单个目录进行编译,比如 make –C app 就会只编译 app 目录, make –C app clean 就会单独清理掉 app 目录。 6. 非主目录编译需要先在主目录中成功 make all 一次,只有生成了配置文件 rules.conf 才能找到编译时需要依赖的规则文件。所以要在非主目录中编译,不能使用 make distclean 命令。在非主目录中编译直接使用 make 就可以了,清理使用 make clean ,打印变量使用 make DEBUG_LEVEL=2 。
%.o: %c 是一种指定泛型的目标与依赖方式,在同一个 makefile 中,只要其他目标有依赖后缀为 .o 目标,那么执行到该目标时,就会执行%.o: %.c。这时-D__NOTDIR_FILE__=$(notdir $$<就代表源文件的路径,它可能和源文件名一样,也可能在文件名前边带了路径,所以使用$(notdir $ 可以除掉路径,只留下文件名。那么这里为何要定义一个 -D__NOTDIR_FILE__ 的宏呢,因为如果这里的 $< 带了路径,那么 __FILE__ 宏一定带有路径,我想很多人在打印文件名时也遇到过这样的问题,只是没有深究。因此,在打印文件名时就可以直接使用 __NOTDIR_FILE__ 宏了,而不使用 __FILE__ 宏。为何不直接替换掉 __FILE__ 的内容,因为 __FILE__ 是 gcc 自带的内部定义宏,尽量不要修改。还有一种方法是调用 basename(__FILE__) 函数,这样可以得到不带路径的文件名,但是没有前一种高效,因为每次打印都要调用一次 basename 函数。 关于彩色警告和错误的打印其实就是使用 sed 在打印的字符串前后加了颜色编码。
find_source_objs = $ ( subst $ ( type ) , . o , $ ( wildcard $ ( patsubst % , % / * $ ( type ) , $ ( SUBDIRS ) ) ) )
SUB_OBJS = $ ( foreach type , $ ( source_type ) , $ ( find_source_objs ) )