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这两个项目已经死亡,不应该使用 ...
随机推荐
- Xamarin.Android部署失败
Xamarin.Android部署失败 项目编译.生成没有错误信息,并且可以找到生成的APK包,但部署失败.提示信息如下: "apksigner.BAT"已退出,代码为1. ...
- Node+Express+MongoDB + Socket.io搭建实时聊天应用实战教程(二)--node解析与环境搭建
前言 本来开始写博客的时候只是想写一下关于MongoDB的使用总结的,后来觉得还不如干脆写一个node项目实战教程实战.写教程一方面在自己写的过程中需要考虑更多的东西,另一方面希望能对node入门者有 ...
- L1 与 L2 正则化
参考这篇文章: https://baijiahao.baidu.com/s?id=1621054167310242353&wfr=spider&for=pc https://blog. ...
- 50 tips of JavaScript,这些坑你都知道吗?
1.在局部作用域中,使用var操作符定义的变量将成为定义该变量的作用域中的局部变量,省略var的会创建全局变量:在全局作用域中,不管是否使用var操作符定义的变量都会创建一个全局变量.但是,在全局作用 ...
- win10 图标异常 ,重命名后,图标不显示,名字错乱。
win10 图标异常 ,重命名后,图标不显示,名字错乱. 按下快捷键 Win+R,在打开的运行窗口中输入 %localappdata%,回车. 在打开的文件夹中,找到 IconCache.db,将其删 ...
- AGC027 B - Garbage Collector 枚举/贪心
目录 题目链接 题解 代码 题目链接 AGC027 B - Garbage Collector 题解 对于一组选取组的最优方案为,走到一点,然后顺着路径往回取点 设选取点坐标升序为{a,b,c,d} ...
- 洛谷.4114.Qtree1(树链剖分)
题目链接 模板题都错了这么多次.. //边权赋到点上 树剖模板 //注意LCA.链的顶端不能统计到答案! #include <cstdio> #include <cctype> ...
- Linux运维笔记(一)网络基础知识
网络基础知识 一.基本概念 1.ARPANET & TCP/IP:以“软件”技术将网络硬件整合,使得不同的计算机或者数据可以通过这个软件达成数据沟通(TCP/IP技术也被称为Internet) ...
- .net core 3.0中可以使用gRPC了
今天发现.net core下有gRPC模板了,这个可是补全了.net core下高性能RPC框架缺失这一大短板了. 使用模板创建了工程后,发现连客户端的示例也创建了. 更加给力的是,IDE是能直接识别 ...
- 实现Qemu aarch32虚拟开发板ping www.baidu.com
环境 Qemu: 2.8.0 开发板: vexpress-ca9 概述 如果要玩物联网,至少应该让开发板实现联网,让qemu支持联网在之前的博文中已经有介绍了,但是如果只能在自己的局域网内玩耍就太没意 ...