Building and adding several libraries with CMake [duplicate] - c++

This question already has answers here:
CMake rejects a second target_link_libraries talking about "keyword" vs "plain" [duplicate]
(1 answer)
Using SDL2 with CMake
(12 answers)
Closed 6 days ago.
I am CMake newbie and trying to use it within a project of mine in order to learn it
The project is a small game engine that use different external libraries such as GLFW, GLUT and SDL2. Some of them such as GL are in my os include directory and some of them such as SDL are inside my source tree (/vendors/SDL2).
I am trying to build the SDL2 library which is a few header files and link it to my project.
After some research I found out that the INTERFACE keyword should be used, this is how I am trying to do it :
add_library(SDL2 INTERFACE)
target_include_directories(SDL2 INTERFACE vendors/SDL2)
And at the end of my CMakeLists :
target_link_libraries(engine INTERFACE SDL2)
But the problem that I have is that I have also other libraries that I build the traditional way (without using the interface keyword) :
find_package(OpenGL REQUIRED)
find_package(glfw3 REQUIRED)
find_package(GLUT REQUIRED)
find_package(GLEW REQUIRED)
set(LIBS_DIR ${OPENGL_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS} ${GLUT_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS})
set(LIBS ${OPENGL_LIBRARIES} ${GLFW_LIBRARIES} ${GLUT_LIBRARIES} ${GLEW_LIBRARIES} SDL2 STB_IMAGE)
target_include_directories(
engine PUBLIC
${LIBS_DIR}
)
target_link_libraries(engine ${LIBS})
Doing that I end up with the following error which I interpret as saying that only a target_link_libraries per project should be used.
The plain signature for target_link_libraries has already been used with the target "engine". All uses of target_link_libraries with a target must be either all-keyword or all-plain.
My question is : how can I link two types of libraries to my project ?
And is my way of building the SDL2 library correct ? I've seen other methods online but this one seemed the simplest one to me
Thanks a lot !
I have also tried to add the SDL2 library to my LIBS value :
set(LIBS ${OPENGL_LIBRARIES} ${GLFW_LIBRARIES} ${GLUT_LIBRARIES} ${GLEW_LIBRARIES} SDL2 STB_IMAGE)
and link it the normal way without using the keyword INTERFACE but I get undefined reference linker errors. In fact the methods that my engine use from the SDL2 libraries seem to be undefined so I guess that the library ha not been lined properly.

Related

Using CMAKE find_package with SDL2

I've got a project that uses CMAKE, and needs to link SDL2. I'm trying to understand how find_package works. At one point in the past, I was able to get find_package to work by supplying my own FindSDL2.cmake, but after some new linker errors, I decided to try a different apporoach. The reading I'm doing seems to imply that, after I've installed the libsdl2-dev package, I should be able to just use find_package(SDL2 REQUIRED) and then target_link_libraries(Suqua PRIVATE SDL2::SDL2), but cmake throws a package not found error. Do I need to provide a custom FindSDL2.cmake?
CMakeLists.txt
cmake_minimum_required (VERSION 3.8)
set(CMAKE_CXX_STANDARD 17)
find_package(SDL2 CONFIG REQUIRED)
file(GLOB source_files
"src/*.cpp"
"header/*.h"
)
add_library(Suqua ${source_files} "src/glad.c" )
target_include_directories(Suqua PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/header)
target_include_directories(Suqua PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../include)
target_link_libraries(Suqua PRIVATE SDL2::SDL2 enet)
if(UNIX)
target_link_libraries(Suqua PRIVATE stdc++fs)
endif()
Error
CMake Error at Suqua/CMakeLists.txt:13 (add_library):
Target "Suqua" links to target "SDL2::SDL2" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
Thank you, and if you have any other critiques of my CMakeLists, they'd be greatly appreciated!
Answer supplied by Tsyvarev
When using an installed library (not built from source), use the SD2_LIBRARIES variable.
On another note, I actually fixed this earlier, but assumed I was doing something wrong when I got a linker error relating to linking CMAKE_DL_LIBS, which I'd removed because I assumed it didn't do anything :/
Definitely gonna read through that CMake book. Thanks all!

How to build static library with bundled dependencies - CMake

