CMake: Undefined reference to function - c++

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.

Related

How to properly link an installed library to the CMake in Windows?

I have a CMake project that uses mosquittopp. It is properly running on Linux without needing any additional configurations (i.e. #include <mosquittopp.h> works without target_include_directories; and libraries are linked without find_library)
However, when I try the same on Windows, I am constantly having undefined reference problems. Here is the minimal reproducible example:
Install mosquitto to the system; Here are some files from C:/Program Files/mosquitto:
├── libcrypto.dll
├── libssl.dll
├── mosquitto.dll
├── mosquitto.exe
├── mosquittopp.dll
├── devel
│   ├── mosquitto.h
│   ├── mosquitto.lib
│   ├── mosquittopp.h
│   └── mosquittopp.lib
Write and save the following to main.cpp:
#include <iostream>
#include <mosquittopp.h>
int main() {
std::cout << "hello world";
mosqpp::lib_init();
return 0;
}
Create the following CMakeLists.txt file:
111
cmake_minimum_required(VERSION 3.15)
project(sandbox LANGUAGES CXX)
add_executable(MainFile main.cpp)
target_include_directories(MainFile PUBLIC "C:/Program Files/mosquitto/devel")
target_link_libraries(MainFile "C:/Program Files/mosquitto/devel/mosquittopp.lib")
set_property(TARGET MainFile PROPERTY CXX_STANDARD 17)
set_property(TARGET MainFile PROPERTY CXX_STANDARD_REQUIRED On)
set_property(TARGET MainFile PROPERTY CXX_EXTENSIONS Off)
I tried to use different combinations of find_library(), absolute paths, adding and removing dll files, adding all lib files but to no avail.
EDIT: The error message in this example is:
[build] C:/Users/myuser/OneDrive/Desktop/test/main.cpp:6: undefined reference to `__imp__ZN6mosqpp8lib_initEv'
[build] collect2.exe: error: ld returned 1 exit status
[build] mingw32-make[2]: *** [CMakeFiles\MainFile.dir\build.make:101: MainFile.exe] Error 1
[build] mingw32-make[1]: *** [CMakeFiles\Makefile2:82: CMakeFiles/MainFile.dir/all] Error 2
[build] mingw32-make: *** [Makefile:90: all] Error 2
this is a minimal reproducible example, but the similar errors arise in the full project as well.
I think I know where the issue is now after looking at the error message and checking out mosquitopp.
My current guess is that you've downloaded pre-compiled binaries from their download page.
These binaries were built using MSVC (2019) however you are using mingw32 to build your project. This is apparent from the line here:
[build] mingw32-make[2]: *** [CMakeFiles\MainFile.dir\build.make:101: MainFile.exe] Error 1
You cannot use different compilers, the binaries will always most likely be different. So you have two options now to solve this:
Build your own mosquittopp library using mingw32
Build your application using MSVC 2019

cmake mutliple targets - one header only target and another an executable

Based on this stackoverflow answer to a similar question (Cmake include header only target from header only target), I am creating a header only library and trying to use it in an executable.
My folder structure is below:
├── CMakeLists.txt // root folder CMake file
├── srcs // this is the hdr only library
│   ├── src1.hpp
│   ├── CMakeLists.txt
│   ├── src2.hpp
│   └── src3.hpp
│   └── ...
└── test // this is the executable project
├── CMakeLists.txt
└── main.cpp
Root level CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project (MyProj CXX)
add_subdirectory(srcs)
add_subdirectory(test)
src level CMakeLists.txt (for header only library)
add_library(MyLib INTERFACE)
target_sources(MyLib INTERFACE
"${CMAKE_CURRENT_SOURCE_DIR}/src1.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src2.hpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src3.hpp"
)
target_include_directories(MyLib
INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(plugins)
CMake file for executable test project
add_executable(MyTest main.cpp)
target_sources(MyTest
PRIVATE main.cpp
)
target_include_directories(MyTest PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
target_link_libraries(MyTest PUBLIC MyLib)
Though this configures cmake without warnings/error, running the make fails, indicating that the executable project is unable to find the header file(s) from library.
/.../nettu2/test/main.cpp:6:10: fatal error: src1.hpp: No such
file or directory #include "src1.hpp"
^~~~~~~~~~~~~~~~ compilation terminated. test/CMakeFiles/MyTest.dir/build.make:62: recipe for target
'test/CMakeFiles/MyTest.dir/main.cpp.o' failed make[2]: *
[test/CMakeFiles/MyTest.dir/main.cpp.o] Error 1
CMakeFiles/Makefile2:126: recipe for target
'test/CMakeFiles/MyTest.dir/all' failed make[1]: *
[test/CMakeFiles/MyTest.dir/all] Error 2 Makefile:129: recipe for
target 'all' failed make: *** [all] Error 2
I am sure that I am missing some crucial but trivial thing here, but yet unable to figure out, what is going wrong here. How can I get this build working?
You have a minor mistake in this line:
target_include_directories(MyLib
INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
The include directory you specify for MyLib expands to the build directory corresponding to srcs, i.e. it results in an invocation like
clang++ /path/to/build/test/test.cpp -I /path/to/build/srcs ...
but you want to pass the actual source directory to the preprocessor. To fix this, try
target_include_directories(MyLib
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

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

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.