新利国际网址新利国际网址

18新利luck
新利国际网址

makefile编译子目录

make子目录常用方法

一般是

SUB_DIR = lib_src service.PHONY: subdirs $(SUB_DIR)subdirs: $(SUB_DIR)$(SUB_DIR): @+make -C $@ foo: baz

或者

subdirs: for dir in $(SUB_DIR); do @+make -C $$dir; done

使用循环的方式比较直观,但是会有这样的问题

当submake报错的时候不会停止,其他submake会继续执行不能体验到make的并行编译 即-j选项子目录之间的依赖不好表示

所以,一般来说会选择第一种来写.但是,当用第一种书写时,怎么表达make子命令(即:make install)呢?

make子命令书写

SUB_DIR_TEST = $(SUB_DIR:%=%_test)test: $(SUB_DIR_TEST)$(SUB_DIR_TEST): @+make -C $(@:%_test=%) test.PHONY: test subdirs $(SUB_DIR_TEST)

核心就是对子目录名字进行包裹一下,把包裹后的名字当作新的伪目标进行构建

实例

以下是我从工作项目中拷出来的总共三个级别的目录

根目录lib_src service实际编译目录:game gate

所以列举了3个makefile

项目目录大致结构

目录做了一些删减bin输出目录:deploy/bin

├── deploy│   └── bin├── deps│   └── tinyxml│   ├── include│   │   └── tinyxml│   │   └── tinyxml.h│   └── lib│   └── libtinyxml.a├── lib_src│   ├── auth│   │   ├── auth.cpp│   │   └── auth.h│   ├── common│   │   ├── common.cpp│   │   └── common.h│   └── lib└── service ├── game │   └── game.cpp └── gate

项目根目录下的Makefile

MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))SUB_DIR = lib_src serviceSUB_DIR_TEST := $(SUB_DIR:%=%_test)SUB_DIR_CLEAN := $(SUB_DIR:%=%_clean)all : $(SUB_DIR) lib_src: @+make -C $@service:lib_src @+make -C $@ clean:$(SUB_DIR_CLEAN) #$(foreach N, $(SUB_DIR),make clean -C $(N);)$(SUB_DIR_CLEAN): @+make clean -C $(@:%_clean=%)test:$(SUB_DIR_TEST) @echo $(MKFILE_PATH) $(SUB_DIR_TEST): @+make test -C $(@:%_test=%) .PHONY: all test clean $(SUB_DIR) $(SUB_DIR_TEST) $(SUB_DIR_CLEAN)

lib_src下的Makefile

MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))SUB_DIR = auth commonSUB_DIR_CLEAN := $(SUB_DIR:%=%_clean)SUB_DIR_TEST := $(SUB_DIR:%=%_test)all : |mk_dir $(SUB_DIR) $(SUB_DIR): mk_dir @+make -C $@ mk_dir: @mkdir -p bin clean:$(SUB_DIR_CLEAN) #$(foreach N, $(SUB_DIR),make clean -C $(N);) $(SUB_DIR_CLEAN): @+make clean -C $(@:%_clean=%) test:$(SUB_DIR_TEST) @echo $(MKFILE_PATH) $(SUB_DIR_TEST): @+make test -C $(@:%_test=%) .PHONY: all test clean mk_dir $(SUB_DIR) $(SUB_DIR_TEST) $(SUB_DIR_CLEAN)

game下的Makefile

编译选项这些忽略吧

MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))include ../../global.mkTARGET := $(BIN_DIR)/game_svr$(BIN_TAG)CUR_INC_FLAGS := -I$(FRAME_INC) -I./ -I$(MYSQL_INC)CUR_LINK_FLAGS := $(LDFLAGS) -L$(MYSQL_LIB)CUR_CPPFLAGS := $(CPPFLAGS) $(CUR_INC_FLAGS) SUB_DIR := app bll dal db thread configALL_OBJS = $(wildcard $(OBJ_DIR)/*.o)all : |$(OBJ_DIR) $(TARGET) $(TARGET) : $(TARGET_OBJS) $(SUB_DIR) $(CXX) -o $@ $(ALL_OBJS) $(CUR_LINK_FLAGS) @echo "#### compile ok "$(TARGET) "####" $(OBJ_DIR)/%.o : %.cpp $(CXX) $(CUR_CPPFLAGS) -c $< -o $@ $(OBJ_DIR): @mkdir $@$(SUB_DIR): @echo "#### compile sub dir start ####" $@ @+make -C $@ @echo "#### compile sub dir end ####" $@clean: @rm -f $(wildcard $(OBJ_DIR)/*.o) $(TARGET) test: @echo $(MKFILE_PATH).PHONY: all test clean .PHONY: $(SUB_DIR)

简要语法说明

$(SUB_DIR:%=%_test)表示文件名加后缀,结果为lib_src_test service_test

$(@:%_test=%)表示去掉后缀,结果为lib_src service

=

在真正执行命令的时候才会对变量求值,所以变量值可能会在中间因为其他引用的其他变量被改变而不是预期的

=:

在赋值的时候直接对变量求值,以后如果不重新赋值是不会变化的

欢迎阅读本文章: 陶远忠

新利国际中文登录

18新利luck