【问题标题】:Trying to compile each .cpp file to a corresponding .o file尝试将每个 .cpp 文件编译为相应的 .o 文件
【发布时间】:2021-12-05 02:40:00
【问题描述】:

我来到 stackoverflow 专家那里是为了更好地理解并可能更好地解决正在发生的事情。所以我通常很擅长使用 Makefile,但我的 Makefile 缺少一个关键部分。所以我通常有一个适合我的项目的 Makefile,它工作得很好。或者直到我发现我没有正确链接库。由于我发现我的 Makefile 不正确,并且我一直无法找到解决此问题的方法/有更好的解决方案。

我想做的事

假设我有一些 .cpp 文件(忽略糟糕的命名)

src
  core
    rector
      Reactor.cpp
      Reactor.h
  reactorprj
    TestReactor.cpp 

我想将这些 .cpp 中的每一个编译成对应的 .o 文件,这样我的构建目录就会像这样

build_dir
  src
    core
      rector
        Reactor.o
    reactorprj
      TestReactor.o 

在将每个 .cpp 文件编译为 .o 文件后,我想将所有 .o 文件一起链接到可执行文件中,同时将库链接到这一点。所以我可以这样做,但不是。

这就是我所拥有的

生成文件

include make_rules/config.mk

# Output of the program
OUTPUT      := App.exe

# All CPP files to compile
CPP_SRC += $(SRC)/core/reactor/Reactor.cpp
CPP_SRC += $(SRC)/reactorprj/TestReactor.cpp

# Compile OBJ files (.o) to a build directory
CPP_OBJ     := $(addprefix $(BLD_DIR), $(subst $(PRJ_DIR), ,$(CPP_SRC:.cpp=.o)))

# Directories on where to include header files
INC_DIR     += $(SRC)
INC_DIR     += /usr/local/lib/cppzmq
INC_DIR     += /usr/local/lib/spdlog/include

# Dependency files
DEP         := $(CPP_OBJ:.o=.d)

# The directory to look for the libraries
LIBS_DIR    += /usr/lib
LIBS_DIR    += /usr/local/lib/spdlog/build

# The library to link
LIBS        += zmq
LIBS        += pthread
LIBS        += spdlog

.PHONY: all
all: $(OUTPUT)

$(OUTPUT): $(CPP_OBJ)
    @$(ECHO)
    @$(ECHO) Compiling all object files...
    @$(ECHO) Linking....
    $(VERBOSE)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INC) -o $@ $(CPP_OBJ) $(LIBSPATHS) $(LDLIBS)

$(CPP_OBJ): $(CPP_SRC)
    $(VERBOSE)$(MKDIR) -p '$(@D)'
    @$(ECHO) 'Compiling $<'
    $(VERBOSE)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INC) -c $< -o $@
    
.PHONY: clean
clean:
    $(RM) -rf $(BLD_DIR)
    $(RM) -rf $(OUTPUT)
    

# Include the dependencies. Since the dependency files won't exist at first the -include supresses the warnings
-include $(DEP)

ma​​ke_rules/config.mk

#############################
### General Config Rules
#############################

# Commands
ECHO    := echo
MAKE    := make
CAT     := cat
RM      := rm
MKDIR   := mkdir
LS      := ls

# Top Level Variables
PRJ_DIR     := /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code
BLD_DIR     := $(PRJ_DIR)/build_dir
SRC         := $(PRJ_DIR)/src

# This is empty because we can add actual defines in the Makefile
DEFINES     +=

# Compiler
CXX         := g++

# Compiler flags
CXXFLAGS    += -Wall -Wextra -Wsign-conversion -g -MMD -MP

# Preprocessor Flags
CPPFLAGS    +=
CPPFLAGS    +=  $(addprefix -D, $(DEFINES))

# Directories on where to include header files
INC_DIR     +=

# Append -I to each directory
INC         += $(INC_DIR:%=-I%)

# LIBS_DIR is used to specify the directories of the libraries
LIBS_DIR    +=

# Take LIBS_DIR and add -L to each
LIBSPATHS   += $(LIBS_DIR:%=-L%)

# The library to link
LIBS        +=

# Add -l to each library
LDLIBS      += $(LIBS:%=-l%)

这是我的结果

这里是make all的结果

20:39:41 **** Build of configuration Default for project ExistingMakefile ****
make VERBOSE= all 
mkdir -p '/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/core/reactor'
Compiling /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp
g++  -Wall -Wextra -Wsign-conversion -g -MMD -MP -I/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src -I/usr/local/lib/cppzmq -I/usr/local/lib/spdlog/include -c /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp -o /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/core/reactor/Reactor.o
mkdir -p '/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/reactorprj'
Compiling /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp
g++  -Wall -Wextra -Wsign-conversion -g -MMD -MP -I/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src -I/usr/local/lib/cppzmq -I/usr/local/lib/spdlog/include -c /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp -o /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/reactorprj/TestReactor.o

