C++ 奇怪的链接器错误,多重定义
C++ weird linker errors, multiple definition of
我正在尝试使用 makefile 在 C++ 中编译项目,当我只有 main.cpp 时它工作正常,但是一旦我添加了一些东西,它就崩溃了,我不知道为什么。请注意,它甚至无法识别 main.
错误图片(可能更适合阅读):
错误文本(以防万一):
make --jobs=9 build
mkdir -p "./dist" "./dist/obj"
g++ -std=c++17 -o dist/a.out dist/obj/hh.o dist/obj/main.o
dist/obj/main.o: In function `hh::hh()':
hh.cpp:(.text+0x0): multiple definition of `hh::hh()'
dist/obj/hh.o:hh.cpp:(.text+0x0): first defined here
dist/obj/main.o: In function `hh::hh()':
hh.cpp:(.text+0x0): multiple definition of `hh::hh()'
dist/obj/hh.o:hh.cpp:(.text+0x0): first defined here
dist/obj/main.o: In function `hh::b()':
hh.cpp:(.text+0xc): multiple definition of `hh::b()'
dist/obj/hh.o:hh.cpp:(.text+0xc): first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [dist/a.out] Error 1
Makefile:12: recipe for target 'dist/a.out' failed
项目结构
root
├───.idea
├───assets
├───dist
│ └───obj
├───doc
├───examples
└───src
我的 Makefile 看起来像这样
COMPILER :=g++
CPPFLAGS :=-std=c++17
DIRS :=./dist
BUILD_DIR :=./dist
OBJS_DIR :=$(BUILD_DIR)/obj
SRC_DIR :=./src
EXEC_FILE :=a.out
# names of obj files (.o gets added later)
OBJS :=hh main
# uses linker to link everythink together
# using functions addsuffix and addprefix adding path and .o to the name of object
# files specified in variable OBJS
$(BUILD_DIR)/$(EXEC_FILE): $(addsuffix .o, $(addprefix $(OBJS_DIR)/, $(OBJS)))
$(COMPILER) $(CPPFLAGS) -o $@ $^
# recipe for any file in source files
$(OBJS_DIR)/%.o: $(SRC_DIR)/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
# recipe for any nested file in source files
$(OBJS_DIR)/%.o: $(SRC_DIR)/*/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
# generates dependecies into Makefile.d
deps:
$(COMPILER) -MM $(SRC_DIR)/*.cpp > Makefile.d
-include Makefile.d
# Callable "scripts" for my IDE
.PHONY: dir_struct, clean, all, rebuild, build
all: dir_struct $(BUILD_DIR)/$(EXEC_FILE)
build: all
rebuild: clean dir_struct all
clean:
rm -r dist
dir_struct:
mkdir -p "$(BUILD_DIR)" "$(OBJS_DIR)"
只是一些仅用于测试的虚拟代码
// main.cpp
#include "hh.h"
int main() {
hh g;
g.b();
return 0;
}
.
// hh.cpp
#include "hh.h"
hh::hh() = default;
void hh::b() {}
.
#ifndef HH_H
#define HH_H
class hh {
public:
hh();
void b();
};
#endif //HH_H
$(OBJS_DIR)/%.o: $(SRC_DIR)/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
这里使用通配符编译所有目标文件,使用所有cpp文件作为依赖。这导致每个 .o 文件仅包含 $(SRC_DIR)/*.cpp
列出的第一个 cpp 文件的定义,导致名称冲突。
您应该创建仅包含相应 cpp 文件中的符号的 .o 文件,而不是这样做:
$(OBJS_DIR)/%.o: $(SRC_DIR)/%.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
我正在尝试使用 makefile 在 C++ 中编译项目,当我只有 main.cpp 时它工作正常,但是一旦我添加了一些东西,它就崩溃了,我不知道为什么。请注意,它甚至无法识别 main.
错误图片(可能更适合阅读):
错误文本(以防万一):
make --jobs=9 build
mkdir -p "./dist" "./dist/obj"
g++ -std=c++17 -o dist/a.out dist/obj/hh.o dist/obj/main.o
dist/obj/main.o: In function `hh::hh()':
hh.cpp:(.text+0x0): multiple definition of `hh::hh()'
dist/obj/hh.o:hh.cpp:(.text+0x0): first defined here
dist/obj/main.o: In function `hh::hh()':
hh.cpp:(.text+0x0): multiple definition of `hh::hh()'
dist/obj/hh.o:hh.cpp:(.text+0x0): first defined here
dist/obj/main.o: In function `hh::b()':
hh.cpp:(.text+0xc): multiple definition of `hh::b()'
dist/obj/hh.o:hh.cpp:(.text+0xc): first defined here
/usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [dist/a.out] Error 1
Makefile:12: recipe for target 'dist/a.out' failed
项目结构
root
├───.idea
├───assets
├───dist
│ └───obj
├───doc
├───examples
└───src
我的 Makefile 看起来像这样
COMPILER :=g++
CPPFLAGS :=-std=c++17
DIRS :=./dist
BUILD_DIR :=./dist
OBJS_DIR :=$(BUILD_DIR)/obj
SRC_DIR :=./src
EXEC_FILE :=a.out
# names of obj files (.o gets added later)
OBJS :=hh main
# uses linker to link everythink together
# using functions addsuffix and addprefix adding path and .o to the name of object
# files specified in variable OBJS
$(BUILD_DIR)/$(EXEC_FILE): $(addsuffix .o, $(addprefix $(OBJS_DIR)/, $(OBJS)))
$(COMPILER) $(CPPFLAGS) -o $@ $^
# recipe for any file in source files
$(OBJS_DIR)/%.o: $(SRC_DIR)/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
# recipe for any nested file in source files
$(OBJS_DIR)/%.o: $(SRC_DIR)/*/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
# generates dependecies into Makefile.d
deps:
$(COMPILER) -MM $(SRC_DIR)/*.cpp > Makefile.d
-include Makefile.d
# Callable "scripts" for my IDE
.PHONY: dir_struct, clean, all, rebuild, build
all: dir_struct $(BUILD_DIR)/$(EXEC_FILE)
build: all
rebuild: clean dir_struct all
clean:
rm -r dist
dir_struct:
mkdir -p "$(BUILD_DIR)" "$(OBJS_DIR)"
只是一些仅用于测试的虚拟代码
// main.cpp
#include "hh.h"
int main() {
hh g;
g.b();
return 0;
}
.
// hh.cpp
#include "hh.h"
hh::hh() = default;
void hh::b() {}
.
#ifndef HH_H
#define HH_H
class hh {
public:
hh();
void b();
};
#endif //HH_H
$(OBJS_DIR)/%.o: $(SRC_DIR)/*.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
这里使用通配符编译所有目标文件,使用所有cpp文件作为依赖。这导致每个 .o 文件仅包含 $(SRC_DIR)/*.cpp
列出的第一个 cpp 文件的定义,导致名称冲突。
您应该创建仅包含相应 cpp 文件中的符号的 .o 文件,而不是这样做:
$(OBJS_DIR)/%.o: $(SRC_DIR)/%.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@