How to know library variable names for CMakeLists? - c++

When using CMakeLists to compile an OpenGL project, I have the following line to link glut and gl:
target_link_libraries(my_exe ${OPENGL_gl_LIBRARY} ${GLUT_LIBRARIES})
I looked up how to link glut and gl with CMake so I saw that I could use ${OPENGL_gl_LIBRARY} and ${GLUT_LIBRARIES}. But how would I know the variables to use otherwise? I am used to just doing ${THELIBRARY_LIBRARES}, but in the case of gl, it changed to adding that "gl" into the variable name. How would I know that without googling it (for any library I want to use)?

Besides consulting the find module's documentation, you could also use CMake's VARIABLES property to give you the variables that were defined by your find_package() call.
For an example the following code:
cmake_minimum_required(VERSION 3.2)
project(FindPackageVars)
get_directory_property(_vars_before VARIABLES)
find_package(OpenGL)
get_directory_property(_vars VARIABLES)
list(REMOVE_ITEM _vars _vars_before ${_vars_before})
foreach(_var IN LISTS _vars)
message(STATUS "${_var} = ${${_var}}")
endforeach()
Outputs on my machine:
-- Found OpenGL: /usr/lib/x86_64-linux-gnu/libGL.so
-- FIND_PACKAGE_MESSAGE_DETAILS_OpenGL = [/usr/lib/x86_64-linux-gnu/libGL.so][/usr/include][v()]
-- OPENGL_FOUND = TRUE
-- OPENGL_GLU_FOUND = YES
-- OPENGL_INCLUDE_DIR = /usr/include
-- OPENGL_INCLUDE_PATH = /usr/include
-- OPENGL_LIBRARIES = /usr/lib/x86_64-linux-gnu/libGLU.so;/usr/lib/x86_64-linux-gnu/libGL.so
-- OPENGL_LIBRARY = /usr/lib/x86_64-linux-gnu/libGLU.so;/usr/lib/x86_64-linux-gnu/libGL.so
-- OPENGL_XMESA_FOUND = NO
-- OPENGL_gl_LIBRARY = /usr/lib/x86_64-linux-gnu/libGL.so
-- OPENGL_glu_LIBRARY = /usr/lib/x86_64-linux-gnu/libGLU.so
-- OPENGL_xmesa_INCLUDE_DIR = OPENGL_xmesa_INCLUDE_DIR-NOTFOUND

Those variables are obtained via find_package(XXX) calls.
Such calls are redirected, depended from the library, either to FindXXX.cmake script (shipped with CMake or contained in the project which uses it) or to XXXConfig.cmake script (shipped with the library itself).
So, for determine meaningful variable's names you need to consult appropriate script. Usually, interface of the script (input-output variables) is described in comments at the beginning of the script.
Documentation for FindXXX.cmake scripts shipped with CMake may be read in CMake documentation pages about modules.

You don't. It is dependent on the find-module for the library.
See here.
Under Writing find modules you see that variables are set in the module. When checking the FindOpenGL.cmake module in your CMake-Modules directory you will see the name of the variable.

Related

printing package details after using find_package [duplicate]