Compiling all object files...
Linking....
g++  -Wall -Wextra -Wsign-conversion -g -MMD -MP -I/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src -I/usr/local/lib/cppzmq -I/usr/local/lib/spdlog/include -o App.exe /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/core/reactor/Reactor.o /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/reactorprj/TestReactor.o -L/usr/lib -L/usr/local/lib/spdlog/build -lzmq -lpthread -lspdlog
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/reactorprj/TestReactor.o: in function `Reactor::Reactor(int)':
/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp:12: multiple definition of `Reactor::Reactor(int)'; /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/core/reactor/Reactor.o:/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp:12: first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/reactorprj/TestReactor.o: in function `Reactor::Reactor(int)':
/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp:12: multiple definition of `Reactor::Reactor(int)'; /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/core/reactor/Reactor.o:/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp:12: first defined here
/usr/lib/gcc/x86_64-pc-cygwin/11/../../../../x86_64-pc-cygwin/bin/ld: /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/reactorprj/TestReactor.o:/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp:18: multiple definition of `main'; /cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/build_dir/src/core/reactor/Reactor.o:/cygdrive/c/Users/kmgag/Documents/eclipse-projects/existing-cpp-code/src/core/reactor/Reactor.cpp:18: first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:36: App.exe] Error 1
"make VERBOSE= all" terminated with exit code 2. Build might be incomplete.

所以我可以看出 Reactor.cpp 正在编译为 Reactor.o 和 TestReactor.o,这导致了重新定义的错误。那么为什么会发生这种情况。应该发生的是 Reactor.cpp 编译为 Reactor.o 和 TestReactor.cpp 编译为 TestReactor.o

更新

根据@Sam Varshavchik 的回答,我的新目标现在看起来像这样:

$(CPP_OBJ):
    $(VERBOSE)$(MKDIR) -p '$(@D)'
    $(eval CPP_FILE := $(addprefix $(PRJ_DIR), $(subst $(BLD_DIR), ,$(subst .o,.cpp,$@))))
    @$(ECHO) 'Compiling $(CPP_FILE)'
    $(VERBOSE)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INC) -c $(CPP_FILE) -o $@

由于我构建到与项目文件不同的目录,我最终将目标的前缀从 .o 更改为 .cpp,然后我删除了构建目录的模式 ($(BLD_DIR)),然后添加了前缀我的源代码所在的位置。然后我把它放在 $(CPP_FILE) 中,稍后用于目标。最终工作完美,所以我接受了 Sam 的回答!我确信可能有更好的方法来解决这个问题,但现在我很擅长。

【问题讨论】:

标签: c++ makefile


【解决方案1】:

您的 Makefile 定义:

CPP_SRC += $(SRC)/core/reactor/Reactor.cpp
CPP_SRC += $(SRC)/reactorprj/TestReactor.cpp

为避免混淆,从现在开始,我将去掉所有目录名并仅引用文件名。所以,基本上是这样的:

CPP_SRC = Reactor.cpp TestReactor.cpp

如下定义:

CPP_OBJ     := $(addprefix $(BLD_DIR), $(subst $(PRJ_DIR), ,$(CPP_SRC:.cpp=.o)))

具有定义的效果:

CPP_OBJ = Reactor.o TestReactor.o

再次,忽略路径。所以现在,我们到了这里:

$(CPP_OBJ): $(CPP_SRC)

如果你拿出一张纸,写下所有这些宏扩展成什么,这定义了以下依赖关系:

Reactor.o TestReactor.o: Reactor.cpp TestReactor.cpp

这意味着Reactor.oTestReactor.o 都依赖于Reactor.cppTestReactor.cpp。这就是Makefile 语法的含义。这并不意味着第一个依赖文件依赖于第一个依赖项,而第二个依赖文件依赖于第二个依赖项。这意味着两个依赖文件都依赖于两个依赖项。这实际上与以下内容相同:

Reactor.o: Reactor.cpp TestReactor.cpp
TestReactor.o: Reactor.cpp TestReactor.cpp

最后,我们到了这里:

    $(VERBOSE)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(INC) -c $< -o $@

如果您查看 GNU make 的文档,您会看到 $&lt; 扩展为 first 依赖项。

这就是Reactor.oTestReactor.oReactor.cpp 编译的方式,并解释了您的Makefile 的错误行为。

你需要替换这个不正确的依赖声明:

$(CPP_OBJ): $(CPP_SRC)

您需要将$(CPP_SRC) 替换为一个宏,该宏将单个依赖目标替换为相应的.cpp 文件。将$(CPP_SRC) 替换为$(patsubst)$@,替换扩展名,应该可以解决问题。

【讨论】:

    猜你喜欢
    • 2016-05-28
    • 1970-01-01
    • 1970-01-01
    • 2012-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-25
    相关资源
    最近更新 更多