Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble with header files in c++: linker command failed

Apologizing ahead of time for what I'm certain is a very simple problem, but I've been unable to find a solution for this. I'm putting a very simple C++ project together, but having trouble using a header file appropriately.

The directory structure is below:

.
├── mainGraph
│   └── hnsw.cpp
└── utils
    ├── distances.cpp
    └── distances.h

The distances header file (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

And finally 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';
}

Now, when I actually try to compile hnsw.cpp with the following command: g++ hnsw.cpp --std=c++11 I get the following error:

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)

If I move the main into the distances.cpp file then everything works smoothly. For the purposes of brevity I'm not posting that whole file as it's sizable and I'm fairly certain it's not relevant. If there are any resources about understanding the general process here that would also be very helpful.

like image 507
Slater Victoroff Avatar asked Sep 05 '25 03:09

Slater Victoroff


2 Answers

If you don't want to build individual object files for later linking, but instead build the whole executable file in one go, you need to specify all the participating translation units on the command line:

g++ -std=c++11 hnsw.cpp ../utils/distances.cpp

The output file will be called a.out, unless you also override that name with the -o flag.

Usually you would compile translation units separately and link them in a separate step:

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

You also wouldn't maintain these commands by hand, but stick them into a Makefile, or some equivalent build system. The key point is that you don't need to recompile translation units that haven't changed just because you changed some part of your source code.

like image 129
Kerrek SB Avatar answered Sep 07 '25 21:09

Kerrek SB


When you run g++ hnsw.cpp --std=c++11, you're telling the compiler to compile hnsw.cpp and link the output with the c++ standard library to create an executable. The linker fails to find the implementation of distances because it lives in distances.cpp.

You need to compile both files and link them together. There are many ways to achieve this, but the simplest is to specify both source files when invoking gcc, like this:

g++ -std=c++11 hnsw.cpp ../utils/distances.cpp
like image 43
Dominic Dos Santos Avatar answered Sep 07 '25 19:09

Dominic Dos Santos