When using CMakeLists to compile an OpenGL project, I have the following line to link glut and gl:
target_link_libraries(my_exe ${OPENGL_gl_LIBRARY} ${GLUT_LIBRARIES})
I looked up how to link glut and gl with CMake so I saw that I could use ${OPENGL_gl_LIBRARY} and ${GLUT_LIBRARIES}. But how would I know the variables to use otherwise? I am used to just doing ${THELIBRARY_LIBRARES}, but in the case of gl, it changed to adding that "gl" into the variable name. How would I know that without googling it (for any library I want to use)?
Besides consulting the find module's documentation, you could also use CMake's VARIABLES property to give you the variables that were defined by your find_package() call.
For an example the following code:
cmake_minimum_required(VERSION 3.2)
project(FindPackageVars)
get_directory_property(_vars_before VARIABLES)
find_package(OpenGL)
get_directory_property(_vars VARIABLES)
list(REMOVE_ITEM _vars _vars_before ${_vars_before})
foreach(_var IN LISTS _vars)
message(STATUS "${_var} = ${${_var}}")
endforeach()
Outputs on my machine:
-- Found OpenGL: /usr/lib/x86_64-linux-gnu/libGL.so
-- FIND_PACKAGE_MESSAGE_DETAILS_OpenGL = [/usr/lib/x86_64-linux-gnu/libGL.so][/usr/include][v()]
-- OPENGL_FOUND = TRUE
-- OPENGL_GLU_FOUND = YES
-- OPENGL_INCLUDE_DIR = /usr/include
-- OPENGL_INCLUDE_PATH = /usr/include
-- OPENGL_LIBRARIES = /usr/lib/x86_64-linux-gnu/libGLU.so;/usr/lib/x86_64-linux-gnu/libGL.so
-- OPENGL_LIBRARY = /usr/lib/x86_64-linux-gnu/libGLU.so;/usr/lib/x86_64-linux-gnu/libGL.so
-- OPENGL_XMESA_FOUND = NO
-- OPENGL_gl_LIBRARY = /usr/lib/x86_64-linux-gnu/libGL.so
-- OPENGL_glu_LIBRARY = /usr/lib/x86_64-linux-gnu/libGLU.so
-- OPENGL_xmesa_INCLUDE_DIR = OPENGL_xmesa_INCLUDE_DIR-NOTFOUND
Those variables are obtained via find_package(XXX) calls.
Such calls are redirected, depended from the library, either to FindXXX.cmake script (shipped with CMake or contained in the project which uses it) or to XXXConfig.cmake script (shipped with the library itself).
So, for determine meaningful variable's names you need to consult appropriate script. Usually, interface of the script (input-output variables) is described in comments at the beginning of the script.
Documentation for FindXXX.cmake scripts shipped with CMake may be read in CMake documentation pages about modules.
You don't. It is dependent on the find-module for the library.
See here.
Under Writing find modules you see that variables are set in the module. When checking the FindOpenGL.cmake module in your CMake-Modules directory you will see the name of the variable.

how to get CMake to add MagickWand library linking automatically everywhere

I want to use CMake in my software that uses MagickWand.
CMake works on my machine and generates a useful Makefile.
On another machine, I have to manually add
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -lMagickWand-6.Q16 -lMagickCore-6.Q16")
otherwise the linker can't find MagickWandGenesis() and other functions.
I found that -l flags via pkg-config --cflags --libs MagickWand.
Shouldn't CMake already generate linker flags for me with TARGET_LINK_LIBRARIES?
Did I miss something obvious, or why is this not working everywhere?
I have this code in CMakeLists.txt:
FIND_PACKAGE(ImageMagick
REQUIRED
COMPONENTS MagickWand
)
[...]
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16")
[...]
INCLUDE_DIRECTORIES(
${Boost_INCLUDE_DIR}
${ImageMagick_INCLUDE_DIRS}
${ImageMagick_MagickWand_INCLUDE_DIRS}
)
[...]
TARGET_LINK_LIBRARIES(application_name
[...]
${Boost_LIBRARIES}
${CURL_LIBRARIES}
${ImageMagick_LIBRARIES}
${ImageMagick_MagickWand_LIBRARY}
)
That last ${ImageMagick_MagickWand_LIBRARY} shouldn't even be necessary.
Using Magick 6.8.9.9, CMake 3.0.2 on both machines (Debian Jessie).
Short answer: the package ImageMagick is buggy.
Looking in CMake's sources, the REQUIRED mechanism is handled exclusively through the variable package-_FOUND, independently of the required components.
Looking in the package ImageMagick here, ImageMagick_FOUND is set as follows:
set(ImageMagick_FOUND ${IMAGEMAGICK_FOUND})
But IMAGEMAGICK_FOUND is not set anywhere in the package, so the call will always unset ImageMagick_FOUND, and it will always be evaluated to true (not actively set to false), wether or not the components are effectively found.
You can either debug the package (and propose a pull request) or check the component variable:
if(NOT ImageMagick_MagickWand_FOUND)
message(FATAL_ERROR "MagickWand not found")
endif()
I guess the test will fail on your second machine.
By the way, you should only use ImageMagick_INCLUDE_DIRS and ImageMagick_LIBRARIES to link to the library (the ImageMagick_MagickWand* variables are here redundant). If you choose to debug the package, you may also declare imported targets.
Figured it out, despite the output of
MESSAGE(${ImageMagick_FOUND})
MESSAGE(${ImageMagick_INCLUDE_DIRS})
MESSAGE(${ImageMagick_LIBRARIES})
MESSAGE(${ImageMagick_MagickWand_FOUND})
MESSAGE(${ImageMagick_MagickWand_INCLUDE_DIRS})
MESSAGE(${ImageMagick_MagickWand_LIBRARY})
being identical, the installed packages differed. I installed the magick-dev packages via virtual packages in aptitude, which for some reason used the graphicsmagick suite for some packages (a imagemagick fork) instead of the original imagemagick suite.
For reference, the used aptitude search one-liner was aptitude search 'magick ?installed' | sort which listed three graphicsmagick packages on the second machine where imagemagick packages were on the first machine.

