c++ - C ++奇怪的链接器错误,多重定义
问题描述
我正在尝试使用 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 文件仅包含列出的第一个 cpp 文件的定义,$(SRC_DIR)/*.cpp
从而导致名称冲突。
您应该创建仅包含来自相应 cpp 文件的符号的 .o 文件,而不是这样做:
$(OBJS_DIR)/%.o: $(SRC_DIR)/%.cpp
$(COMPILER) $(CPPFLAGS) -c $< -o $@
推荐阅读
- java - 在Android中如何更改列表项颜色并即使在关闭后也将其存储
- javascript - Firebase 网络应用:firebase.database 不是函数
- html - 我正在尝试删除空间,并且在侧面滑动和缓出的图像不会在纯 CSS 中缩放
- c++ - 从 codeforces 解决 dp 问题 - Cut Ribbon
- reactjs - 如何将文本(查询)附加到反应路由器 URL?
- ios - 音频完成后更改按钮 Xcode
- javascript - TypeError:无法调用 null 的方法“createEvent”。(第 38 行,文件“代码”)
- django - 在 Django 中使用模型创建有序列表
- node.js - Firebase Cloud Functions:来自referer 的请求
被阻止。- 没有权限 - node.js - 安装后无法连接到 Express 欢迎页面