C++ 中的头文件出现问题:链接器命令失败

Sla*_*off 4 c++ header-files c++11

提前道歉,我确信这是一个非常简单的问题,但我一直无法找到解决方案。我正在将一个非常简单的C++项目放在一起,但在正确使用头文件时遇到问题。

\n\n

目录结构如下:

\n\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 mainGraph\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 hnsw.cpp\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 utils\n    \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 distances.cpp\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 distances.h\n
Run Code Online (Sandbox Code Playgroud)\n\n

距离头文件 ( distances.h):

\n\n
#ifndef DISTANCES\n#define DISTANCES\n\n#include <vector>\n\nenum class Metric { Cosine, Euclidean};\n\ndouble distance(const std::vector<double>& A, const std::vector<double>& B, Metric metric);\ndouble similarity(const std::vector<double>& A, const std::vector<double>& B, Metric metric);\n\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n\n

最后hnsw.cpp:

\n\n
#include "../utils/distances.h"\n#include <vector>\n#include <iostream>\n\nint main(){\n    std::vector<double> A = {0.1, 0.5, 0.7, 1.1};\n    std::vector<double> B = {0.5, 0.3, 0.8, 0.9};\n\n    std::cout << distance(A, B, Metric::Cosine) << \'\\n\';\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,当我实际尝试hnsw.cpp使用以下命令进行编译时:g++ hnsw.cpp --std=c++11我收到以下错误:

\n\n
Undefined symbols for architecture x86_64:\n  "distance(std::__1::vector<double, std::__1::allocator<double> > const&, std::__1::vector<double, std::__1::allocator<double> > const&, Metric)", referenced from:\n      _main in hnsw-ad0e05.o\nld: symbol(s) not found for architecture x86_64\nclang: error: linker command failed with exit code 1 (use -v to see invocation)\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我将 main 移动到distances.cpp文件中,那么一切都会顺利进行。为了简洁起见,我不会发布整个文件,因为它很大,而且我相当确定它不相关。如果这里有任何关于了解一般流程的资源,那也会非常有帮助。

\n

Ker*_* SB 5

如果您不想构建单独的目标文件以供以后链接,而是一次性构建整个可执行文件,则需要在命令行上指定所有参与的翻译单元:

g++ -std=c++11 hnsw.cpp ../utils/distances.cpp
Run Code Online (Sandbox Code Playgroud)

输出文件将被称为a.out,除非您还使用标志覆盖该名称-o。

通常您会单独编译翻译单元并在单独的步骤中链接它们:

g++ -std=c++11 hnsw.cpp ../utils/distances.cpp
Run Code Online (Sandbox Code Playgroud)

您也不会手动维护这些命令,而是将它们粘贴到 Makefile 或某些等效的构建系统中。关键点是,您不需要仅仅因为更改了源代码的某些部分而重新编译未更改的翻译单元。