CMake: undefined reference to - c++

I use CMake 3.5.2. When trying to build my C++ code I get the following error:
[100%] Linking CXX executable SomeExecutable
CMakeFiles/SomeExecutable.dir/Common/src/FunctionOne.cpp.o: In function `FunctionOne::FunctionOne(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double, double, unsigned int, bool)':
FunctionOne.cpp:(.text+0x490): undefined reference to `Helper::initLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)'
The program doesn't find Helper::initLevel() in myLib.so. How do I fix it?
CMakeLists.txt: (shortened for brevity)
cmake_minimum_required(VERSION 3.0)
project(ProjectName)
add_definitions(-std=c++11)
add_definitions(-Wall)
add_definitions(-O2)
link_directories(/usr/local/lib)
add_executable(SomeExecutable SomeExecutable.cpp ${FunctionOne} ${FunctionTwo})
target_link_libraries(SomeExecutable -pthread -lboost_thread ${Boost_LIBRARIES} myLib armadillo)
File structure (shortened for brevity):
├── bin
├── CMakeCache.txt
├── cmake_install.cmake
├── CMakeLists.txt
├── Common
│   ├── include
│   │   ├── dataContainer.h
│   │   ├── FunctionOne.h
│   │   ├── FunctionTwo.h
│   └── src
│   ├── FunctionOne.cpp
│   └── FunctionTwo.cpp
├── SomeExecutable.cpp
├── myLib
│   ├── example.cpp
│   ├── include
│   │   ├── Config.h
│   │   ├── Helper.h
│   ├── libmyLib.so
UPDATE:
myLib/include/Config.h:
Namespace Helper {
[...]
Level* initLevel(const std::string& jsonLvlPath, bool twiceSpatPts = false);
[..]
}
UPDATE 2:
kepj#laptop:~/ProjectName$ make VERBOSE=1
/usr/bin/cmake -E cmake_link_script CMakeFiles/SomeExecutable.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/SomeExecutable.dir/SomeExecutable.cpp.o CMakeFiles/SomeExecutable.dir/Common/src/FunctionOne.cpp.o CMakeFiles/SomeExecutable.dir/Common/src/FunctionTwo.cpp.o SomeExecutable -L/usr/local/lib -rdynamic -pthread -lboost_thread -lboost_system -lboost_filesystem -lmyLib -lsymbolicc++ -lmatio -larmadillo -Wl,-rpath,/usr/local/lib
CMakeFiles/SomeExecutable.dir/Common/src/FunctionTwo.cpp.o: In function `FunctionTwo::FunctionTwo(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, double, double, unsigned int, bool)':
FunctionTwo.cpp:(.text+0x490): undefined reference to `Helper::initLevel(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool)'
collect2: error: ld returned 1 exit status
CMakeFiles/SomeExecutable.dir/build.make:174: recipe for target 'SomeExecutable' failed
make[2]: *** [SomeExecutable] Error 1
make[2]: Leaving directory '/home/kepj/ProjectName'
CMakeFiles/Makefile2:67: recipe for target 'CMakeFiles/SomeExecutable.dir/all' failed
make[1]: *** [CMakeFiles/SomeExecutable.dir/all] Error 2
make[1]: Leaving directory '/home/kepj/ProjectName'
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2

So there is technically still not enough information about this issue to answer this question with certainty, but I am going to share how I would debug this isssue, only knowing what is in the question, explaining each step along the way.
Make sure you are linking to the correct myLib.so
This one is pretty explanatory, and would be my best guess as to the root of this problem.
Relevant compiler flags: -L/usr/local/lib -lmyLib
When trying to find the library you specified with the -l argument to your compile command, there is a series of steps that the linker takes:
1. It sees if the argument passed to -l was an absolute path (entire path to the library, ie starting with / on *nix computers or a drive letter on Windows) or just a name. If it is a absolute path, then it knows where it is. In this case, it is just a name, so continue on to step 2.
2. The next place to look is in the paths specified in -L arguments. In this case the only -L argument is to /usr/local/lib so it looks there. This may or may not be where it is found for this specific case. Look in your filesystem to see if the file /usr/local/lib/libmyLib.so exists, and if so make sure that is the version that is most recenpt.
3. Now it searches in configured linker paths. Use the same steps as in step 2 for each of these paths.
This is my guess because there is no reference to your myLib folder in your linker arguments, yet you claim it is in that folder, so I think it is using an out of date myLib.so.
Make sure the .so or .a file actually has the symbol that is undefined
On linux, you can list the symbols defined in a .so file. Make sure the symbol that is resolving to undefined is in there.
If they aren't there, here are the possible causes:
You aren't using all the C++ source files (.cpp) to create your library.
The definition and the declaration don't match:
You forgot to enter namespace Helper before defining the function
You misspelled the function name
The arguments/return type don't match
For member functions, you forgot to include MyClass:: before the function name.
ABI mismatch
(thanks to n.m in the comments for pointing this out)
Because there are multiple implementations (and versions) of the C++ standard library, it is possible that you have an ABI Mismatch.
This means that the standard library that myLib was compiled with is not compatable with the one you are trying to compile your executable with. For example, when you compile myLib with libstdc++ on linux, then go to mac and try to compile your executable, where the standard library is libc++ you will get errors. Why? The signature for anything, for example std::string is not the same. They are different classes entirely, and will cause a signature mismatch while linking.

