'undefined reference to' with cmake - c++

So, I am trying to write an applet for school, and part of it requires using cmake. I have two different classes contained in their own files, and I use them as part of the main class. I have included their headers as such in the main project header:
#include /path/to/header/1.h
#include /path/to/header/2.h
The problem I have is that when I run make after I've run cmake, I get undefined reference errors for any instance in which I try to use one of the two libraries. I know that it has to do with linker errors, but since I'm new to cmake, I'm not exactly sure what the proper way to use TARGET_LINK_LIBRARIES would be.
EDIT
After linking/associating my libraries, I have the following:
CMakeLists.txt:
# A name for the project
project(plasma-engine-gdrive)
# Find the required libaries
find_package(KDE4 REQUIRED)
include(KDE4Defaults)
add_definitions (${QT_DEFINITIONS} ${KDE4_DEFINITIONS}, -std=c++0x)
include_directories(
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
${KDE4_INCLUDES}
./include
./lib
)
set (GOOGLE_LIBS include/atom_helper.h include/util/string_utils.h include/client/doc_list_service.h include/client/service.h)
set (GOOGLE_SRCS include/atom_helper.cc include/util/string_utils.cc include/client/doc_list_service.cc include/client/service.cc)
# We add our source code here
set(gdrive_engine_SRCS gdriveengine.cpp)
add_library (DataWrapper include/DataWrapper.cpp include/DataWrapper.h)
add_library (GData ${GOOGLE_SRCS} ${GOOGLE_LIBS})
# Now make sure all files get to the right place
kde4_add_plugin(plasma_engine_gdrive ${gdrive_engine_SRCS})
target_link_libraries(plasma_engine_gdrive
GData
DataWrapper
${KDE4_KDECORE_LIBS}
${KDE4_PLASMA_LIBS})
install(TARGETS plasma_engine_gdrive
DESTINATION ${PLUGIN_INSTALL_DIR})
install(FILES plasma-engine-gdrive.desktop
DESTINATION ${SERVICES_INSTALL_DIR})
There are also too many errors to put here. Here's a few:
/usr/include/c++/4.6/bits/stl_map.h:467: undefined reference to `Glib::ustring::ustring()'
lib/libGData.a(atom_helper.o): In function `pair<Glib::ustring, Glib::ustring, void>':
/usr/include/c++/4.6/bits/stl_pair.h:132: undefined reference to `Glib::ustring::ustring(Glib::ustring const&)'
/usr/include/c++/4.6/bits/stl_pair.h:132: undefined reference to `Glib::ustring::ustring(Glib::ustring const&)'
lib/libGData.a(atom_helper.o): In function `pair<Glib::ustring, Glib::ustring>':
/usr/include/c++/4.6/bits/stl_pair.h:137: undefined reference to `Glib::ustring::ustring(Glib::ustring const&)'
/usr/include/c++/4.6/bits/stl_pair.h:137: undefined reference to `Glib::ustring::ustring(Glib::ustring const&)'

I was working with some others and I got it compiled!
All I really needed was to provide the name of the library and put it into target_link_libraries like so:
target_link_libraries(plasma_engine_gdrive
DataWrapper
GData
xml++-2.6
curl
glibmm-2.4
${KDE4_KDECORE_LIBS}
${KDE4_PLASMA_LIBS})
My dad, being completely unfamiliar with CMake, went and dug out the link.txt within the CMake build structure. There, he just added the following after the -o flag:
-lxml++-2.6
-lcurl
-lglibmm-2.4
When I saw that, I thought I might try to do that linking through CMakeLists.txt -- and it worked.

Related

CMake 'undefined reference' error with CERN-ROOT

I'm writing a small addition to CERN ROOT and now can't get rid of 'undefined reference' errors on every function from ROOT that I use (and my classes too). Can't find a way to fix this, so looking for help here.
My OS is Linux Mint 19. I use g++ as my c++ compiler, however, I tried clang++ and there was no difference.
I downloaded sources of ROOT from their github and built it now on my computer. Output of root --version is this:
ROOT Version: 6.19/01
Built for linuxx8664gcc on Sep 29 2019, 14:25:35
From heads/master#v6-19-01-1167-gbec9f2d1f7
This is the structure of my project:
ParentFolder
--CMakeLists.txt
--General
----include/...
----source/...
----CMakeLists.txt
----LinkDef.h
--Test
----include/...
----source/...
----CMakeLists.txt
Important lines from top level CMakeLists.txt are:
find_package(ROOT REQUIRED)
list(APPEND CMAKE_PREFIX_PATH $ENV{ROOTSYS})
include(${ROOT_USE_FILE})
add_subdirectory("./General")
add_subdirectory("./Test")
From Test/CmakeLists.txt:
add_executable(Test source/test_main.cpp)
target_include_directories(Test PUBLIC "./include")
target_link_libraries(Test PUBLIC General GTest::GTest GTest::Main ${ROOT_LIBRARIES})
From General/CmakeLists.txt:
file(GLOB_RECURSE SOURCES . source/*.cpp)
ROOT_GENERATE_DICTIONARY(GeoManagerExtractor LINKDEF LinkDef.h)
add_library(General SHARED ${SOURCES} GeoManagerExtractor.cxx)
target_link_libraries(General ${ROOT_LIBRARIES})
target_include_directories(General PUBLIC "./include")
Here are first few lines produced by CMake (while using clang++)
CMakeFiles/Test.dir/source/test_main.cpp.o: In function `main':
test_main.cpp:(.text+0x37): undefined reference to `TGeoManager::Import(char const*, char const*, char const*)'
test_main.cpp:(.text+0x3f): undefined reference to `gGeoManager'
test_main.cpp:(.text+0x8c): undefined reference to `gGeoManager'
CMakeFiles/Test.dir/source/test_main.cpp.o: In function `TGeoManagerExporter::~TGeoManagerExporter()':
test_main.cpp:(.text._ZN19TGeoManagerExporterD2Ev[_ZN19TGeoManagerExporterD2Ev]+0xa): undefined reference to `vtable for TGeoManagerExporter'
../General/libGeneral.so: undefined reference to `ROOT::GenerateInitInstance(TGeoManagerExporter const*)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Here are a few lines from test_main.cpp:
TGeoManager::Import("../root_tests/geofile_full.root");
if (gGeoManager == nullptr) {
std::cerr << "Can't find TGeoManager in file" << std::endl;
return 0;
}
UPD: Forgot to mention, that in order to create my CMakeLists.txt files I used these two sources:
https://root.cern.ch/how/integrate-root-my-project-cmake
https://cliutils.gitlab.io/modern-cmake/chapters/packages/ROOT.html
I have managed to compile my project.
As it turned out, .so file that contains TGeoManager implementation was not included in ROOT_LIBRARIES(thanks, Kamil Cuk for bringing my attention to this variable) by the script provided by ROOT developers. It was hard to find as this class was working properly in Cling(c++ interpreter included with ROOT) and this class is almost the only one from ROOT that I use in the project, so I assumed, that the whole ROOT library was not linking properly. After I found this issue, I fixed my CMake files like this (this is from General/CmakeLists.txt):
file(GLOB_RECURSE SOURCES2 . $ENV{ROOTSYS}/lib/*.so)
add_library(General SHARED ${SOURCES} ${SOURCES2} GeoManagerExtractor.cxx)
This eliminates all of the "undefined reference to 'gGeoManager'" and alike, but "undefined reference to `vtable for TGeoManagerExporter'" (TGeoManagerExporter is my own class) stays. However, I figured out that this error is caused by a reflection feature, so as a temporary solution I just don't activate it. I'll post a comment here if I solve this problem.

C++ undefined reference for libtins library

I installed the libtins package for C++, by building it as described and adding #include <tins/tins.h> to the header of the example file. I ran ldconfig but building always throws a Undefined reference error:
CMakeFiles/lts.dir/main.cpp.o: In function `main':
/home/patrick/ClionProjects/lts/main.cpp:6: undefined reference to `Tins::EthernetII::EthernetII(Tins::HWAddress<6ul, unsigned char> const&, Tins::HWAddress<6ul, unsigned char> const&)'
/home/patrick/ClionProjects/lts/main.cpp:7: undefined reference to `Tins::IPv4Address::IPv4Address(char const*)'
/home/patrick/ClionProjects/lts/main.cpp:7: undefined reference to `Tins::IPv4Address::IPv4Address(char const*)'
/home/patrick/ClionProjects/lts/main.cpp:7: undefined reference to `Tins::IP::IP(Tins::IPv4Address, Tins::IPv4Address)'
/home/patrick/ClionProjects/lts/main.cpp:8: undefined reference to `Tins::TCP::TCP(unsigned short, unsigned short)'
/home/patrick/ClionProjects/lts/main.cpp:10: undefined reference to `Tins::PDU::inner_pdu(Tins::PDU*)'
/home/patrick/ClionProjects/lts/main.cpp:12: undefined reference to `Tins::PDU::inner_pdu(Tins::PDU*)'
CMakeFiles/lts.dir/main.cpp.o: In function `Tins::EthernetII::~EthernetII()':
/usr/local/include/tins/ethernetII.h:46: undefined reference to `vtable for Tins::EthernetII'
/usr/local/include/tins/ethernetII.h:46: undefined reference to `Tins::PDU::~PDU()'
collect2: error: ld returned 1 exit status
make[3]: *** [lts] Error 1
I am using CLion as IDE and the following cmake file:
cmake_minimum_required(VERSION 3.5)
project(lts)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -ltins")
set(SOURCE_FILES main.cpp)
add_executable(lts ${SOURCE_FILES})
Any Idea what could be the problem?
There's a couple of things to address in your question. First, let CMake find the location of the libtins library for you, then use target_link_libraries() to add it to your lts executable. In the CMake sample in your question, you are specifying library options in the compiler flags variable (CMAKE_CXX_FLAGS). The other thing is to also let CMake handle setting the appropriate compiler flags for C++11 instead of manually adding them to CMAKE_CXX_FLAGS (which would only take care of the compiler part but not the linker). The following should do what you want in a robust, platform independent way:
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(lts)
find_library(TINS_LIBRARY tins)
set(SOURCE_FILES main.cpp)
add_executable(lts ${SOURCE_FILES})
target_link_libraries(lts "${TINS_LIBRARY}")
I recommend you read the CMake docs for find_library() and target_link_libraries() to understand what those commands do. For the C++11 stuff, I recommend this blog article for a more cohesive explanation than what the CMake docs give you (disclosure: I wrote the article).
The CMake variable CMAKE_CXX_FLAGS is for the compiler flags, not for libraries.
To add a library you should use target_link_libraries:
target_link_libraries(lts tins)
If you want all targets to link to the same library, you should add it to the list CMAKE_STANDARD_LIBRARIES.
A small tip on debugging these kind of things: Either set CMAKE_VERBOSE_MAKEFILE or use make VERBOSE=1 to inhibit the normal CMake build output, and instead display the normal make output, which will show you all commands make runs, and all flags and options used for each and every program. That way you will be able to see the -ltins flag being passed as a compiler flag, but not as a linker flag or library.
The compiler should -ltins. Refer to CMake manual on how to add library dependencies.
From the Download page of libtins:
In order to link your application with libtins on GCC or clang, use the -ltins flag
Simply add the following line in your CMake file:
target_link_libraries(PROJECT_NAME -ltins)

Bundling opencv as a static library gives thousands of undefined references

I have a library that I am trying to link with openCV (and I think I did successfully) into one big dynamic library. I then try and add an executable and link everything together to test the library and I get 2000-3000 errors each saying
In function `________________`: undefined reference to `________`
some examples are:
/path/to/libs/libopencv_features2d.a(matchers.cpp.o): In function `cv::FlannBasedMatcher::read(cv::FileNode const&)':
matchers.cpp:(.text._ZN2cv17FlannBasedMatcher4readERKNS_8FileNodeE+0x227): undefined reference to `cv::flann::IndexParams::setAlgorithm(int)'
/path/to/libs/libopencv_videoio.a(cap_gstreamer.cpp.o)` In function `CvCapture_GStreamer::getProperty(int) const':
cap_gstreamer.cpp:(.text._ZNK19CvCapture_GStreamer11getPropertyEi+0x8b): undefined reference to `gst_element_query_position'
/path/to/lib/libopencv_core.a(stat.cpp.o): In function `cv::norm(cv::_InputArray const&, int, cv::_InputArray const&)':
stat.cpp:(.text._ZN2cv4normERKNS_11_InputArrayEiS2_+0x1d27): undefined reference to `ippicviNorm_L1_32f_C1MR'
stat.cpp:(.text._ZN2cv4normERKNS_11_InputArrayEiS2_+0x1dab): undefined reference to `ippicviNorm_L1_8u_C1MR'
My cmake file which runs:
project(SDK-build)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(MYLIB_SRC
file1.cpp
file2.cpp
file3.cpp
)
add_library(gesture SHARED ${MYLIB_SRC})
cmake_policy(SET CMP0015 NEW)
link_directories(./opencvlib-wgstreamer)
set(OPENCV_LIBS
libopencv_calib3d.a
libopencv_core.a
libopencv_features2d.a
libopencv_highgui.a
libopencv_imgcodecs.a
libopencv_imgproc.a
libopencv_ml.a
libopencv_objdetect.a
libopencv_photo.a
libopencv_video.a
libopencv_videoio.a
)
set(TEST_SRC
test.cpp
)
add_executable(gesture_test ${TEST_SRC})
#build library
#target_link_libraries(gesture -Wl,-whole-archive ${OPENCV_LIBS} -Wl,--no-whole-archive)
#build library with executable
target_link_libraries(gesture_test gesture -Wl,-whole-archive ${OPENCV_LIBS} -Wl,--no-whole-archive)
When I use the first target_link_libraries, everything builds and make has no problem executing, but linking with the file with main() causes the massive confusion. Any suggestions I've been banging my head over this for hours. I also tried several combinations of compiling opencv, using both WITH_IPP=ON, WITH_IPP=OFF, and WITH_GSTREAMER_ON
You have to specify the libraries in the correct order.
See here for more information.
Edit I see you are using -Wl-whole-archive which I believe is an other possible way to fix the problem, so maybe I'm wrong

How do I use a static library (in my case assimp) without the source files

I have a libassimp.a file and the header files. How can I use the library?
I'm adding the header files to my project with set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${ASSIMP_INCLUDE_DIR}"). With ASSIMP_INCLUDE_DIR being ../contrib/assimp/include.
Now when I use some class in my main.cpp it gives me errors about undefined references to some funtions, because obviously I don't have the source files.
When I add the libassimp.a to my compile flags I get the following errors when using make:
make[3]: *** No rule to make target `../contrib/assimp/lib/libassimp.a',
...
main.cpp:7:32: fatal error: assimp/Importer.hpp: No such file or directory
....
Linking CXX static library libassimp.a
I don't understand these messages. Maybe they are there because it's trying to access libassimp.a before it's actually there? Is this some kind of concurrency problem?
Anyways, if I call make again then I get different errors, namely a bunch of undefined references to things I am not using, e.g.
../contrib/assimp/lib/libassimp.a(AssbinLoader.cpp.o): In function `Assimp::AssbinImporter::InternReadFile(std::string const&, aiScene*, Assimp::IOSystem*)':
AssbinLoader.cpp:(.text+0x2a49): undefined reference to `uncompress'
EDIT:
I am compiling with CMake like this:
target_link_libraries(monoRenderer [some other libraries] ${ASSIMP_STATIC_LIB})
ASSIMP_STATIC_LIB is the path to libassimp.a.
EDIT2:
I reduced my CMake file to this:
cmake_minimum_required(VERSION 2.8.12)
project(monoRenderer)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
file(GLOB_RECURSE CXX_SRCS src/*.cpp)
file(GLOB_RECURSE C_SRCS src/*.c)
file(GLOB_RECURSE HPP_HDRS src/*.hpp)
file(GLOB_RECURSE H_HDRS src/*.h)
set(SRCS "${C_SRCS};${CXX_SRCS}")
set(HDRS "${H_HDRS};${HPP_HDRS}")
include_directories(${PROJECT_SOURCE_DIR}/contrib/assimp/include)
add_executable(monoRenderer ${SRCS} ${HDRS})
target_link_libraries(monoRenderer ${PROJECT_SOURCE_DIR}/contrib/assimp/lib/libassimp.a)
The header files are in contrib/assimp/include and the libassmip.a is in contrib/assimp/lib. It still doesn't work, same errors as before.
My main.cpp looks like this:
#include <assimp/Importer.hpp>
#include <cstdlib>
int main() {
Assimp::Importer importer;
return EXIT_SUCCESS;
}
EDIT3:
I think it has something to do with zlib, since all the errors seem to have that in common I think:
undefined reference to `uncompress'
undefined reference to `inflateInit2_'
undefined reference to `inflate'
undefined reference to `inflateEnd'
undefined reference to `inflateReset'
undefined reference to `inflateSetDictionary'
undefined reference to `get_crc_table'
undefined reference to `crc32'
As you stated yourself you are encountering problems with zlib. You have to add all dependencies from your static library yourself, e.g.:
target_link_libraries(monoRenderer z)
Since you stated that your header are located in contrib/assimp/include you might want to change your include in main.cpp to
#include <Importer.hpp>

Undefined Python references in C++ using CMake

I am trying to compile a c++ project referencing Python using CMake. I am using Cygwin and I have Python2.7 source files in Cygwin.
For example:
PyObject *l = PyList_New(0);
Online help suggested I add the -lpython2.7 linker flag. Am I not adding this correctly in CMake? Otherwise why can I still not use the Python library and how might I fix this?
The compile line:
C:\cygwin64\bin\cmake.exe --build "C:\Users\...\.clion10\system\cmake\generated\3e6845d6\3e6845d6\Release" --target projectname -- -j 4
The CMakeList.txt file:
cmake_minimum_required(VERSION 2.8.4)
project(projectname)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -lpython2.7")
set(SOURCE_FILES
src/cpp/...
src/cpp/...
src/cpp/..
src/cpp/...
src/cpp/...)
add_executable(projectname ${SOURCE_FILES})
The errors...
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaeb4): undefined reference to `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaeb4): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaec4): undefined reference to `PyList_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaec4): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `PyList_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaf0d): undefined reference to `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaf0d): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `PyDict_New'
CMakeFiles/spot.dir/src/cpp/OBwrapper.cpp.o:OBwrapper.cpp:(.text+0xaf25): undefined reference to `PyString_FromString'
...and so on....
You misunderstand CMake's way: before use something you ought to find it! I.e. make sure that everything you need to build your package is available and usable at build host. Otherwise that would be not good to waste a (compile) time (say 2 hours) and then get an error that some header/library/executable not found. So, at CMake run time you'd better to be sure that everything you need is here. To do so, CMake have a lot of tools.
Consider your particular case: you need to find Python libraries otherwise build is not possible. To do so, you ought to use find_package like this:
find_package(PythonLibs REQUIRED)
Take a look to documentation and provide other options (like version) if you need. You shouldn't use hardcoded paths in your CMakeLists.txt, otherwise your project wouldn't be really portable (and most probably you'll be the only who can build it w/o a lot of problems). Instead Python libs finder module will provide variables you need to use later, or failed w/ error if nothing has found.
If CMake ends w/o errors, you may use found Python libs. First of all you need to update #include paths:
include_directories(${PYTHON_INCLUDE_DIRS})
Then tell to linker that your executable projectname needs to be linked w/ Python libs:
add_executable(projectname ${SOURCE_FILES})
target_link_libraries(projectname ${PYTHON_LIBRARIES})
And again, try to avoid to modify CMAKE_CXX_FLAGS (and others) directly -- there are bunch of calls to do that globally and/or per target. Some of them are:
add_definitions to define/undefine macros
include_directories to update #include paths
add_compile_options to add other compiler options
link_directories to update linker search paths