【问题标题】:Makefile with Objects in Separate Directory Tree带有单独目录树中的对象的 Makefile
【发布时间】:2019-07-14 18:42:20
【问题描述】:

我一直在尝试设计一个 makefile 示例,它可以将目标文件构建到与关联源不同的目录结构中。包含源和目标的目录树如下:

/repo-root
|-- /build
    |-- /example_lib
        |-- makefile
        |-- /Release*
            |-- libexample_lib.a*
            |-- /obj*
                |-- example_lib.o*
                |-- example_lib.d*
|-- /source
    |-- /example_lib
        |-- /inc
            |-- example_lib.h
        |-- /src
            |-- example_lib.cpp

星号文件夹/文件是 makefile 应该生成的那些。

我已经看到其他问题和答案 (Makefile : Build in a separate directory tree)、(Makefile with directory for object files) 等,但如果我正确理解它们的源到对象规则,这些似乎会在输出目录中创建一个子目录树匹配来源。

我当前使用的makefile如下,使用GNU Make 3.82运行:

SHELL = /bin/sh

.SUFFIXES:
.SUFFIXES: .cpp .o

# @todo Variables passed to make.
BUILD_CONFIG=Release

# Makefile specific variables
REPO_ROOT=../..
LIBRARY_NAME=example_lib

#-------------------------------------------------------------------
# Derived variables
#-------------------------------------------------------------------

LIBRARY_FILENAME=lib$(LIBRARY_NAME).a
LIBRARY_FILEPATH=$(BUILD_CONFIG)/$(LIBRARY_FILENAME)

# Source directories
CPP_SRC_DIRS=$(REPO_ROOT)/source/example_lib/src

# Source files
vpath %.cpp $(CPP_SRC_DIRS)
CPP_SRCS=$(foreach cpp_src_dir, $(CPP_SRC_DIRS), $(wildcard $(cpp_src_dir)/*.cpp))

# Object/dependencies directory
OBJ_DEPS_DIR=./$(BUILD_CONFIG)/obj

# Object files
OBJS=$(CPP_SRCS:%.cpp=$(OBJ_DEPS_DIR)/%.o)

# Dependency files (built with objects)
DEPS=$(CPP_SRCS:%.cpp=$(OBJ_DEPS_DIR)/%.d)

#-------------------------------------------------------------------
# C++ compiler settings
#-------------------------------------------------------------------

CPP_COMMAND=g++
CPP_OPTIONS_INC_PATHS=-I"$(REPO_ROOT)/source/example_lib/inc"
CPP_OPTIONS_OPTIM=-O3
CPP_OPTIONS_WARN=-Wall
CPP_OPTIONS_MISC=-c -fmessage-length=0
CPP_OPTIONS=$(CPP_OPTIONS_INC_PATHS) $(CPP_OPTIONS_OPTIM) $(CPP_OPTIONS_WARN) $(CPP_OPTIONS_MISC)

#-------------------------------------------------------------------
# Archiver settings
#-------------------------------------------------------------------

AR_COMMAND=ar
AR_OPTIONS=-r

#-------------------------------------------------------------------
# Targets
#-------------------------------------------------------------------

# Object/dependency directory target
$(OBJS): | $(OBJ_DEPS_DIR)
$(OBJ_DEPS_DIR):
    mkdir -p $(OBJ_DEPS_DIR)

# Object targets
$(OBJ_DEPS_DIR)/%.o: %.cpp
    @echo 'Building file: $<'
    @echo 'Invoking: GCC C++ Compiler'
    $(CPP_COMMAND) $(CPP_OPTIONS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<"
    @echo 'Finished building: $<'
    @echo ' '

# 'all' target
all: $(LIBRARY_FILEPATH)

# Output library target
$(LIBRARY_FILEPATH): $(OBJS)
    @echo 'Building target: $@'
    @echo 'Invoking: GCC Archiver'
    $(AR_COMMAND) $(AR_OPTIONS)  "$@" $(OBJS)
    @echo 'Finished building target: $@'
    @echo ' '

# 'clean' target
clean:
    @echo 'Cleaning targets'
    rm -rf $(OBJS) $(DEPS) $(LIBRARY_FILENAME)
    @echo ' '

# 'PHONY' target
.PHONY: all clean

有意义的“make”输出是:

make all 
Building file: ../../source/example_lib/src/example_lib.cpp
Invoking: GCC C++ Compiler
g++ -I"../../source/example_lib/inc" -O3 -Wall -c -fmessage-length=0 -MMD -MP -MF"Release/obj/../../source/example_lib/src/example_lib.d" -MT"Release/obj/../../source/example_lib/src/example_lib.o" -o "Release/obj/../../source/example_lib/src/example_lib.o" "../../source/example_lib/src/example_lib.cpp"
../../source/example_lib/src/example_lib.cpp:6:1: fatal error: opening dependency file Release/obj/../../source/example_lib/src/example_lib.d: No such file or directory
 }
 ^
compilation terminated.
make: *** [Release/obj/../../source/example_lib/src/example_lib.o] Error 1

source-to-object 规则是将 %.cpp 文件的完整路径替换为 %.o 目标,这导致对象路径为:

Release/obj/../../source/example_lib/src/example_lib.o

我不明白的是,当源文件和目标文件位于不同的树中时,如何让它们的隐式规则匹配。我为此使用 vpath 来帮助解析源,但对象(目标)部分不匹配。我还尝试将源到对象规则更改为:

$(OBJ_DEPS_DIR)/$(notdir %.o): %.cpp

但这导致了相同的路径(似乎 $(notdir ...) 之类的命令不支持通配符匹配?)。我还意识到,如果两个源目录碰巧有一个同名的文件,那么从可能不同的源目录中删除所有对象文件可能会导致名称冲突——这对于我正在使用的代码来说不是问题。

任何帮助表示赞赏,并提前感谢!

【问题讨论】:

  • how to get the implicit rules for a source and object file to match when they are in different trees 然后您必须为每对匹配的“构建源”(子)目录编写(模式)规则。该过程可以使用 make 宏工具自动化。

标签: makefile gnu-make


【解决方案1】:

诀窍是在构造目标文件的名称之前删除不需要的源文件路径:

CPP_SRCS=$(foreach cpp_src_dir, $(CPP_SRC_DIRS), $(wildcard $(cpp_src_dir)/*.cpp))
# CPP_SRCS now contains "../../source/example_lib/src/example_lib.cpp"
SRCS := $(notdir $(CPP_SRCS))
# SRCS now contains "example_lib.cpp"
BAD_OBJS := $(CPP_SRCS:%.cpp=$(OBJ_DEPS_DIR)/%.o)
# BAD_OBJS now contains "./Release/obj/../../source/example_lib/src/example_lib.o"
OBJS := $(patsubst %.cpp,$(OBJ_DEPS_DIR)/%.o,$(SRCS))
# OBJS now contains "./Release/obj/example_lib.o"

一旦你做了这么多工作,就可以对你的规则进行一些小的调整。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 2015-08-14
    • 2020-08-16
    • 2023-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多