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. 低差异序列 (low-discrepancy sequences)之Hammerysley在半球中采样点方法的介绍

    半球上的Hammersley 源作者:Holger Dammertz 一组关于如何在2D中使用Hammersley点集以在着色器程序中快速实用地生成半球方向的笔记.如果你发现任何错误或有意见,不要犹豫 ...

  2. P5163-WD与地图【tarjan,整体二分,线段树合并】

    正题 题目链接:https://www.luogu.com.cn/problem/P5163 题目大意 给出\(n\)个点\(m\)条有向边,点有权值,要求支持操作 删除一条边 修改一个点的权值 求一 ...

  3. Visual Studio Code (VSCode) 配置 C/C++ 开发编译环境

    前言 工作多年,突然发现很多C++的基础都忘记了,加之C++不断更新换代后的各种新特性,于是想重拾C++的基础学习.虽然现在工作都是Linux平台,但考虑到个人方便,自己也仅仅想重温语法,家里家外都可 ...

  4. Redux使用指南

    Redux使用指南 00-简介 本文主要是用来记录Redux结合React的使用过程,帮助大家在使用Redux的时候,能够更好的理解Redux,从而更好地使用它 01-为什么需要Redux JavaS ...

  5. NOIP 模拟 六十八

    咕了十几场了,还是写一写吧.. T1 玩水 发现满足三个人路径不同必须要有2个及以上的斜线相同结构,需要注意如果同一行或者同一列的话必须要相邻才行. #include<bits/stdc++.h ...

  6. 前端快闪四: 拦截axios请求和响应

    马甲哥继续在同程艺龙写一点大前端: 今天我们来了解一下 如何拦截axios请求/响应? axios是一个基于 promise 的网络请求库,可以用于浏览器和 node.js, promise 类似于C ...

  7. JS 开发中数组常用的方法

    大家有没有想过,js数组为什么会有这么多的方法,没错,就是为了不同场景下处理数据的需要,就像设计模式一样,都是为了能更好的处理当前场景的需要. 首先怎么创建一个数组呢, // 两种方式 // 1,构造 ...

  8. java语言程序设计与数据结构(基础篇)第四章答案

    4.1 import java.util.Scanner; public class Welcome { public static void main(String[] args) { Scanne ...

  9. Python读取Excel表格

    前言:需要进行自动化办公或者自动化测试的朋友,可以了解下此文,掌握Python读取Excel表格的方法. 一.准备工作: 1.安装Python3.7.0(官网下载安装包) 2.安装Pycharm(官网 ...

  10. python爬虫时,解决编码方式问题的万能钥匙(uicode,utf8,gbk......)

    转载   原文:https://blog.csdn.net/xiongzaiabc/article/details/81008330 无论遇到的网页代码是何种编码方式,都可以用以下方法统一解决 imp ...