Home > Software engineering >  CMake & C : linker error : undefined reference to function
CMake & C : linker error : undefined reference to function

Time:05-31

I am trying to compile a simple C program with CMake, but I am getting a linker error :

[2/2] Linking CXX executable bin/MY_PROGRAM
FAILED: bin/MY_PROGRAM
: && g   -g  CMakeFiles/MY_PROGRAM.dir/src/main.cpp.o -o bin/MY_PROGRAM  && :
/usr/bin/ld: CMakeFiles/MY_PROGRAM.dir/src/main.cpp.o: in function `main':
/home/user/Code/root/src/main.cpp:27: undefined reference to `str_toupper(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&)'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

I have tried looking at some questions with similar issues but couldn't find what I did wrong. There must be a problem with my directory structure and CMake files. I could change the directory structure to make things easier, but I may be missing something important and I'd like to figure out why. Also, I am new to C so I might be doing something wrong in the code itself, but my IDE doesn't find any issue.

My directory structure is :

root
    |-- CMakeLists.txt
    |-- src
        |-- main.cpp
    |-- utils
        |-- CMakeLists.txt
        |-- src
            |-- strutils.cpp
        |-- include
            |-- strutils.h

The top-level CMakeLists.txt is :

// general stuff (standard, etc...)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
set(MY_PROGRAM_SRC src/main.cpp)
add_executable(MY_PROGRAM ${MY_PROGRAM_SRC})

include_directories(utils/include)
link_libraries(MY_LIBRARY)

and utils/CMakeLists.txt :

set(MY_LIBRARY_SRC include/strutils.h src/strutils.cpp)
add_library(MY_LIBRARY STATIC ${MY_LIBRARY_SRC})

// This is to include strutils.h in strutils.cpp 
// (but is it needed ? I could just #include <string> in strutils.cpp, I guess)
target_include_directories(MY_LIBRARY PUBLIC include)

Finally, the source files :

// strutils.h
#include <string>

void str_toupper(const std::string &in, std::string &out);
// strutils.cpp
#include <algorithm>
#include <strutils.h>

void str_toupper(const std::string &in, std::string &out) {
  std::transform(in.begin(), in.end(), out.begin(), [](char c){return std::toupper(c);});
}
// main.cpp
#include <strutils.h>

#include <cstdlib>
#include <cstdio>
#include <string>

int main(int argc, char *argv[]) {
  // ...
  std::string arg_in;
  for (int i = 0; i < argc; i  ) {
    str_toupper(std::string(argv[i]), arg_in);
  }
}

Does anyone have an idea of what's going on ? Thanks !

CodePudding user response:

The first sentence in the manual link_libraries

Link libraries to all targets added later.

You use this directive after the target MY_PROGRAM is added - the target MY_PROGRAM is added prior link_libraries.

Prefer use target_link_libraries(MY_PROGRAM MY_LIBRARY) - other targets can require different dependencies and it's better not use a global set of dependencies for all targets.

  • Related