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 service
SUB_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 common
SUB_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.mk
TARGET := $(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 config
ALL_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

=

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

=:

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

makefile编译子目录的更多相关文章

  1. live555学习(一)通读Makefile编译live555

    live555学习(一)通读Makefile编译live555 live555 编译live555 学习开源 live555学习(一)通读Makefile编译live555 前言 live555简介 ...

  2. C++---初识《通过g++ / makefile 编译和调用动态库so文件》(ubuntu)

    C++---初识<通过g++ / makefile  编译和调用动态库so文件>(ubuntu) ------------------------目录------------------- ...

  3. gcc与makefile编译 BY 四喜三顺

    gcc编译控制过程:(假设源代码为a.c)(1)源文件到预处理文件:    gcc -E -o a.cxx a.c    a.cxx显示调用哪些头文件(2)生成汇编代码:              g ...

  4. 【Linux学习】 写一个简单的Makefile编译源码获取当前系统时间

    打算学习一下Linux,这两天先看了一下gcc的简单用法以及makefile的写法,今天是周末,天气闷热超市,早晨突然发现住处的冰箱可以用了,于是先出去吃了点东西,然后去超市买了一坨冰棍,老冰棍居多, ...

  5. Linux Makefile 编译速度的优化【转】

    转自:https://blog.csdn.net/QQ1452008/article/details/51851801 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...

  6. makefile 编译指定目录

    makefile 编译指定目录 sub1=test1 sub2=test2 subs = sub1 sub2 SUBDIRS =$(foreach i, $(subs), $($(i))) .PHON ...

  7. CMake 工程调用 Makefile 编译项目

    本文主要介绍如何将一个依赖 Makefile 项目(MIDG)移植到 CMake 上. 首先介绍项目文件结构,文件主要由三个目录组成 3rdParty include src 其中,3rdParty ...

  8. 由于makefile编译所有子目录中 sed 's,/($*/)/.o[ :],/1.o $@ : ,g' <$@ > $@ 的解释

    这个语句分为好几层,我们一层一层来看 1. sed 's,/($*/)/.o[ :],/1.o $@ : ,g' <$@ > $@ 首先看加粗这一层,$@表示目标参数中的.d文件, '&l ...

  9. Makefile编译库

    funs.h: #ifndef __FUNS_H__ #define __FUNS_H__ void fun1(); #endif funs.c #include "funs.h" ...

随机推荐

  1. Jemter请求乱码解决方案

    1:jemeter查看结果树乱码 (1)在jmeter的bin目录下找到jmeter.properties这个文件,添加上 sampleresult.default.encoding=utf-8 (2 ...

  2. 鸿蒙内核源码分析(内存映射篇) | 虚拟内存虚在哪里 | 百篇博客分析OpenHarmony源码 | v15.03

    百篇博客系列篇.本篇为: v15.xx 鸿蒙内核源码分析(内存映射篇) | 虚拟内存虚在哪里 | 51.c.h .o 内存管理相关篇为: v11.xx 鸿蒙内核源码分析(内存分配篇) | 内存有哪些分 ...

  3. 51nod1600-Simple KMP【SAM,树链剖分】

    正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1600 题目大意 给出一个字符串\(s\),每次在最后插入一个字符后求它的 ...

  4. Redis分布式方案:集群

    Redis集群通过分片(sharding)进行数据共享,并提供复制和故障转移功能. 节点 一个Redis集群由多个node组成,连接各节点的命令格式如下: CLUSTER MEET 127.0.0.1 ...

  5. NOIP 模拟八 考试总结

    T1星际旅行 给出n个点,m条边,求满足一条路径使得m-2条边经过2次,2条边经过1次的方案数.并且题目中给出有自环. 看到题面我以为是个计数DP,可能是计数题做多了吧哈哈.其实仔细朝图的方向想一想就 ...

  6. Redis缓存穿透、缓存击穿、缓存雪崩的介绍及其解决方案

    首先,来画一张图了解下缓存处理的流程 一.缓存穿透 描述: 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求查询该数据,导致数据库压力过大. 解决方案: 1.接口校验 如鉴权校验.数据合法性 ...

  7. 遇到括号就是栈(bushi)

    CF508E Arthur and Brackets 我在赛场上想都没想直接DP \(O(n^3)\)过了 但别人说正解是栈+贪心 讲讲DP \(bool\) \(dp[i][j]\)表示从第i对括号 ...

  8. NX屏蔽窗口的按钮

    有时候在激活一个命令按钮的时候,需要同时禁止掉另外一个或多个命令按钮 ''' <summary> ''' 取按钮是否敏感 ''' </summary> ''' <para ...

  9. PinPoint单节点部署及客户端配置方法

    在一次做项目中,需要涉及全链路压测,为了更好定位链路中某一节点可能会出现的问题,在繁忙之余,快速部署及应用了该链路工具,分享给大家~ 话不多说,开始部署~ 一.环境配置1.1 获取需要的依赖包进入ho ...

  10. Scrum Meeting 0531

    零.说明 日期:2021-5-31 任务:简要汇报两日内已完成任务,计划后两日完成任务 一.进度情况 组员 负责 两日内已完成的任务 后两日计划完成的任务 困难 qsy PM&前端 完成后端管 ...