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 小结
至此,最初的问题基本解决了。本文主要参考如下资料:
----------------------------------------------------------------------------------------------------------------------------
本文作者:Tocy e-mail: zyvj@qq.com
版权所有@2015-2020,请勿用于商业用途,转载请注明原文地址。本人保留所有权利。