Related

How do I set up a CMake project with subfolders?

I'm new to CMake so I apologize if my question turns out to be a noob one.
I'm trying to set up a project in C++ with a directory structure similar to what Maven would create if I was coding in Java (src directory and build directory):
root
├── build (where to build)
├── CMakeLists.txt (main one)
├── compile_commands.json -> ./build/compile_commands.json
├── doc
├── Doxyfile
└── src
├── CMakeLists.txt
├── common
│   └── Terminal.hpp
├── fsa
│   ├── CMakeLists.txt
│   ├── Machine.cpp
│   ├── Machine.hpp
│   └── MachineState.hpp
└── main.cpp
I don't know how to properly set CMake so to recognize, compile and link all the files. In particular, I think I should use (a mix of) add_subdirectory(), add_executable(), link_directories(), target_link_libraries(), add_library() and target_include_directories(), but I'm not sure I got how.
I provide later my CMakeLists.txt files, but when I configure and compile, I get:
/usr/bin/ld: fsa/libfsalib.a(Machine.cpp.o): in function `Machine::addState(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, bool)':
Machine.cpp:(.text+0xd1): undefined reference to `MachineState::MachineState(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool)'
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/elr1.dir/build.make:98: src/elr1] Error 1
make[1]: *** [CMakeFiles/Makefile2:115: src/CMakeFiles/elr1.dir/all] Error 2
make: *** [Makefile:91: all] Error 2
What do I do wrong?
EDIT: turned out it was a very stupid mistake of mine, I forgot to add an implementation. However, some questions remain:
Can you please tip me if this project/cmake structure is best practice or not?
I dind't get the where i should use link_directories() and target_include_directories().
More in general, how can I keep my codebase tidy and compile my project?
Thanks in advance
My commands are
to configure: "cmake -S /path_to_root_project -B /path_to_root_project/build -D CMAKE_EXPORT_COMPILE_COMMANDS=ON"
to compile: "cmake --build /path_to_root_project/build"
root_project/CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(elr1 VERSION 0.1)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_subdirectory(src)
root_project/src/CMakeLists.txt:
add_subdirectory(fsa)
# add the executable
add_executable(elr1 main.cpp)
link_directories(fsa)
target_link_libraries(elr1 #target in which link
fsalib #library name
)
root_project/src/fsa/CMakeLists.txt:
add_library(fsalib #name
Machine.cpp #files
MachineState.hpp
)
target_include_directories(fsalib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
)
Can you please tip me if this project/cmake structure is best practice or not?
There are none, or endless, best practices, and every day someone invents a new one. Especially as to how to structure your project, which is unrelated to CMake. Structure it in a way that you want, and you judge is the best. Your structure seems completely fine.
Look a look at endless google results. What's a good directory structure for larger C++ projects using Makefile? and http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1204r0.html project.
As for CMake you can take a look at the ultimate https://github.com/friendlyanon/cmake-init , https://github.com/cmake-lint/cmake-lint , https://gist.github.com/mbinna/c61dbb39bca0e4fb7d1f73b0d66a4fd1 .
where i should use link_directories() and target_include_directories().
Generally you should prefer target stuff, i.e. target_link_directories over non-target.
Use target_include_directories to add a path to #include <thishere> search path.
Use target_link_directories to add a library path to the search path target_link_libraries(... this_library_here). Usually you want to use add_library(... IMPORTED), then find_library, instead of target_link_directories. See man ld.
In your project there are no external shared .so nor static .a libraries. I see no reason to use link_directories at all.
how can I keep my codebase tidy and compile my project?
Well, you can work hard and cleanup your project often. Remember about regular exercise, sleep and to eat healthy.
Instead of set(CMAKE_CXX_STANDARD 11) prefer target_set_properties(. .. CXX_STANDARD 11).

Undefined reference after using CMAKE to generate a makefile

