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. 让selenium规避网站的检测

    在使用selenium对某些网站模拟访问的时候会被检测出来,检测出来之后就有可能拿不到我们想要的数据,那么我们怎么可以规避掉呢? 在使用谷歌浏览器的时候我们右键-检查-console-输入window ...

  2. P4201-[NOI2008]设计路线【结论,树形dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P4201 题目大意 给出\(n\)个点的一棵树开始所有边都是白色,选出若干条没有公共点的路径将上面所有边变为黑色. ...

  3. 密码学系列之:1Password的加密基础PBKDF2

    目录 简介 PBKDF2和PBKDF1 PBKDF2的工作流程 详解PBKDF2的key生成流程 HMAC密码碰撞 PBKDF2的缺点 总结 简介 1password是一个非常优秀的密码管理软件,有了 ...

  4. FastAPI 学习之路(七)字符串的校验

    系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...

  5. linux版火狐浏览器部署详解

    Firefox下载地址 Firefox全历史版本下载: http://ftp.mozilla.org/pub/firefox/releases/ Firefox驱动问题下载  https://gith ...

  6. Spark RDD编程(博客索引,日常更新)

    本篇主要是记录自己在中解决RDD编程性能问题中查阅的论文博客,为我认为写的不错的建立索引方便查阅,我的总结会另立他篇 1)通过分区(Partitioning)提高spark性能https://blog ...

  7. 【UE4 C++】定时器 Timer 与事件绑定

    概念 定时执行操作,可执行一次,或循环执行直到手动终止 定时器在全局定时器管理器(FTimerManager 类型)中管理.全局定时器管理器存在于 游戏实例 对象上以及每个 场景 中 定时器需要绑定委 ...

  8. 【UE4 C++】播放声音、特效

    播放声音 PlaySoundAtLocation() USoundCue* HitSound = LoadObject<USoundCue>(this, TEXT("SoundC ...

  9. Jmeter之BeanShell 断言

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15436864.html 博客主页:https://www.cnblogs.com/testero ...

  10. 关于tkinter

    tkinter介绍 tkinter是python自带的GUI库,是对图形库TK的封装tkinter是一个跨平台的GUI库,开发的程序可以在win,linux或者mac下运行 组件概念 一个窗口中任意内 ...