层级目录结构的Makefile递归编译方法 以你之姓@ 2022-05-23 09:16 372阅读 0赞 ### 层级目录结构的Makefile递归编译方法. ### * * * 层级目录结构的Makefile编写方法. * 0.前言 * 1.如何编译整个工程 * 2.过滤每层不需要编译的目录 * 3将所有输出文件定向输出. #### 0.前言 #### 假如现在有这样一个目录结构: ![70][] 要怎么实现简洁的自动化编译呢? 现在我`想要实现的效果` 1.在顶级目录,直接make即可编译整个工程. 2.可以很方便的在Makefile中添加或过滤掉只有我想编译的目录或不需要编译的目录. 3.新添加的模块,只需要直接编写本模块的Makefile即可,其余地方不需要改动. 4.将所有输出的目标文件和可执行文件,定向输出到指定目录(如out/bin;out/obj) 因为新建的工程,暂且就这些基本功能,如果还有没实现的好目标,再继续添加. 接下来一个一个目标的看看怎么实现. #### 1.如何编译整个工程 #### 想要编译整个工程,那么所有需要编译的目录都要能够编译. 最简单的方法:`依依编译每一个需要的目录.` 如: WIFI := wifi BLUETOOTH := bluetooth all: cd $(WIFI); make cd $(BLUETOOTH); make 很直观,但是每个目录写一遍,就是每添加一个模块,你都得在Makefile里面加一句,写起来内容偏多. 另一种`递归的编译层层目录.` 要这么做,首先需要获得每层目录下的目录名: GET\_SUBDIRS1 := $(shell find . -maxdepth 1 \-type d) GET\_SUBDIRS2 := $( basename $(patsubst ./%,%,$(GET\_SUBDIRS1))) SUBDIRS := $(GET\_SUBDIRS2) 之后在每层目录make -C 进入目录编译即可 all : $(SUBDIRS) $(SUBDIRS) : ECHO $(MAKE) -C $@ ECHO : @echo "Compiling " $(SUBDIRS) "..." #### 2.过滤每层不需要编译的目录 #### 有些不需要编译的目录,像include,env,document 进去make会因为找不到make停止编译. 所以我们需要在每层目录过滤掉所有不需要编译的目录. 这里我们可以设置一个通用的Makefile环境文件,如Makefile.env OBJOUT := $(ROOT\_DIR)/out/obj/ EXEOUT := $(ROOT\_DIR)/out/bin/ INCLUDE\_DIR := $(ROOT\_DIR)/source/include MAKE := make CC := gcc GET\_SUBDIRS1 := $(shell find . -maxdepth 1 -type d) GET\_SUBDIRS2 := $(basename $(patsubst ./%,%,$(GET\_SUBDIRS1))) GET\_SUBDIRS3 := $(filter-out $(EX\_INCLUDE), $(GET\_SUBDIRS2)) SUBDIRS := $(GET\_SUBDIRS3) 之后再每层的Makefile将Makefile.env包含进来,并里面配置一个EX\_INCLUDE变量进行过滤. 顶层目录Makefile: CUR\_DIR := $(shell pwd) \#ROOT\_DIR := $(ROOT\_DIRS) SOURCE\_DIR := $(CUR\_DIR)/ source MAKEFILE\_PARA := $(SOURCE\_DIR)/Makefile. env EX\_INCLUDE := PlatformHeandle out document env include $(MAKEFILE\_PARA) all : $(SUBDIRS) $(SUBDIRS) : ECHO $(MAKE) -C $@ ECHO : @echo "Compiling " $(SUBDIRS) "..." 其余层的Makefile均是这样编写,只需要改一下Makefile.env的路径. #### 3将所有输出文件定向输出. #### 这个比较简单吧,只要知道根目录,然后直接在编译的时候输出到指定目录即可. all: $(TARGET) $(TARGET) : $(OBJ) $(CC) $(CFLAGS) $(OBJOUT)$^ -o $(EXEOUT)$@ @echo "Compiling" $@ "end\\n" %.o : %.c @echo "Compiling" $< "..." $(CC) $(CFLAGS) -c $^ -o $(OBJOUT)$@ %.o : %.cpp @echo "Compiling" $< "..." $(CC) $(CFLAGS) -c $^ -o $(OBJOUT)$@ 那么问题来了,底层的Makefile怎么知道根目录呢. 上一级Makefile中的变量,底层Makefile是不知道的. 1.最呆的方法,写死的,每一层Makefile都来个相对根目录深度的../: ROOT\_DIR = ../../../ 2.通过配置一个都知道的系统环境,我在env/env.sh里面声明. 当然,env.sh 还可以干一些其他事,如创建out下的输出目录. ROOT\_DIRS=$( pwd) export ROOT\_DIRS mkdir \-p @\{ROOT\_DIRS\}/ out/bin mkdir \-p @\{ROOT\_DIRS\}/ out/obj 之后只要在根目录 source ./env/env.sh 即可,然后在Makefile里面取它. ROOT\_DIR := $(ROOT\_DIRS) SOURCE\_DIR := $(ROOT\_DIR)/source MAKEFILE\_PARA := $(SOURCE\_DIR)/Makefile.para EX\_INCLUDE := 这样即实现了这个工程简便的自动化编译了,以后也能很快捷的修改. 如果有什么不足的地方或者更好的方法欢迎提出. [70]: /images/20220523/cdb8ae44524642b4997adcaffce37562.png
还没有评论,来说两句吧...