I can generate my CMake project, but I can't build it.
I have a fairly straightforward project structure:
├── bin
├── build
├── CMakeLists.txt
├── include
│   └── project
│   ├── base_socket.h
│   ├── tcp_client.h
│   ├── tcp_server.h
│   ├── udp_client.h
│   └── udp_server.h
├── LICENSE.txt
├── README.md
└── src
└── project
├── base_socket.cpp
├── CMakeLists.txt
├── main.cpp
├── tcp_client.cpp
├── tcp_server.cpp
├── udp_client.cpp
└── udp_server.cpp
And a fairly straight forward CMakeLists.txt file in the top directory:
# Project initialization
cmake_minimum_required(VERSION 2.7.2 FATAL_ERROR)
project("cpp_sockets")
# Add include directory
include_directories(include)
# Add subdirectories
add_subdirectory(src/project)
And also a fairly simple one in src/project/CmakeLists.txt:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(HEADER_DIR ${CMAKE_SOURCE_DIR}/include/project)
set(HEADER_FILES
${HEADER_DIR}/base_socket.h
${HEADER_DIR}/tcp_client.h
${HEADER_DIR}/tcp_server.h
${HEADER_DIR}/udp_client.h
${HEADER_DIR}/udp_server.h
)
add_executable(cpp_sockets main.cpp ${HEADER_FILES})
When I cd into /build and type cmake .. it works fine.
However, when I follow that with make, I get many terrible errors about undefined reference.
main.cpp:(.text+0x2c6): undefined reference to `UDPClient::UDPClient(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x2eb): undefined reference to `UDPClient::send_message(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x359): undefined reference to `UDPServer::UDPServer(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x380): undefined reference to `UDPServer::socket_bind()'
main.cpp:(.text+0x38c): undefined reference to `UDPServer::listen()'
main.cpp:(.text+0x400): undefined reference to `TCPClient::TCPClient(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x40c): undefined reference to `TCPClient::make_connection()'
main.cpp:(.text+0x42b): undefined reference to `TCPClient::send_message(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x492): undefined reference to `TCPServer::TCPServer(int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
main.cpp:(.text+0x4b9): undefined reference to `TCPServer::socket_bind()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `UDPClient::~UDPClient()':
main.cpp:(.text._ZN9UDPClientD2Ev[_ZN9UDPClientD5Ev]+0x14): undefined reference to `Socket::~Socket()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `UDPServer::~UDPServer()':
main.cpp:(.text._ZN9UDPServerD2Ev[_ZN9UDPServerD5Ev]+0x14): undefined reference to `Socket::~Socket()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `TCPClient::~TCPClient()':
main.cpp:(.text._ZN9TCPClientD2Ev[_ZN9TCPClientD5Ev]+0x14): undefined reference to `Socket::~Socket()'
CMakeFiles/cpp_sockets.dir/main.cpp.o: In function `TCPServer::~TCPServer()':
main.cpp:(.text._ZN9TCPServerD2Ev[_ZN9TCPServerD5Ev]+0x14): undefined reference to `Socket::~Socket()'
collect2: error: ld returned 1 exit status
src/project/CMakeFiles/cpp_sockets.dir/build.make:94: recipe for target '../bin/cpp_sockets' failed
make[2]: *** [../bin/cpp_sockets] Error 1
CMakeFiles/Makefile2:85: recipe for target 'src/project/CMakeFiles/cpp_sockets.dir/all' failed
make[1]: *** [src/project/CMakeFiles/cpp_sockets.dir/all] Error 2
Makefile:83: recipe for target 'all' failed
make: *** [all] Error 2
main.cpp file looks like:
#include "project/udp_server.h"
#include "project/udp_client.h"
#include "project/tcp_client.h"
Why would the linker not be able to find the references like this?
It looks like your src/project/CMakeLists.txt neglects to specify the other cpp files, like udp_server.cpp and udp_client.cpp, as dependencies of the executable cpp_sockets. You need to do this in order for CMake to compile those source files; it won't automatically figure out to compile them just because you have included their corresponding headers. In fact, the add_executable declaration doesn't need to say anything about the headers, because the include_directories command takes care of that.
Given the header files that your main.cpp depends on, its add_executable line should look like this:
add_executable(cpp_sockets main.cpp udp_server.cpp udp_client.cpp tcp_client.cpp)

Cmake: cannot open output file no such file or directory

