0

This is my error when trying to compile:

Undefined symbols for architecture x86_64:
    "Model::Model(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::vector<int, std::__1::allocator<int> >)", referenced from: ____C_A_T_C_H____T_E_S_T____4() in tests.cpp.o

I have read that std::string is a typedef of std::basic_string and I'm guess that std::vector is a typedef of... std::vector and std::allocator? or something...

Anyway. I have a Settings class that holds my settings and a Model class that contains my model. The code I am attempting to run is as below, and I am unable to compile it. the issue is with it not recognising my model constructor.

Settings s = Settings("../config/settings.json");
std::string mf = s.get_model_file();
std::vector<int> vec = s.get_input_shape();
Model m = Model(mf, vec);

For reference here is my Model class header:

class Model {
public:
  Model(std::string model_file, std::vector<int> input_shape);
  ~Model();
  double* get_ref_to_input_buffer();
  std::string predict();

private:
  std::string _model_file;
  fdeep::model _model;

  fdeep::shape3 _input_shape;
  int _input_size;
  double* _input_buffer;
  fdeep::tensor3s _result;

  void _load_model();
  void _set_input_size(std::vector<int> input_shape);
  void _set_input_shape(std::vector<int> input_shape);
  void _create_input_buffer();
  std::string _result_to_string();
};

and my Model class constructor:

Model::Model(std::string model_file, std::vector<int> input_shape) {
      _model_file = model_file;
      _load_model();
      _set_input_size(input_shape);
      _set_input_shape(input_shape);
}

These are the function being called in the constructor:

void Model::_load_model() { _model = fdeep::load_model(_model_file); }

void Model::_set_input_size(std::vector<int> input_shape) {
  int total = 1;
  for (std::vector<int>::iterator it = input_shape.begin();
      it != input_shape.end(); ++it) {
    total *= *it;
  }
  _input_size = total;
}

void Model::_set_input_shape(std::vector<int> input_shape) {
  _input_shape = fdeep::shape3(input_shape[0], input_shape[1], input_shape[2]);
}

If anyone could point out where I'm going wrong or send me in the direction of what I need to read / learn that would be great. Thank you!

Kevin Glasson
  • 408
  • 2
  • 13
  • class `Model` doesn't inherit the `_model` class in its declaration and you define the constructor and call the base constructor in it. `: _model(fdeep::load_model(model_file)` – user3366592 Jul 02 '18 at 09:25
  • `Model m = Model(mf, vec);` - pointless copying. Just do `Model m(mf, vec);` – Ivan Rubinson Jul 02 '18 at 09:35
  • 6
    Yours is probably a configuration error. You don't link the object file that implements your constructor. – StoryTeller - Unslander Monica Jul 02 '18 at 09:35
  • 1
    Side note: `std::vector` is just an ordinary template - with default template arguments, though, but there are no `typedef`s involved. – Aconcagua Jul 02 '18 at 09:37
  • @Aconcagua std::string is required to be typedef of std::basic_string by standard. – Öö Tiib Jul 02 '18 at 09:39
  • 1
    @IvanRubinson since C++17 those two codes are the same – M.M Jul 02 '18 at 09:39
  • https://stackoverflow.com/questions/22818925/c-error-undefined-symbols-for-architecture-x86-64 – Ivan Rubinson Jul 02 '18 at 09:39
  • @ÖöTiib Never spoke of `std::string` - just `std::vector`... – Aconcagua Jul 02 '18 at 09:40
  • if I replace my Model object creation `Model m = Model(mf, vec);` with what I'm trying to do inside my class it works fine `fdeep::model model = fdeep::load_model("fdeep_model.json");` – Kevin Glasson Jul 02 '18 at 09:57
  • 1
    @KevinGlasson Just another hint that the linker is not provided the object file the constructor resides in... You should add the complete compiler and linker calls to the question as the error is most likely made there... – Aconcagua Jul 02 '18 at 10:14
  • Yep, you're right! I had .hpp instead of .cpp in my CMakeLists.txt. Far out that has taken me hours. @Aconcagua – Kevin Glasson Jul 02 '18 at 10:40
  • Duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix/), specifically the ["Failure to link against appropriate libraries/object files or compile implementation files"](https://stackoverflow.com/a/12574400/981959) answer. – Jonathan Wakely Jul 02 '18 at 10:56

2 Answers2

2

According to http://www.cplusplus.com/forum/general/55587/

"Undefined Symbols" generally indicates a linking issue. Are you definitely linking correctly to the appropriate library?

Your code compiles fine. The linker then goes looking in the libraries for the right functions, and since you compiled for architecture x86_64, it looks for the right libraries, similarly compiled - and finds none. This suggests (unless you've simply forgotten to link to the 64 bit library) that you've got a 32 bit version of the library. Your choices are:

  1. Build your code for 32 bit, so you can use the libraries you've got.
  2. Get the library source code, and compile it yourself for x86_64
  3. Go looking wherever you found the library, and hope there's an x86_64 version sitting next to the 32 bit version you found last time.
Ivan Rubinson
  • 3,001
  • 4
  • 19
  • 48
  • 1
    cplusplus.com is a poor reference site. It would be better to refer to (in this order): the standard, another question on this site, or cppreference.com – M.M Jul 02 '18 at 09:38
  • I know, but it's the first thing a quick googling showed. – Ivan Rubinson Jul 02 '18 at 09:39
  • 3
    google is even lower on that list :P – M.M Jul 02 '18 at 09:41
  • I dont think this is the correct answer. There seems to be an issue with constructor definition. –  Jul 02 '18 at 09:52
  • 1
    There is no "appropriate library" that needs to be linked to, the undefined reference refers to the `Model::Model(std::string model_file, std::vector input_shape)` constructor. So the problem is not linking to `Model.cpp` (or whatever the file is that defined the constructor), not some library. – Jonathan Wakely Jul 02 '18 at 10:50
  • ^ This is **EXACTLY** what it turned out to be @JonathanWakely – Kevin Glasson Jul 02 '18 at 11:59
1

By taking @Aconcagua 's advice I output the linker command from cmake using:

make tests VERBOSE=1

which gave me:

usr/bin/g++ -Wl,-search_paths_first -Wl,-headerpad_max_install_names CMakeFiles/tests.dir/tests.cpp.o CMakeFiles/tests.dir/__/Settings.cpp.o -o ../../../bin/tests

Noticing that this did not have a Model.cpp.o file I checked CMakeLists.txt and found:

add_executable(tests tests.cpp ../Settings.cpp ../Model.hpp)

Note that for Model I have entered the header file not the source file. Changing it to this:

add_executable(tests tests.cpp ../Settings.cpp ../Model.cpp)

Fixed my problem.

Kevin Glasson
  • 408
  • 2
  • 13
  • Right. The linker error was telling you the constructor was not defined. Since you did write that constructor (it's the `Model::Model(std::string model_file, std::vector input_shape)` one that you showed us) then the problem is that you never told the linker to use the file containing that code. If the linker tells you there's an undefined reference, either you forgot to define it, or you forgot to tell the linker where to find it. – Jonathan Wakely Jul 02 '18 at 10:52
  • Yeah so I was thrown off by my general lack of knowledge! and confusion over the typedef expansion of my parameters – Kevin Glasson Jul 02 '18 at 10:58
  • Yes, interpreting linker errors like that should become second nature when you're more familiar with C++ (and the ways a build can fail). It doesn't help that the "true names" of the types as printed by the linker don't match the names you used for them in the source code, but you did actually interpret that part correctly :-) – Jonathan Wakely Jul 02 '18 at 11:05