提前道歉,我确定这是一个非常简单的问题,但我一直无法为此找到解决方案。我将一个非常简单的C++
项目放在一起,但无法正确使用头文件。
目录结构如下:
.
├── mainGraph
│ └── hnsw.cpp
└── utils
├── distances.cpp
└── distances.h
距离头文件(distances.h
):
#ifndef DISTANCES
#define DISTANCES
#include <vector>
enum class Metric { Cosine, Euclidean};
double distance(const std::vector<double>& A, const std::vector<double>& B, Metric metric);
double similarity(const std::vector<double>& A, const std::vector<double>& B, Metric metric);
#endif
最后hnsw.cpp
:
#include "../utils/distances.h"
#include <vector>
#include <iostream>
int main(){
std::vector<double> A = {0.1, 0.5, 0.7, 1.1};
std::vector<double> B = {0.5, 0.3, 0.8, 0.9};
std::cout << distance(A, B, Metric::Cosine) << '\n';
}
现在,当我尝试使用以下命令编译hnsw.cpp
时:g++ hnsw.cpp --std=c++11
我收到以下错误:
Undefined symbols for architecture x86_64:
"distance(std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, Metric)", referenced from:
_main in hnsw-ad0e05.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
如果我将主要文件移到distances.cpp
文件中,那么一切都会顺利进行。出于简洁的目的,我不会发布整个文件,因为它很大,我相当肯定它不相关。如果有任何关于理解这里的一般过程的资源也会非常有帮助。
答案 0 :(得分:4)
如果您不想构建单个目标文件以供以后链接,而是一次性构建整个可执行文件,则需要在命令行上指定 all 参与的翻译单元:
g++ -std=c++11 hnsw.cpp ../utils/distances.cpp
输出文件将被称为a.out
,除非您还使用-o
标记覆盖该名称。
通常您会单独编译翻译单元并在单独的步骤中链接它们:
g++ -std=c++11 mainGraph/hnsw.cpp -c -o mainGraph/hnsw.o
g++ -std=c++11 utils/distances.cpp -c -o utils/distances.o
g++ -std=c++11 mainGraph.hnsw.o utils/distances.o -o myprog
您也不会手动维护这些命令,而是将它们粘贴到Makefile或某个等效的构建系统中。关键点在于,您不需要仅仅因为更改了源代码的部分部分而重新编译未更改的翻译单元。
答案 1 :(得分:2)
运行g++ hnsw.cpp --std=c++11
时,您告诉编译器编译hnsw.cpp并将输出与c ++标准库链接以创建可执行文件。链接器无法找到distances
的实现,因为它位于distance.cpp中。
您需要编译这两个文件并将它们链接在一起。有很多方法可以实现这一点,但最简单的方法是在调用gcc时指定两个源文件,如下所示:
g++ -std=c++11 hnsw.cpp ../utils/distances.cpp