I am learning to use cmake for a project using a shared library, but I keep getting this error:
Linking CXX executable test/test/robot_test
/usr/bin/ld: cannot open output file test/test/robot_test: No such file or directory
collect2: error: ld returned 1 exit status
make[2]: *** [test/test/robot_test] Error 1
make[1]: *** [CMakeFiles/test/robot_test.dir/all] Error 2
make: *** [all] Error 2
Here is my CMake file:
cmake_minimum_required(VERSION 2.8.12)
project("Particle Filter")
set(CMAKE_BUILD_TYPE Release)
include_directories(include)
set(LIB_SOURCES src/robot.cc src/sampler.cc src/general.cc)
set(LIB_HEADERS include/robot.h include/sampler.h include/general.h)
add_library(my_lib SHARED ${LIB_SOURCES} ${LIB_HEADERS})
install(TARGETS my_lib DESTINATION lib)
set(APP_SOURCES test/robot_test.cc test/sampler_test.cc)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
foreach(test ${APP_SOURCES})
#cut off .cc of src files using empty string
string(REPLACE ".cc" "" testname ${test})
add_executable(${testname} ${test})
target_link_libraries(${testname} my_lib)
endforeach(test ${APP_SOURCES})
add_definitions(
-std=c++11 # Or -std=c++0x
# Other flags
)
Here is my tree (excluding the build directory that contains a lot of this such as my makefile,.so and .a file):
├── CMakeLists.txt
├── driver.cc
├── include
│   ├── general.h
│   ├── robot.h
│   └── sampler.h
├── lib
├── notes
├── src
│   ├── general.cc
│   ├── robot.cc
│   └── sampler.cc
└── test
├── robot_test.cc
└── sampler_test.cc
Also, the .so or .a files are not getting saved to my lib folder after sudo make install, how do I fix this?
The first parameter for command add_executable is not a filename but a name of target. Target's name shouldn't contain special symbols like slash ("/").
You may control output directory of executables created by setting variable CMAKE_RUNTIME_OUTPUT_DIRECTORY:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test")
...
# Relative path to executable will be 'test/robot_test'.
add_executable(robot_test robot_test.cc)

using cmake, gTest and OpenCV: 'undefined reference to'

I tried to compile project consist of GTest, OpenCV, CMake and Make(It is only a script). The hierarchy is:
.
├── build
├── include
│   ├── csv_loader.h
│   ├── loader.h
│   ├── mat_reader.h
│   ├── processor.h
│   └── reader.h
├── Makefile
├── pictures
│   └── pila_original.jpg
├── sources
│   ├── CMakeLists.txt
│   ├── csv_loader.cpp
│   ├── mat_reader.cpp
│   └── processor.cpp
└── test
├── CMakeLists.txt
├── hello-test.cpp
└── not_null_data-test.cpp
When I tried to compile whole project, I got this error in test/CmakeLists.txt:
CMakeFiles/CPOO-PROJECT-TEST.dir/not_null_data-test.cpp.o: In function `NOTNULL_flowtest_Test::TestBody()':
not_null_data-test.cpp:(.text+0x1e): undefined reference to `Processor::Processor()'
not_null_data-test.cpp:(.text+0x2d): undefined reference to `Processor::Detect()'
not_null_data-test.cpp:(.text+0xfb): undefined reference to `Processor::~Processor()'
not_null_data-test.cpp:(.text+0x145): undefined reference to `Processor::~Processor()'
collect2: error: ld returned 1 exit status
./test/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(CPOO-PROJECT-TEST)
find_package( OpenCV 3.1.0 REQUIRED )
#eanble_testing()
find_package( GTest REQUIRED )
add_definitions(-std=c++11)
set (LIB ../release/libCPOO-PROJECT.so)
file(GLOB TEST "*.cpp")
include_directories(../include)
include_directories( ${OpenCV_INCLUDE_DIRS}
${GTest_INCLUDE_DIRS})
add_executable( ${PROJECT_NAME} ${LIB} ${TEST})
target_link_libraries( ${PROJECT_NAME}
${GTEST_BOTH_LIBRARIES}
pthread
)
I don't know how to fix linker problem, if there is any additional information needed, I'll add them.
EDIT 1
After adding flag to CMake, I get this log:
Scanning dependencies of target CPOO-PROJECT-TEST
make[3]: Leaving directory '/home/mateusz/Projects/EiTI/CPOO/build/test'
make -f CMakeFiles/CPOO-PROJECT-TEST.dir/build.make CMakeFiles/CPOO-PROJECT-TEST.dir/build
make[3]: Entering directory '/home/mateusz/Projects/EiTI/CPOO/build/test'
[ 33%] Building CXX object CMakeFiles/CPOO-PROJECT-TEST.dir/hello-test.cpp.o
/usr/bin/c++ -I/home/mateusz/Projects/EiTI/CPOO/test/../include -I/usr/include/opencv -std=c++11 -o CMakeFiles/CPOO-PROJECT-TEST.dir/hello-test.cpp.o -c /home/mateusz/Projects/EiTI/CPOO/test/hello-test.cpp
[ 66%] Building CXX object CMakeFiles/CPOO-PROJECT-TEST.dir/not_null_data-test.cpp.o
/usr/bin/c++ -I/home/mateusz/Projects/EiTI/CPOO/test/../include -I/usr/include/opencv -std=c++11 -o CMakeFiles/CPOO-PROJECT-TEST.dir/not_null_data-test.cpp.o -c /home/mateusz/Projects/EiTI/CPOO/test/not_null_data-test.cpp
[100%] Linking CXX executable CPOO-PROJECT-TEST
/usr/bin/cmake -E cmake_link_script CMakeFiles/CPOO-PROJECT-TEST.dir/link.txt --verbose=1
/usr/bin/c++ CMakeFiles/CPOO-PROJECT-TEST.dir/hello-test.cpp.o CMakeFiles/CPOO-PROJECT-TEST.dir/not_null_data-test.cpp.o -o CPOO-PROJECT-TEST -rdynamic -lgtest -lgtest_main -lpthread
CMakeFiles/CPOO-PROJECT-TEST.dir/not_null_data-test.cpp.o: In function `NOTNULL_flowtest_Test::TestBody()':
not_null_data-test.cpp:(.text+0x1e): undefined reference to `Processor::Processor()'
not_null_data-test.cpp:(.text+0x2d): undefined reference to `Processor::Detect()'
not_null_data-test.cpp:(.text+0xfb): undefined reference to `Processor::~Processor()'
not_null_data-test.cpp:(.text+0x145): undefined reference to `Processor::~Processor()'
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/CPOO-PROJECT-TEST.dir/build.make:126: CPOO-PROJECT-TEST] Error 1
make[3]: Leaving directory '/home/mateusz/Projects/EiTI/CPOO/build/test'
make[2]: *** [CMakeFiles/Makefile2:71: CMakeFiles/CPOO-PROJECT-TEST.dir/all] Error 2
make[2]: Leaving directory '/home/mateusz/Projects/EiTI/CPOO/build/test'
make[1]: *** [Makefile:87: all] Error 2
make[1]: Leaving directory '/home/mateusz/Projects/EiTI/CPOO/build/test'
make: *** [Makefile:13: build-test] Error 2

