java递归编译目录,层级目录结构的Makefile递归编译方法

0.前言

假如现在有这样一个目录结构:

4dc4639c44b141f380f14f3c85ea0087.png

要怎么实现简洁的自动化编译呢?

现在我想要实现的效果

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 :=

这样即实现了这个工程简便的自动化编译了,以后也能很快捷的修改.

如果有什么不足的地方或者更好的方法欢迎提出.

0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值