Undefined Python references in C++ using CMake - c++

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

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)

Source-built gcc linking error

I have Debian Wheezy and I need C++11 features to build my project. I've compiled gcc(c and c++ only) from source and put the libraries under my home folder using this question. I am also using the wrapper script supplied by the guy who answered that question which is
$HOME/gcc/gcc-4.8.4/bin/g++ -Wl,-rpath,$HOME/gcc/gcc-4.8.4/lib32 "$#"
Now, I have a game engine that I use in my project for GUI and graphic operations. It compiles in 32 bit just fine. I pass -m32 switch for all of the external libraries it uses and the engine itself. Also, in order for cmake to find my wrapper, I give following options while running cmake
cmake .. -DCMAKE_CXX_COMPILER=path/to/my/32-bit-wrapper
After compilation, it gives following linking erros
undefined reference to `XOpenDisplay'
undefined reference to `glBlendFunc'
undefined reference to `alGenBuffers'
At first, I thought I may be missing the 32-bit development libraries, so I installed following packages.
libgl1-mesa-dev:i386
libopenal-dev:i386
libx11-dev:i386
but I am getting errors, regardless. So, How can I solve this problem? I can supply additional information such as cmake files etc if needed. Thank you in advance.
EDIT
Cmake file in case if error stems from it
cmake_minimum_required(VERSION 2.8.3)
project(uwmf)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -m32 -DLINUX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32 -DLINUX")
#set(CMAKE_CXX_COMPILER "${HOME_PATH}/devel/g++-4.8.4-32")
#set(CMAKE_C_COMPILER "${HOME_PATH}/devel/gcc-4.8.4-32")
message("${CMAKE_CXX_FLAGS}")
message("${CMAKE_C_FLAGS}")
message("${CMAKE_CXX_COMPILER}")
message("${CMAKE_C_COMPILER}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(GGE ${HOME_PATH}/devel/gorgon-3.x)
set(GRAPHICS ${HOME_PATH}/devel/graphics)
set(SOURCES
src/source.cpp
src/algorithms.h
src/cloud-gen.h
src/latex.h
src/macros.h
src/matrix.h
src/utils.h
)
include_directories(${GGE})
include_directories(${GRAPHICS})
add_executable(uwmf ${SOURCES})
target_link_libraries(uwmf ${GGE}/build/libGGE.a)
UPDATE
ereOn's answer did the trick. I also had to install libalut-dev:i386 and link (-lalut) to successfully compile. I get many warning messages like the following (probably due to introducing additional linkage of same library)
/usr/bin/ld: Warning: type of symbol `glDrawBuffers' changed from 2 to 1 in ../devel/gorgon-3.x/build/libGGE.a(OpenGL.cpp.o)
/usr/bin/ld: Warning: type of symbol `glGetAttribLocation' changed from 2 to 1 in ../devel/gorgon-3.x/build/libGGE.a(OpenGL.cpp.o)
but these are not part of this question. Thank you for your help.
It could be that the symbols that are reported missing are not used by your game engine library and were thus "optimized out" to make for a smaller binary.
Try linking your target executable explicitely with -lX11 and -lGL to see if that works.
As #ereOn said, the linker could have optimized out some symbols. Try linking with -Wl,--no-as-needed.

Trying to compile OpenGL 4 Helloworld in CLion+CMake+MinGW on Windows. "undefined reference to `_imp____glewCreateShader' " errors [duplicate]

This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 7 years ago.
Googling aroung told me it was "wrong VS libraries" but when tried to use glew-1.5.4-mingw32 and libgluew32.a instead of glew32.lib (and same done to glut) nothing changed.
main.cpp got from project on VS2012, attaching same libs, so it may not be wrong.
Some files I use to make:
CMakeLists.txt
cmake_minimum_required(VERSION 2.8.4)
project(HelloGL)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
add_executable(HelloGL main.cpp)
set(LIBS_DIR D:/libs)
set(GLEW_ROOT_DIR ${LIBS_DIR}/glew-1.5.4-mingw32 )
set(GLUT_ROOT_DIR ${LIBS_DIR}/glut-3.7.6-src/glut-3.7.6 )
set(GLEW_INCLUDE_DIRS ${GLEW_ROOT_DIR}/include)
set(GLUT_INCLUDE_DIRS ${GLUT_ROOT_DIR}/include)
set(GLEW_LIBRARY ${GLEW_ROOT_DIR}/lib/libglew32.a)
set(GLUT_LIBRARY ${GLUT_ROOT_DIR}/lib/glut/libglut32.a)
include_directories( ${GLEW_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS} )
target_link_libraries(HelloGL ${GLEW_LIBRARY} ${GLUT_LIBRARY} )
Part of LOG:
"D:\Tools\CLion 140.569.17\bin\cmake\bin\cmake.exe" --build C:\Users\Alexey\.clion10\system\cmake\generated\dc6fcb22\dc6fcb22\Debug --target HelloGL -- -j 8
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Users/Alexey/.clion10/system/cmake/generated/dc6fcb22/dc6fcb22/Debug
Linking CXX executable HelloGL.exe
CMakeFiles\HelloGL.dir/objects.a(main.cpp.obj): In function `Z11LoadShadersPKcS0_':
D:/Projects/CPP/HelloGL/main.cpp:19: undefined reference to `_imp____glewCreateShader'
D:/Projects/CPP/HelloGL/main.cpp:20: undefined reference to `_imp____glewCreateShader'
D:/Projects/CPP/HelloGL/main.cpp:56: undefined reference to `_imp____glewShaderSource'
D:/Projects/CPP/HelloGL/main.cpp:57: undefined reference to `_imp____glewCompileShader'
D:/Projects/CPP/HelloGL/main.cpp:60: undefined reference to `_imp____glewGetShaderiv'
D:/Projects/CPP/HelloGL/main.cpp:61: undefined reference to `_imp____glewGetShaderiv'
D:/Projects/CPP/HelloGL/main.cpp:64: undefined reference to `_imp____glewGetShaderInfoLog'
Try adding this line to your CMakeLists.txt:
add_definitions(-DGLEW_STATIC)
It seems that you are trying to link GLEW statically but you didn't define GLEW_STATIC
Did you compile GLEW yourself?
Generally the library called glew32 is dynamic linking and glew32s is static. MinGW really does not like the dynamic (DLL) version of GLEW and you should probably avoid it. The pre-built Windows dynamic GLEW libraries that are distributed on the GLEW site will not work with MinGW because of differences between Visual C++ and gcc's function naming convention for import libraries (it is a difference of one underscore, but enough to make life really difficult).
If you #define GLEW_STATIC before including <glew.h> and link to glew32s that will eliminate any potential issues with the dynamic linking library. In practice, this works best if you add the definition to your Makefile as Nazar554 has demonstrated.
This gist is how I compile OpenGL project in linux. Hope it helps

'undefined reference to' with cmake

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.