How to let cmake use another opencv directory other than the system's in ubuntu?

Specifically, I want to include opencv from my/path/to/opencv/release where my own opencv is built other than the system's opencv lib in /usr/local/include. How can I set cmake to achieve this? I'm using Ubuntu 14.04.
To provide an example, below is a Find-CMake file for the Luajit library. Your CMake project has one that's probably called something like "FindOpenCV.cmake". It most likely has a default installation path that was manually added, such as: "/usr/include/luajit-2.0 /usr/local/include/luajit-2.0" and you would change these DIR's to your desired install directory. If the default path is contained in a variable, you could either find the definition of that variable and change it (preferably through a configuration option), or override it with a string.
# Try to find Lua or LuaJIT depending on the variable ENABLE_LUAJIT.
# Sets the following variables:
# LUA_FOUND
# LUA_INCLUDE_DIR
# LUA_LIBRARY
#
SET (LUA_FOUND FALSE)
SET (LUA_INTERPRETER_TYPE "")
SET (LUA_INTERPRETER_TYPE "LuaJIT")
SET (LUA_LIBRARY_NAME luajit-5.1)
SET (LUA_INCLUDE_DIRS /usr/include/luajit-2.0 /usr/local/include/luajit-2.0)
FIND_PATH (LUA_INCLUDE_DIR lua.h ${LUA_INCLUDE_DIRS}
HINT ${LUAJIT_INCLUDE_DIR_HINT}/include)
FIND_LIBRARY (LUA_LIBRARY NAMES ${LUA_LIBRARY_NAME} PATHS /usr/lib /usr/local/lib
HINT ${LUAJIT_INCLUDE_DIR_HINT}/bin)
#...
MARK_AS_ADVANCED ( LUA_INCLUDE_DIR LUA_LIBRARY)
There are multiple ways to achieve this, you can modify a FindOpenCV.cmake file, you set the cmake variable OpenCV_DIR before the library is found https://stackoverflow.com/a/9835300/2079934, you can export the environment variable OpenCV_DIR before you run CMake https://stackoverflow.com/a/16959771/2079934.
I would recommend not to hard-code any library paths into CMakeLists.txt, that would take away all the benefits of CMake. In Linux, I would use export to set OpenCV_DIR, in other OSes CMake GUI is more common there you could edit the path variable in the GUI.

cmake: target_link_libraries use static library not shared