CMake: Undefined reference to function

I have following directory structure:
├── build (empty dir)
├── CMakeLists.txt
├── easylogging++.h
├── help.h
├── operation.h
├── operation_list.h
├── operations
│   ├── CMakeLists.txt
│   ├── matchcount.cc
│   └── matchcount.h
└── ops_toolkit.cc
And I am new to CMake and trying to write CMakeLists.txt.
My matchcount.h has a signature whose implementation is in matchcount.cc (as typical C/C++ structure).
Following is my CMakeLists.txt in base directory
cmake_minimum_required(VERSION 2.6)
project(ops_toolkit)
add_subdirectory(operations)
add_executable(ops_toolkit ops_toolkit.cc)
set(CMAKE_CXX_FLAGS "-std=c++0x")
and following is the one in operations directory
include_directories(${ops_toolkit_SOURCE_DIR}/operations)
link_directories(${ops_toolkit_BINARY_DIR}/operations)
set(all_operations_HEADER operations/matchcount.h)
set(all_operations_SOURCES operations/matchcount.cc)
I am getting undefined reference for function signature called int matchcount(int, const char**) and make complains following
dev:~/work/ops_toolkit/build$ make
Scanning dependencies of target ops_toolkit
[100%] Building CXX object CMakeFiles/ops_toolkit.dir/ops_toolkit.cc.o
Linking CXX executable ops_toolkit
CMakeFiles/ops_toolkit.dir/ops_toolkit.cc.o: In function `__static_initialization_and_destruction_0(int, int)':
ops_toolkit.cc:(.text+0x249): undefined reference to `operations::matchcount(int, char const**)'
collect2: ld returned 1 exit status
make[2]: *** [ops_toolkit] Error 1
make[1]: *** [CMakeFiles/ops_toolkit.dir/all] Error 2
make: *** [all] Error 2
Can someone help me with this?
Thanks
The problem comes from the add_subdirectory and its associated CMakeLists.txt (the one in ./operations), which is incorrect, see this SO question for the implications of the add_subdirectory command.
I also advise you to put include_directories and link_directories in the main CMake file, for clarity.