【发布时间】: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)
make_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 的回答!我确信可能有更好的方法来解决这个问题,但现在我很擅长。
【问题讨论】:
-
看来您只需要申请stackoverflow.com/a/43359468/5267751 即可正确编写makefile。在当前状态下,它只适用于一个 cpp 项目