GNU make使用(二)
[时间: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)
相比于常规情况,主要修改如下:
OBJS := $(SOURCE:%.cpp=${OBJ_FOLDER}/%.o)目标文件列表换到单独的目录。${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中的参数。有三种方式:
- 在上层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使用(二)的更多相关文章
- GNU make 总结 (二)
规则描述了在何种情况下使用什么命令来创建或者更新一个目标.如果在makefile中第一个规则有多个目标的话,那么多个目标中的第一个将会作为make的“终极目标”. 3.1 规则语法 TARGETS : ...
- 从零开始之uboot、移植uboot2017.01(二、从入口分析流程)
原创: To_run_away 从零开始学linux 本节的开始之前,先看一下uboot的链接脚本. 一.链接脚本 /* * Copyright (c) 2004-2008 Texas Instrum ...
- 查看centos版本号
--写在开始-- 玩Linux,不同的版本会有一些细微区别: so,经常需要查看服务器版本号: --正文-- 有以下命令可以查看linux服务器版本号: # lsb_release -a LSB Ve ...
- 在Linux下怎么确定哪个网卡对应哪个接口?
国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...
- [Linux Kernel]查看CentOS版本方法
查看CentOS版本方法 有以下命令可以查看: # lsb_release -a LSB Version: :core-3.1-ia32:core-3.1-noarch:graphics- ...
- buildroot构建项目(三)--- u-boot 2017.11 适配开发板修改 1
当前虽然编译成功了,但是对于我们自己的目标板并不太适用.还得做一系列得修改. 一.lds 文件分析 u-boot 中最重要得链接文件即是,u-boot.lds.我们可以查看我们编译出来得 u-boot ...
- npm 版本问题
STF之问题篇 https://yq.aliyun.com/articles/221602 装完成后输入stf doctor查看工具依赖是否正确,安装教程可以参考我之前写的,这里不再多说,直接说问题. ...
- 给广大码农分享福利:一个业界良心的github仓库,中文计算机资料
我今天查资料时无意发现的,https://github.com/CyC2018/CS-Notes 这个仓库包含了下列几个维度的计算机学习资料: 深受国内程序员喜爱,已经有超过3万多star了. 1. ...
- Yum三方仓库——RPMForge
参考:How to Enable RPMForge Repository in RHEL/CentOS 7.x/6.x/5.x RPMForge / RepoForge这两个项目已经死亡,不应该使用 ...
随机推荐
- JDBC fetch size
make your java run faster A blog on java performance and optimization. On JDBC, Hibernate, caching, ...
- UltraEdit 不生成.bak文件
UE不自动生成.bak文件每次保存之后都能看到后面加个.bak后缀的文件出现有时真的很烦,而且还容易搞混,下面的方法可以解除这种烦恼.版本不同可以会有些差别. 中文版按照如下顺序设置:高级--> ...
- 洛谷P2982 [USACO10FEB]慢下来Slowing down(线段树 DFS序 区间增减 单点查询)
To 洛谷.2982 慢下来Slowing down 题目描述 Every day each of Farmer John's N (1 <= N <= 100,000) cows con ...
- Python3面向对象基础
面向对象概述 面向对象 面向对象的世界,引入了对象的概念,对象具有属性:数据,对象具有过程或者方法:成员函数.成员函数的作用就是处理属性. 例子 对象:Car 属性:fuel_level, isSed ...
- 2017-2018-20172309 『Java程序设计』课程 结对编程练习_四则运算_第三周
2017-2018-20172309 『Java程序设计』课程 结对编程练习_四则运算 组队成员: 仇夏 学号: 20172310 博客地址: @王志伟 四则运算第一周博客 @仇夏四则运算第一周博客 ...
- USBWriter之后恢复磁盘大小
USBWriter之后恢复磁盘大小的方法: 1,cmd 2,diskpart 3,list disk 4,select disk *(*你的U盘代号) (e.g:U盘为磁盘 2 ,则代号为2 ,使用命 ...
- Android笔记(五):广播接收者(Broadcast Receiver)
Android有四大组件,分别为:Activity(活动).Service(服务).Content Provider(内容提供器).Broadcast Receiver(广播接收者). 引入广播的目的 ...
- 各种组件的js 获取值 / js动态赋值
jQuery获取Select选择的Text和Value:语法解释:1. $("#select_id").change(function(){//code...}); //为Se ...
- PID控制器(比例-积分-微分控制器)- III
PID Controller Algorithms Controller manufacturers arrange the Proportional, Integral and Derivative ...
- api日常总结
异步加载JS和CSS <script type="text/javascript"> (function () { var s = document.createEle ...