[时间:2017-06] [状态:Open]

[关键词:makefile,gcc,编译,shell命令,目标文件]

0 引言及目标

之前使用Makefile都是把源文件和目标文件放到同一个目录编译。近期看到有些编译工具支持将目标文件放到独立的目录,将源代码和目标文件(*.o)分开,这样查看代码以及目录结构也会相对清晰些。

下面我们开始展开这个过程。

1 准备工作

我们的目录结构是这样的

src
|---- audio
|--- audio.h
|--- audio.cpp
|---- video
|--- video.h
|--- video.cpp
|---- main.cpp
Makefile
obj

obj目录用于存放编译之后的目标文件,这个是自动生成的目录。src目录包含需要编译的源代码。相关代码及Makefile都可以从我的SampleCode-git下载。

常规的情况是把*.o目标文件和源代码放到同一个目录。

2 单Makefile编译整个工程

注意这个Makefile和目标文件输出目录在同一级。

OBJ_FOLDER := objs
vpath %.cpp src/audio src/video
#源文件,自动找所有.cpp文件,并将目标定义为同名.o文件
SOURCE := $(wildcard src/*.cpp) $(wildcard src/audio/*.cpp) $(wildcard src/video/*.cpp)
OBJS := $(SOURCE:%.cpp=${OBJ_FOLDER}/%.o) #目标文件名,输入任意你想要的执行文件名
TARGET := separator #编译参数
CC := g++
LIBS :=
LDFLAGS :=
DEFINES :=
INCLUDE := -I.
CFLAGS := -g -Wall -O3 $(DEFINES) $(INCLUDE)
CXXFLAGS:= $(CFLAGS) #下面的基本上不需要做任何改动了
.PHONY : everything objs clean veryclean rebuild everything : $(TARGET) all : $(TARGET) ${OBJS} : $(OBJ_FOLDER)/%.o : %.cpp
mkdir -p $(OBJ_FOLDER)/$(<D)
$(CC) -c $(CXXFLAGS) $< -o $@ rebuild: veryclean everything clean :
rm -fr *.so
rm $(OBJS) veryclean : clean
rm -fr $(TARGET) $(TARGET) : $(OBJS)
$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)

相比于常规情况,主要修改如下:

  1. OBJS := $(SOURCE:%.cpp=${OBJ_FOLDER}/%.o) 目标文件列表换到单独的目录。
  2. ${OBJS} : $(OBJ_FOLDER)/%.o : %.cpp 设置依赖规则

    mkdir -p \((OBJ_FOLDER)/\)(<D) # 创建对应的目录,\((<D)表示\)<所在目录名。

    $(CC) -c $(CXXFLAGS) $< -o $@ # 编译规则

3 多层嵌套的Makefile

先更新下目录结构:

src
|---- audio
|--- audio.h
|--- audio.cpp
|---- video
|--- video.h
|--- video.cpp
|---- main.cpp
|---- Makefile
Makefile
obj

这里在src目录下添加一个Makefile文件。我们的顶级Makefile相对会比较简单,但是为了避免遇到例如:./../obj/xxx.o的文件系统报错,因为../不是一个有效的目录名称,需要从主Makefile中传到参数到子目录的Makefile中。其实现如下:

SOURCE_DIR := src
export LOCAL_PATH := $(shell pwd)
$(warning ${LOCAL_PATH}) .PHONY: all everything clean veryclean rebuild
all:
$(MAKE) -C ${SOURCE_DIR} everything:
$(MAKE) -C ${SOURCE_DIR} $@ clean:
$(MAKE) -C ${SOURCE_DIR} $@ veryclean:
$(MAKE) -C ${SOURCE_DIR} $@ rebuild:
$(MAKE) -C ${SOURCE_DIR} $@

子目录的实现相对简单点,就是把第一句OBJ_FOLDER更新下,修改如下:

OBJ_FOLDER := $(LOCAL_PATH)/objs
#目标文件名,输入任意你想要的执行文件名
TARGET := $(LOCAL_PATH)/separator

这里主要有一个知识点,从主Makefile传递到子文件夹的Makefile中的参数。有三种方式:

  1. 在上层Makefile中使用”export”关键字对需要传递的变量进行声明。比如:

    DEBUG_SYMBOLS = TRUE

    export DEBUG_SYMBOLS

当不希望将一个变量传递给子makefile时,可以使用指示符 unexport来声明这个变量。

2. export一般用法是在定义变量的同时对它进行声明。如下:

export DEBUG_SYMBOLS = TRUE

3. 在命令行上指定变量。比如:

$(MAKE) -C xxx DEBUG_SYMBOLS = TRUE

这样在进入子目录xxx执行make时该变量也有效。

4 小结

至此,最初的问题基本解决了。本文主要参考如下资料:

GNU make使用(二)的更多相关文章

  1. GNU make 总结 (二)

    规则描述了在何种情况下使用什么命令来创建或者更新一个目标.如果在makefile中第一个规则有多个目标的话,那么多个目标中的第一个将会作为make的“终极目标”. 3.1 规则语法 TARGETS : ...

  2. 从零开始之uboot、移植uboot2017.01(二、从入口分析流程)

    原创: To_run_away 从零开始学linux 本节的开始之前,先看一下uboot的链接脚本. 一.链接脚本 /* * Copyright (c) 2004-2008 Texas Instrum ...

  3. 查看centos版本号

    --写在开始-- 玩Linux,不同的版本会有一些细微区别: so,经常需要查看服务器版本号: --正文-- 有以下命令可以查看linux服务器版本号: # lsb_release -a LSB Ve ...

  4. 在Linux下怎么确定哪个网卡对应哪个接口?

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  5. [Linux Kernel]查看CentOS版本方法

    查看CentOS版本方法  有以下命令可以查看:   # lsb_release -a LSB Version:    :core-3.1-ia32:core-3.1-noarch:graphics- ...

  6. buildroot构建项目(三)--- u-boot 2017.11 适配开发板修改 1

    当前虽然编译成功了,但是对于我们自己的目标板并不太适用.还得做一系列得修改. 一.lds 文件分析 u-boot 中最重要得链接文件即是,u-boot.lds.我们可以查看我们编译出来得 u-boot ...

  7. npm 版本问题

    STF之问题篇 https://yq.aliyun.com/articles/221602 装完成后输入stf doctor查看工具依赖是否正确,安装教程可以参考我之前写的,这里不再多说,直接说问题. ...

  8. 给广大码农分享福利:一个业界良心的github仓库,中文计算机资料

    我今天查资料时无意发现的,https://github.com/CyC2018/CS-Notes 这个仓库包含了下列几个维度的计算机学习资料: 深受国内程序员喜爱,已经有超过3万多star了. 1. ...

  9. Yum三方仓库——RPMForge

    参考:How to Enable RPMForge Repository in RHEL/CentOS 7.x/6.x/5.x RPMForge / RepoForge这两个项目已经死亡,不应该使用 ...

随机推荐

  1. 使用PhoneGap搭建一个山寨京东APP(转)

      为什么要写一个App 首先解释下写出来的这个App,其实无任何功能,只是用HTML和CSS模仿JD移动端界面写的一个适配移动端的Web界面.本篇主要内容是介绍如何使用PhoneGap把开发出来的m ...

  2. BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)

    题目链接 若点数确定那么ans = (n-2)!/[(d1-1)!(d2-1)!...(dn-1)!] 现在把那些不确定的点一起考虑(假设有m个),它们在Prufer序列中总出现数就是left=n-2 ...

  3. BZOJ.2229.[ZJOI2011]最小割(最小割树)

    题目链接 题意:给定一张无向图,求任意两点之间的最小割. 在所有点中任选两个点作为源点\(S\).汇点\(T\),求它们之间的最小割\(ans\),并把原图分成两个点集\(S',T'\),用\(ans ...

  4. navicat 官方使用手册,中文版,快捷键大全

    2017年1月23日09:52:51 这个官方中文文档很详细 https://www.navicat.com.cn/manual/online_manual/cn/navicat/win_manual ...

  5. 在现实面前,IT从业者的无奈

    话题:在中国,有多少程序员干到40了? 作者:匿名用户 链接:https://www.zhihu.com/question/33953081/answer/349839986 学历低,计算机理论不高, ...

  6. Java中使用Timer和TimerTask实现多线程

    转自:http://www.bdqn.cn/news/201305/9303.shtml 摘要:Timer是一种线程设施,用于安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行,可以 ...

  7. python 安装pip setuptools

    注意操作前提一定要使用管理员方式运行 python目录要完全允许控制 windows7 下 0.先安装python2.7.13 32位:https://www.python.org/ftp/pytho ...

  8. Standard Series Values in a Decade for Resistances and Capacitances E24 E48 E96

    E3     50% tolerance (no longer used)E6     20% tolerance (now seldom used)E12   10% toleranceE24    ...

  9. GoDaddy账户间域名转移PUSH以及ACCEPT接受域名过户方法

    GoDaddy账户之间的域名进行过户PUSH.以及接受ACCEPT一般发生在我们有要求代购.交易域名账户之间的处理.一般的海外域名注册商账户之间是直接可以用户交易过户的,不需要经过商家允许,但是不同的 ...

  10. android http中请求访问添加 cookie

    第一种HashMap<String, String> map = new HashMap<String, String>();map.put("cookie" ...