Makefile中用foreach,eval,call实现将目标文件编译到指定目录

博主要建立一个工程目录,但愿将全部的.c文件都编译成.o并存放到out/目录下。以下:shell

.
├── d1
│   ├── aa.c
│   └── dd.c
├── main.c
├── Makefile
└── out

通过一夜的尝试,最终使用了foreach函数实现了这个目标:数组

TARGET=test
ALL_SOURCES=$(shell find -name "*.c")

SOURCE_TO_OBJECT = ./out/$(subst .c,.o,$(notdir $(1)))
ALL_OBJECTS=$(foreach src,$(ALL_SOURCES),$(call SOURCE_TO_OBJECT,$(src)))

define CREATE_OBJECT_TARGET
$(call SOURCE_TO_OBJECT,$(1)) : $(1)
	gcc -c -o $$@ $$^
endef

all: $(TARGET)

clean:
	-rm $(ALL_OBJECTS)
	-rm $(TARGET)

$(TARGET):$(ALL_OBJECTS)
	gcc -o $@ $^

$(foreach src,$(ALL_SOURCES),$(eval $(call CREATE_OBJECT_TARGET,$(src))))

大概思路是这样的:
首先,ALL_SOURCES=$(shell find -name "*.c"),我将当前目录下的全部.c文件找到并赋值给ALL_SOURCE变量。
而后,ALL_OBJECTS=$(foreach src,$(ALL_SOURCES),$(call SOURCE_TO_OBJECT,$(src))),对每一个一ALL_SOURCE中的源文件进行处理,将每一个文件名去除路径,并将后缀.c替换成.o,再加上./out前缀就成了目标文件名。注意:函数调用中不能随意地加空格!!
SOURCE_TO_OBJECT是一个将源文件名转换成目标文件名的函数。上面用$(call ...) 对它进行调用。函数

而后,我想为每一个目标文件创建依赖关系,以下:code

./obj/main.o : main.c
    gcc -c -o $@ $^

./obj/aa.o : d1/aa.c
    gcc -c -o $@ $^

./obj/bb.o : d1/bb.c
    gcc -c -o $@ $^

文件个数少还好说,若是工程大了,上百个文件维护起来很吃力。因而想到要用 $(foreach ...) 函数来实现。建立这么一个函数,用于生成目标与文件依赖关系:ip

define CREATE_OBJECT_TARGET
$(call SOURCE_TO_OBJECT,$(1)) : $(1)
	gcc -c -o $$@ $$^
endef

转入的一个参数$(1)是源文件全路径。
注意:其中的 gcc -c -o $$@ $$^,是双 $ 符号。字符串

再用以下的$(foreach ...)函数达到对每个源文件都创建一个目标的目的:
$(foreach src,$(ALL_SOURCES),$(eval $(call CREATE_OBJECT_TARGET,$(src))))编译

其中用到的命令有:test

  • notdir,从全路径的文件名,提取出文件名称。至关于shell的basename
  • subst,字符串替换
  • foreach,对数组中的每个元数作处理
  • call,调用自定义宏
  • eval,将字串应用到Makefile上下文
  • shell,执行shell脚本

其它经常使用的函数还有:变量

  • dir
  • addprefix
  • patsubst
  • strip
  • sort
  • wildcard

若是你们还有别的什么更好的方法,欢迎留言。gcc

相关文章
相关标签/搜索