Is it possible to tell cmake to link against a static library instead of shared?
At the top of my CMakeLists.txt I have the following configured:
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
Later, I add a binary, and tell it to link against tcmalloc in release mode:
target_link_libraries(${BIN_NAME} optimized tcmalloc_minimal)
The resulting makefile links aginst the shared version of tcmalloc:
$ make VERBOSE=1 | grep tcmalloc
/usr/bin/c++ ... -Wl,-Bdynamic ltcmalloc_minimal
Further proof:
$ ldd app
...
libtcmalloc_minimal.so.4 => /usr/local/lib/libtcmalloc_minimal.so.4 (0x00007eff89733000)
...
Both static and shared versions of tcmalloc exist:
$ ls -1 /usr/local/lib/libtcmalloc_minimal*
/usr/local/lib/libtcmalloc_minimal.a
/usr/local/lib/libtcmalloc_minimal_debug.a
/usr/local/lib/libtcmalloc_minimal_debug.la
/usr/local/lib/libtcmalloc_minimal_debug.so
/usr/local/lib/libtcmalloc_minimal_debug.so.4
/usr/local/lib/libtcmalloc_minimal_debug.so.4.2.6
/usr/local/lib/libtcmalloc_minimal.la
/usr/local/lib/libtcmalloc_minimal.so
/usr/local/lib/libtcmalloc_minimal.so.4
/usr/local/lib/libtcmalloc_minimal.so.4.2.6
Question:
How can I configure cmake to link against the static version of tcmalloc?
You can create a helper function which sets CMAKE_FIND_LIBRARY_SUFFIXES at function scope (so therefore doesn't affect the parent scope) which searches for the library in question and sets an output variable with the result
function(find_static_library LIB_NAME OUT)
if (WIN32 OR MSVC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
elseif (UNIX)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
endif()
find_library(
FOUND_${LIB_NAME}_STATIC
${LIB_NAME}
)
if (FOUND_${LIB_NAME}_STATIC)
get_filename_component(ABS_FILE ${FOUND_${LIB_NAME}_STATIC} ABSOLUTE)
else()
message(SEND_ERROR "Unable to find library ${LIB_NAME}")
endif()
set(${OUT} ${ABS_FILE} PARENT_SCOPE)
endfunction()
You can then call this function from somewhere in your CMakeLists.txt to populate a variable with the location of the library.
Failure to find it results in a hard failure
find_static_library(tcmalloc_minimal TCMALLOC)
You can then use this variable in your call to target_link_libraries and be sure you're linking against the static version
target_link_libraries(${BIN_NAME} optimized ${TCMALLOC})
Here you can see the result:
$ make VERBOSE=1 | grep tcmalloc
/usr/bin/c++ ... /usr/local/lib/libtcmalloc_minimal.a ...
If you only need to support non-Windows platforms, then this old email from the CMake mailing list from one of the Kitware developers gives the simplest method. In essence, use find_library() to find the location of the actual library, favouring static libraries over shared ones by listing them first in the names to look for. i.e.
find_library(TCMALLOC_LIB NAMES libtcmalloc_minimal.a tcmalloc_minimal)
You would then link to the library found in the usual way:
target_link_libraries(${BIN_NAME} ${TCMALLOC_LIB})
You could get smarter about how you define the static library name if you need to support platforms where a static library is named something other than lib???.a. You would use CMAKE_STATIC_LIBRARY_PREFIX and CMAKE_STATIC_LIBRARY_SUFFIX variables for that.
On Windows, the problem is that you cannot distinguish between a static library and the import library for a DLL, as discussed in this old issue in the Kitware bug tracker. Both have the file extension .lib, so you can't use the extension to work out if a particular file is a static library or not, unlike Unix-based platforms where you can.
You have to set your CMAKE_FIND_LIBRARY_SUFFIXES variable in this manner:
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
because in default CMAKE_FIND_LIBRARY_SUFFIXES there is also .so suffix (and it seems not searching in order of insertion). In order to allow portability other suffixes should be added (see here for default values of CMAKE_FIND_LIBRARY_SUFFIXES on different platforms).

Using CMAKE how can I use CHECK_LIBRARY_EXISTS to check a C++ library?

I'm trying to use the cmake's function:
CHECK_LIBRARY_EXISTS(library function location variable)
How can I check if the C++ library are available ?
CHECK_LIBRARY_EXISTS(yaml-cpp "YAML::Token" ${YAML-CPP_PATHS} HAVE_YAML-CPP)
IF(HAVE_YAML-CPP)
MESSAGE(STATUS "YAML-CPP libraries founded: OK")
ENDIF(HAVE_YAML-CPP)
IF(NOT HAVE_YAML-CPP)
MESSAGE(FATAL_ERROR "ERROR: unable to link YAML::Token")
ENDIF(NOT HAVE_YAML-CPP)
That code snip don't work.
The CheckLibraryExists module only works for C symbols, not C++. Personally I would just use find_library and find_path to find the library and include path. If the library doesn't contain the right symbols, the user is going to notice soon enough during the linking...
Since yaml-cpp installs a pkg-config file, you can also use the FindPkgConfig module. However, since yaml-cpp itself is built using CMake, you should encourage them to actually install a yaml-cpp-config.cmake file. See e.g. this tutorial for more information.