I am currently using CMake to create a static library which utilizes a few of the static libraries from OpenCV 4 ( core imgcodecs video highgui imgproc ). My intention is to be able to bundle all of the required OpenCV static libraries into my own library so that I can distribute it as one library. Additionally, I want for the user of my library to not have to install OpenCV 4 on their system (but do not mind if the user has to do simple installs using apt-get install). I know there are tools for bundling static libraries (such as using ar for linux).
However, where I really am having the issue is with all the dependencies of OpenCV (such as libjpeg, libpng, etc). I don't necessarily mind if these libraries are bundled with mine or linked dynamically as they are relatively easy to install (can be installed with sudo apt-get install, whereas opencv4 needs to be built from source).
What is the best way to go about doing this?
This is my current CMakeLists.txt
It is currently working, but that is because I am using find_package(OpenCV REQUIRED) (which defeats the purpose of what I am trying to do). When I remove that line, the linker complains about not being able to find the OpenCV dependencies.
cmake_minimum_required(VERSION 2.8)
project(myproject)
set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
list(APPEND LINKER_LIBS opencv_core opencv_highgui opencv_video opencv_imgcodecs libmxnet.so libncnn.a nlohmann_json::nlohmann_json)
file(GLOB SRC${CMAKE_CURRENT_LIST_DIR}/src/*.cpp${CMAKE_CURRENT_LIST_DIR}/main.cpp)
add_library(myproject ${SRC})
target_link_libraries(myproject ${LINKER_LIBS} ${OpenMP_CXX_FLAGS})
To elaborate on my question. I build my project which generates libmyproject.a. I then take this library and will eventually extract the symbols from the OpenCV libs (libopencv_core.a libopencv_highgui.a libopencv_imgcodecs.a libopencv_video.a) and add them to my lib (for the time being, I have not yet done this step, which is why in the below example I am linking libopencv_*). I then use my library in a new project, for which the CMakeLists.txt is shown below:
cmake_minimum_required(VERSION 2.8)
project(myproject-driver)
set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
find_package(OpenMP REQUIRED)
add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver myproject libncnn.a ${OpenMP_CXX_FLAGS} libmxnet.so libopencv_core.a libopencv_highgui.a libopencv_imgcodecs.a libopencv_video.a)
Building this generates the following errors:
Linking CXX executable myproject-driver
/usr/bin/ld: /home/nchafni/Cyrus/myproject/lib/libopencv_imgcodecs.a(grfmt_jpeg.cpp.o): undefined reference to symbol 'jpeg_default_qtables##LIBJPEG_8.0'
//usr/lib/x86_64-linux-gnu/libjpeg.so.8: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
How can I fix this. Is there some CMake command which will link all these dependencies for me? Do I need to manually track down each dependency of those libopencv_* libs and link those manually? Once again, this is assuming that the person using libmyproject.a can't use find_package(OpenCV REQUIRED) as it won't be defined as they have not installed OpenCV on their machine.
First of all, don't use the super old and outdated version 2.8 of CMake. CMake 3.x is so much more powerful and pretty straightforward to use.
Some tips for modern CMake.
Don't use file(GLOB), see here why that is.
Don't use directory wide instructions, rather use target instructions, e.g. target_include_directories vs. include_directories.
Don't use string variables like ${<PACKAGE_NAME>_LIBRARIES}, rather use targets, e.g. <Package_NAME>::lib
When using targets instead of string variables, all the properties (including LINK_INTERFACE) of that target will be populated to the library/executable when calling target_link_libraries, so no more include_directories,link_directories, etc.
myproject
cmake_minimum_required(VERSION 3.14)
project(myproject)
set(CMAKE_CXX_STANDARD 14)
find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
set(SOURCES ...) # list all the source files here
add_library(myproject ${SOURCES})
target_include_directories(myproject PUBLIC # give it a scope
${CMAKE_CURRENT_LIST_DIR}/include
)
target_link_libraries(myproject PUBLIC # give it a scope
opencv_core # using the target, you will get all LINK_LIBRARIES
opencv_highgui
opencv_video
opencv_imgcodecs
libmxnet.so # where is this coming from?
libncnn.a # where is this coming from?
nlohmann_json::nlohmann_json
OpenMP::OpenMP_CXX ## linking against a target, CXX_FLAGS will be populated automatically
)
myprojec-driver
cmake_minimum_required(VERSION 3.14)
project(myproject-driver)
set(CMAKE_CXX_STANDARD 14)
add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver PUBLIC # give it a scope
myproject # gets all dependencies through the LINK_INTERFACE
)

proper way to write a CMakeLists referencing HDF5 in Windows

I've already downloaded an built HDF5 under Windows using CMake, I also generated an installer to install it under Program Files.
Below the CMakeLists.txt I wrote to be able to use HDF5 in a program I already wrote under Linux :
cmake_minimum_required(VERSION 2.8)
project(Hdf5DataFeed)
add_definitions(-DWINDOWS)
find_package(HDF5)
FIND_LIBRARY(HDF5_HL_LIBRARY hdf5_hl)
FIND_LIBRARY(ZLIB zlib)
find_library(ZMQ_LIB zmq)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
include_directories(${ZMQ_LIB_INCLUDE})
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${ZLIB} "C:/Program Files/HDF_Group/HDF5/1.10.1/lib/libszip.lib" ${VTK_LIBRARIES} ${ZMQ_LIB} ${HDF5_LIBRARIES} ${HDF5_HL_LIBRARY} Qt5::Core Qt5::Gui Qt5::Widgets)
target_include_directories(${PROJECT_NAME} PRIVATE ${HDF5_INCLUDE_DIRS})
As you can see above, to link HDF5 under Visual Studio, I needed Zlib, Szip (that I had to enter an absolute path to it, I don't like that), HDF5 library and the HDF5 High Level (Lite) library.
These libraries are located under C:\Program Files\HDF_Group\HDF5\1.10.1\lib :
libhdf5.lib <============
libhdf5.settings
libhdf5_cpp.lib
libhdf5_hl.lib <=====
libhdf5_hl_cpp.lib
libhdf5_tools.lib
libszip.lib <=== ????
libzlib.lib <====
I use CMake-Gui to inform CMake of the libraries path (except for Szip, I don't know why CMake doesn't know about it, and why I don't have the possibility to just feed CMake the library directory instead of indicating the path of few of them).
I want to use CMake-GUI to inform CMake of Szip library path, but this last doesn't create an entry of it, I only have these entries related to HDF5 :
I'm having troubles with HDF5 also under Ubuntu (see this question : hdf5.h no such file or directory under Ubuntu and CMake).
For now, it's only under CentOS 7 that I didn't encounter any issues with HDF5.
If someone can give me/us a final solution that works both on Windows and Ubuntu that would be great !
Does this solution work for you?
cmake_minimum_required(VERSION 2.8)
project(Hdf5DataFeed)
# necessary?
add_definitions(-DWINDOWS)
find_package(HDF5 REQUIRED COMPONENTS C CXX HL)
find_package(ZLIB REQUIRED)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
find_library(ZMQ_LIB zmq)
include_directories(${ZMQ_LIB_INCLUDE} ${HDF5_INCLUDE_DIR}
${ZLIB_INCLUDE_DIRS})
aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${HDF5_LIBRARIES}
${HDF5_HL_LIBRARIES} ${ZLIB_LIBRARIES} ${VTK_LIBRARIES}
Qt5::Core Qt5::Gui Qt5::Widgets ${ZMQ_LIB})
Recommendation 1: Surely, there is a way to find Qt5 via find_package, i.e.,
find_package(Qt5 COMPONENTS Core Widgets REQUIRED)
and then add the correct variables to include_directories and target_link_libraries. Not sure whether such a possibility exists for the zmq library, though.
Recommendation 2: I think the call the aux_source_directory should be avoided in most cases. Create an explicit list of your source files instead.
For libszip, adding a find_library is better than putting an absolute link to it. For ZLib, it is preferable to use find_library as find_package will require you to feed CMake with an include directory which is not required for HDF5. Finally, it is preferable to use find_package for ZMQ, otherwise, we need to add manually the entry "ZMQ_LIB_INCLUDE".

CMake: undefined reference when linking libraries to KDE4 lib

at the moment I am trying to create a shared library using kde4_add_library. Actually it does not matter if it is add_library or kde4_add_library but it seems that add_library makes no sense since it cannot handle classes with "Q_OBJECT" macros/moc files?! Unfortunately compiling says "undefined reference" for many methods from classes of shared libraries in sub directories which are linked against the kde4 lib target.
The error messages look like:
./wc3lib/src/editor/editor.cpp:71: undefined reference to `wc3lib::editor::BlpCodec::startup()'
For finding the packages I use the following macros:
if (EDITOR)
find_package(Qt4 COMPONENTS QtCore QtGui REQUIRED)
elseif (PLUGINS)
find_package(Qt4 COMPONENTS QtCore QtGui)
endif ()
if (${QT4_FOUND})
include(${QT_USE_FILE})
add_definitions(${QT_DEFINITIONS})
include_directories(${QT_INCLUDE_DIR})
endif ()
if (EDITOR)
find_package(KDE4 REQUIRED)
elseif (PLUGINS)
find_package(KDE4) # only for MPQ plugins
endif ()
if (${KDE4_FOUND})
include(KDE4Defaults)
add_definitions(${KDE4_DEFINITIONS})
include_directories(${KDE4_INCLUDE_DIR} ${KDE4_INCLUDES})
link_directories(${KDE4_LIB_DIR})
endif ()
find_package(OGRE COMPONENTS Paging Terrain REQUIRED)
if (${OGRE_FOUND})
include_directories(${OGRE_INCLUDE_DIRS})
link_directories(${OGRE_LIB_DIR})
endif ()
the sub directories are added after that:
if (BLP AND ${OGRE_FOUND})
add_subdirectory(Plugin_BlpCodec)
endif ()
if (MPQ AND ${KDE4_FOUND})
add_subdirectory(kio_mpq)
endif ()
if (BLP AND ${QT4_FOUND})
add_subdirectory(qblp)
endif ()
they contain targets without any KDE macros:
add_library(Plugin_BlpCodec SHARED ${wc3lib_EDITOR_PLUGIN_BLPCODEC_SRC})
target_link_libraries(Plugin_BlpCodec wc3libblp ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${GETTEXT_LIBRARIES})
now finally in the parent directory the KDE target is created:
kde4_add_library(wc3libeditor SHARED ${wc3lib_EDITOR_SRC} ${wc3lib_EDITOR_UI_H})
target_link_libraries(wc3libeditor ${wc3lib_CORE_LIBRARIES} ${GETTEXT_LIBRARIES} ${Boost_LIBRARIES} ${OGRE_LIBRARIES} ${QT_LIBRARIES} ${KDE4_KIO_LIBS} ${KDE4_KUTILS_LIBS} ${KDE4_KPARTS_LIBS} Plugin_BlpCodec qblp)
the CMake options like "EDITOR" are all enabled.
For the one linked library "qblp" I use some Qt stuff:
add_definitions(${QT_DEFINITIONS})
add_definitions(-DQT_PLUGIN)
add_definitions(-DQT_SHARED)
the other one simply uses "add_library" and has itself also system libs linked against it.
None of these dependencies fails to compile.
The methods are all defined.
I use
cmake_minimum_required(VERSION 2.8.4)
kdelibs-4.11.5
qtcore-4.8.5-r1
this is not the first time I have problems using Qt/KDE via CMake. Any help so far?
edit:
Note that "Target "wc3libeditor" has an INTERFACE_LINK_LIBRARIES property which
differs from its LINK_INTERFACE_LIBRARIES properties." appear for the wc3libeditor target. Is this related to the linking issues?
So the problem seems to be that
find_package(KDE4 REQUIRED)
adds various C++ flags. You can find all this in /usr/share/apps/cmake/modules/FindKDE4Internal.cmake
Some of these flags lead to the undefined reference errors.
A simple workaround might be adding
set(CMAKE_CXX_FLAGS "")
after the find_package statement which is kind of ugly.
More information can be found here:
http://lists.kde.org/?l=kde-buildsystem&m=132906487119016
and there is a better solution using the export macro:
https://forum.kde.org/viewtopic.php?f=64&t=89265
Another solution might be using KDE Frameworks (5) instead.
I've also created a bug report: https://bugs.kde.org/show_bug.cgi?id=338151

How to compile QtGui example with OpenGL/Angle in CMake?

I am trying to take the Qt example from the Qt-distribution in examples/gui/openglwindow/ and make it compile/run with CMake on Windows. However, when compiling, it fails with a bunch of
“error LNK2019: unresolved external symbol __imp_glClear”
I can fix that by manually adding C:\Qt_install\lib\libGLESv2d.lib to the linker path, however, that’s obviously not how CMake should work.
My CMakeLists is very simple:
PROJECT( oglwin )
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12 )
cmake_policy(SET CMP0020 NEW) # for Qt: auto-link to qtmain.lib
set(CMAKE_AUTOMOC ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
SET(SOURCE
main.cpp
openglwindow.cpp
)
SET(HEADERS
openglwindow.h
)
ADD_EXECUTABLE( oglwin ${SOURCE} ${HEADERS} )
TARGET_LINK_LIBRARIES( oglwin Qt5::Core Qt5::Gui )
Now as I mentioned before, my expectation would be that this automatically links to libGLESv2.lib (or libGLESv2d.lib), as I am using a Qt-build built with ANGLE.
(For that matter, I guess when on the desktop/opengl build, it should link to GL.lib [or whatever the system openGL lib is called]).
Possibly in my case, it should also link to C:\Qt_install\lib\libEGLd.lib.
There are a few related topics around, for example this:
https://bugreports.qt-project.org/browse/QTBUG-29132
(where it says “fixed”), and one can follow that to gitorious:
https://codereview.qt-project.org/#change,53857
So basically what should happen is that QtGui automatically links to its correct OpenGL back-end, whatever that may be (desktop OpenGL, Angle/GLESv2), it says in the bugreport there that it's able to deduce which back-end to use from the installed Qt distribution.
Apparently what I’m trying to do should work, but it doesn’t. Am I doing something wrong?
The solution was as follows:
It was coupled with a Qt bug that is now fixed, but it was also necessary to add ${Qt5Gui_EGL_LIBRARIES} and ${Qt5Gui_OPENGL_LIBRARIES} to target_link_libraries.
That makes Qt find the correct OpenGL dependency.