how to get CMake to add MagickWand library linking automatically everywhere - c++

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.

Related

How to have sub_directory use VCPKG in find_package() in CMake?

I'm trying to build PROJ from source. I don't have many of its dynamic dependencies on Centos 7, nor is it possible for me to obtain these dependencies through the system package manager.
In order to skirt these issues, I sought to use VCPKG. However VCPKG is in a lot of turmoil over PROJ and I cannot physically use any version past 7.2.x in VCPKG (I need newer features) and I can't load geo tiffs either (so most non trivial projections will straight up not work). So I can't use VCPKG and PROJ together at all.
However I can still comfortably get the dependencies required to run PROJ through VCPKG.
I tried to convert PROJ source into a subdirectory, however to my suprise it was still trying to use my system libraries despite -DCMAKE_TOOLCHAIN_FILE=... -DVCPKG_TARGET_TRIPLET=x64-linux being set.
I tried using the directory as a standalone library, but with the VCPKG variables set, and... it worked.
So I tried setting cache variables to see if somehow that wasn't propagated downwards, and it didn't work (error message same as below)
set(CMAKE_TOOLCHAIN_FILE "/home/user/Documents/vcpkg/scripts/buildsystems/vcpkg.cmake" CACHE STRING "TEST")
set(VCPKG_TARGET_TRIPLET "x64-linux" CACHE STRING "TEST")
add_subdirectory(external/PROJ)
My project is setup like this:
- CMakeLists.txt
- main.cpp
- external
- PROJ
...
my cmake is like this:
cmake_minimum_required(VERSION 3.13)
project(test)
set(CMAKE_CXX_STANDARD 17)
add_subdirectory(external/PROJ)
add_executable(test main.cpp)
target_link_libraries(test PRIVATE PROJ::proj)
and I keep getting
-- Found Sqlite3: /usr/lib64/libsqlite3.so
-- Sqlite3 version: 3.7.17
CMake Error at external/PROJ/CMakeLists.txt:180 (message):
sqlite3 >= 3.11 required!
when PROJ is a subdirectory
and I get the correct thing:
-- Found Sqlite3: /home/user/Documents/vcpkg/installed/x64-linux/debug/lib/libsqlite3.a
-- Sqlite3 version: 3.36.0
when I don't use it as a sub-directory.
After the first project() call, it is much too late for CMAKE_TOOLCHAIN_FILE to do anything useful. Indeed, it won't even be read if it changes after the first project() call. Vcpkg, Conan, and the like must be used globally or not at all.
You could get away with writing something like this:
cmake_minimum_required(VERSION 3.21) # upgrade!! 3.13 is ancient
# Use vcpkg by default
if (EXISTS "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake")
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
CACHE STRING "TEST")
set(VCPKG_TARGET_TRIPLET "x64-linux"
CACHE STRING "default vcpkg triplet")
endif ()
project(test)
set(CMAKE_CXX_STANDARD 17
CACHE STRING "C++ standard to use")
if (CMAKE_CXX_STANDARD LESS 17)
message(FATAL_ERROR "Must compile `test` with C++17 or newer")
endif ()
add_subdirectory(external/PROJ)
add_executable(test main.cpp)
target_link_libraries(test PRIVATE PROJ::proj)
It is customary to set the environment variable VCPKG_ROOT to point to your vcpkg installation.
After fiddling around with this answer and wondering why it still wasn't working, I tried making an exact copy of the current MCVE in a different directory. To my surprise, it worked, and even worked with out caching (normal CMake command line variables). When using PROJ as a sub_directory, it actually only exposes PROJ as a target. However, I was trying to use PROJ::proj, a target apparently made by VCPKG to link against their install. Well I had uninstalled that, and wasn't using it as a dependency. Despite that, left over files in a separate build folder apparently were messing with my install, my directory originally looked like this:
- CMakeLists.txt
- main.cpp
- external
- PROJ
- cmake-build-debug
- cmake-build-release
Well, VCPKG stores some meta information about package caches and such in these directories. But with out completely deleting the whole directory I was not able to get it to "forget" about this old install. What's more, it took deleting both directories to get it to "fully" forget about proj.
So I deleted these files, like this:
- CMakeLists.txt
- main.cpp
- external
- PROJ
And reset/reloaded the CMake cache and file, and re-generated those build directories.
After doing this, I no longer had to worry about this extra target.

Run-path dependent library cannot locate its dependency during linking stage of a programme build on linux

I have written a tutorial project whilst trying to understand the use of run-path dependent libraries on macOS and Linux. simpleapp depends on libmymaths, which in turn depends on libfastmatrix. libmymaths is a run-path dependent library and you can see the structure of the project here. I am trying to use the OS specific macros (#executable_path for macOS and $ORIGIN for linux) in order to allow the binaries to be easily moved around without breaking, since their location is going to be resolved during run-time and substituted in the macros. However, although what I've programmed so far works nicely on macOS, it doesn't on Linux. Specifically, I'm getting the following error during the linking stage of simpleapp (you can reproduce simply with ./run.sh):
/usr/bin/ld: warning: libfastmatrix.so, needed by /home/thomas/Developer/rpath_tutorial/libmymaths/libmymaths.so, not found (try using -rpath or -rpath-link)
In libmymaths' CMakeLists.txt I specify the rpath where its dependency (libfastmatrix) can be found, and that's verifiable with ldd libmymaths.so once libmymaths is built.
if(APPLE)
set(TOKEN "#loader_path")
elseif(UNIX AND NOT APPLE)
set(TOKEN "$ORIGIN")
endif()
set_target_properties(${PROJECT_NAME} PROPERTIES
CXX_STANDARD 11
CXX_EXTENSIONS FALSE
BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_NAME_DIR "#rpath" # Necessary prior CMP0042 introduction.
INSTALL_RPATH "${TOKEN}/../libfastmatrix"
)
I have implemented the ld's suggestions as Fix 1 and Fix 2 in simpleapp's main CMake script, which allows the project to build.
# # Fix 1, -rpath-link (linux-specific ld option)
# LINK_FLAGS "-Wl,-rpath-link,${CMAKE_CURRENT_SOURCE_DIR}/../libfastmatrix/"
# # Fix 2, additional (unecessary for macOS) rpath, overwrites line 47
# INSTALL_RPATH "${TOKEN}/../libmymaths;${CMAKE_CURRENT_SOURCE_DIR}/../libfastmatrix"
However, this is against what I'm trying to achieve - make each library responsible for its own dependencies and not contaminate other projects with dependencies of dependencies.
1) What changes do I need to make to achieve my goal on Linux as I have done on macOS?
2) In case this is not feasible because the whole approach I am taking is incorrect, can you provide some proof or sources where this is documented?
I'm using:
CMake 3.5.1
ld 2.26.1
gcc 5.4.0
Thanks.
I do this with my game project. Here are the steps I use to make it work.
cmake_minimum_required(VERSION 3.5)
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib/:$$ORIGIN/lib/")
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
install(TARGETS SpeedBlocks DESTINATION ${PROJECT_SOURCE_DIR}/build)
endif()
Note that I'm using a higher CMAKE version, so could be a bit different from what you need to do in 2.8.
After this I need to build the project, then run make install. The built binary will not have the RPATH set properly, but when I run make install (which basically just copies the binary and applies the RPATH from what I can tell) it gets set properly.
You can check if a binary has RPATH set properly by using
objdump -x path_to_binary_or_lib | grep RPATH
should output something like
RPATH $ORIGIN/lib/:$$ORIGIN/lib/:/usr/local/lib

CMake find_package() cannot find include dirs

I am trying to install two projects: Foo and NeedsFoo. I have successfully compiled and locally installed Foo using cmake. However, I'm on a server and cmake doesn't appear to "remember" where Foo is.
In the cmake to configure NeedsFoo I have
list(APPEND CMAKE_MODULE_PATH "<prefix>/foo-install/CMake/FOO") # add path to FOOConfig.cmake
find_package(FOO REQUIRED)
if( FOO_FOUND )
MESSAGE(STATUS "Found FOO!")
endif( FOO_FOUND )
MESSAGE(STATUS ${FOO_INCLUDE_DIRS})
"Found Foo!" is printed --- so cmake finds FOO --- but the variable ${FOO_INCLUDE_DIRS} is empty and, therefore, the package does not compile. Any thoughts?
EDIT: There seems to be another copy of Foo installed on the server. Unfortunately, I can't use it (it is the 'master' branch of our project and I need to use my own branch). I tried changing the find_package call to
find_package(FOO REQUIRED PATHS "<prefix>/foo-install/CMake/Foo" NO_DEFAULT_PATH)
but that did not solve the problem.
Make sure the headers are installed, often you'll need to install a -dev or -devel package to get the headers. If they are installed and you can see them in your system, they might be on a path that cmake isn't expecting. Open the findFoo.cmake file (on Linux this will generally be in /usr/share/c make-x.y/modules) and check the list of expected locations, see if you're have installed in a less conventional one.

Building Open Source library Teem with Levmar support using CMake

I try to build the library Teem under Windows 64bit with levmar support using cmakeGUI with generator VisualStudio10 Win64.
First off all, i built Levmar with CLAPACK and F2C. That works fine as levmar can be compiled without errors and the demo succeds.
The mysterious thing is, when i try to build teem with levmar support ON, cmake always turns it off "because it was not found" although i told cmake the path to levmar.lib.
Thats what the CmakeGUI tells me:
"warning: Turning off Teem_LEVMAR, because it wasn't found.
Configuring done"
Here is a part of my CMakeList.txt delivered with teem:
# Look for "levmar" library <http://www.ics.forth.gr/~lourakis/levmar/>
option(Teem_LEVMAR "Build Teem with levmar library support." OFF)
set(Teem_LEVMAR_LIB "")
if(Teem_LEVMAR)
find_package(LEVMAR)
if(LEVMAR_FOUND)
add_definitions(-DTEEM_LEVMAR)
set(Teem_LEVMAR_LIB ${LEVMAR_LIBRARIES})
set(Teem_LEVMAR_IPATH ${LEVMAR_INCLUDE_DIR})
else()
# We need to set this as a cache variable, so that it will show up as
# being turned off in the cache.
message("warning: Turning off Teem_LEVMAR, because it wasn't found.")
set(Teem_LEVMAR OFF CACHE BOOL "Build Teem with levmar library support." FORCE)
endif()
endif()
Has anyone an idea what happens here?
I tried the same thing with 3 different levmar.lib and different generators but unfortunately i suggest that i have to tell cmake the exact name of the library or the name levmar.lib is simply wrong.
I reported that question also to my supervisor for my thesis but he had the same problem and could not help me.
I also tried to modify the CMakeList:
#if(Teem_LEVMAR)
include_directories(${LEVMAR}/lib)
#endif()
which was originally
if(Teem_LEVMAR)
include_directories(${Teem_LEVMAR_IPATH})
endif()
but it did not help.
Why does cmake recognizes levmar.lib not as the levmar library, in fact does not accept it.
i also tried to understand why find_package(levmar) does not succeed but now i do not know any ways to make it work.
greetings,
jan luca.

OpenCV linking problems with ROS

I'm trying to compile this project (following the instructions given). When building it with rosmake, I get a bunch of undefined reference to cv::String::deallocate() and undefined reference to cv::String::allocate(unsigned long). I find curious that I'm getting an error just in those functions while the rest of the OpenCV functions seem to be working properly.
I know this happens because the linker can't find the objects where these functions were compiled to, but I'm kind of new to the ROS build system and can't find what's wrong.
I've tried using the CMakeLists.txt file provided, and also adding find_package(OpenCV REQUIRED) and target_link_libraries(xxx xxx ${OpenCV_LIBRARIES}), without that making any difference. I know OpenCV is installed and compiled properly (I've used it before), and I had installed ROS without any problems.
I'm using OpenCV 3, ROS Indigo, Ubuntu 14.04
I had this exact same problem - same error messages, same setup. I've managed to solve it, though I'm not exactly sure of the steps I did which actually contributed. As far as I can tell, it was due to a conflict of OpenCV versions - I think I had old versions of OpenCV cluttering my /usr/include and /usr/local. I uninstalled all OpenCV packages (including the ROS ones) and including my from-source install of OpenCV3 (also in /usr/local). Then I installed the ROS package vision_opencv, which seemed to install OpenCV 2.4.8 (incidentally the one recommended by LSD SLAM). Of course, this could be annoying if you need OpenCV3 for other things, but I now have that as a local install in my home directory (I couldn't figure out how to get ROS to link to this).
I think this solved the problem, the only issue remaining was that I got error messages saying was not found. This was because the package install leaves it in (similar for all module include files), whereas the make install step of the from-source install copies them into the parent folder. To get around this I simply edited the #include in the only file in which it is used (lsd_slam_core/src/IOWrapper/OpenCV/ImageDisplay_OpenCV.cpp). That seemed to solve it!
I hope this helps, I can give further details if needed.
I am using OpenCV 3.1.0(Bleeding edge), ROS Indigo, Ubuntu 14.04.
I ran in to similar trouble when trying to compile LSD-SLAM
I added:
find_package(OpenCV 3.1.0 REQUIRED COMPONENTS core highgui imgproc imgcodecs)
I also added opencv libs to target link libs:
target_link_libraries(lsdslam ${FABMAP_LIB} g2o_core g2o_stuff csparse cxsparse g2o_solver_csparse g2o_csparse_extension g2o_types_sim3 g2o_types_sba X11 opencv_core opencv_imgproc opencv_highgui opencv_imgcodecs)
Here is my CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8.12)
project(lsd_slam_core)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
find_package(OpenCV 3.1.0 REQUIRED COMPONENTS core highgui imgproc imgcodecs)
# Set the build type. Options are:
# Coverage : w/ debug symbols, w/o optimization, w/ code-coverage
# Debug : w/ debug symbols, w/o optimization
# Release : w/o debug symbols, w/ optimization
# RelWithDebInfo : w/ debug symbols, w/ optimization
# MinSizeRel : w/o debug symbols, w/ optimization, stripped binaries
set(ROS_BUILD_TYPE Release)
rosbuild_init()
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
find_package(Eigen3 REQUIRED)
find_package(SuiteParse REQUIRED) # Apparently needed by g2o
find_package(X11 REQUIRED)
# FabMap
# uncomment this part to enable fabmap
#add_subdirectory(${PROJECT_SOURCE_DIR}/thirdparty/openFabMap)
#include_directories(${PROJECT_SOURCE_DIR}/thirdparty/openFabMap/include)
#add_definitions("-DHAVE_FABMAP")
#set(FABMAP_LIB openFABMAP )
# Dynamic Reconfigure Services
rosbuild_find_ros_package(dynamic_reconfigure)
include(${dynamic_reconfigure_PACKAGE_PATH}/cmake/cfgbuild.cmake)
gencfg()
# SSE flags
rosbuild_check_for_sse()
add_definitions("-DUSE_ROS")
add_definitions("-DENABLE_SSE")
# Also add some useful compiler flag
set(CMAKE_CXX_FLAGS
"${CMAKE_CXX_FLAGS} ${SSE_FLAGS} -march=native -std=c++0x"
)
# Set source files
set(lsd_SOURCE_FILES
${PROJECT_SOURCE_DIR}/src/DataStructures/Frame.cpp
${PROJECT_SOURCE_DIR}/src/DataStructures/FramePoseStruct.cpp
${PROJECT_SOURCE_DIR}/src/DataStructures/FrameMemory.cpp
${PROJECT_SOURCE_DIR}/src/SlamSystem.cpp
${PROJECT_SOURCE_DIR}/src/LiveSLAMWrapper.cpp
${PROJECT_SOURCE_DIR}/src/DepthEstimation/DepthMap.cpp
${PROJECT_SOURCE_DIR}/src/DepthEstimation/DepthMapPixelHypothesis.cpp
${PROJECT_SOURCE_DIR}/src/util/globalFuncs.cpp
${PROJECT_SOURCE_DIR}/src/util/SophusUtil.cpp
${PROJECT_SOURCE_DIR}/src/util/settings.cpp
${PROJECT_SOURCE_DIR}/src/util/Undistorter.cpp
${PROJECT_SOURCE_DIR}/src/Tracking/Sim3Tracker.cpp
${PROJECT_SOURCE_DIR}/src/Tracking/Relocalizer.cpp
${PROJECT_SOURCE_DIR}/src/Tracking/SE3Tracker.cpp
${PROJECT_SOURCE_DIR}/src/Tracking/TrackingReference.cpp
${PROJECT_SOURCE_DIR}/src/IOWrapper/Timestamp.cpp
${PROJECT_SOURCE_DIR}/src/GlobalMapping/FabMap.cpp
${PROJECT_SOURCE_DIR}/src/GlobalMapping/KeyFrameGraph.cpp
${PROJECT_SOURCE_DIR}/src/GlobalMapping/g2oTypeSim3Sophus.cpp
${PROJECT_SOURCE_DIR}/src/GlobalMapping/TrackableKeyFrameSearch.cpp
)
set(SOURCE_FILES
${lsd_SOURCE_FILES}
${PROJECT_SOURCE_DIR}/src/IOWrapper/ROS/ROSImageStreamThread.cpp
${PROJECT_SOURCE_DIR}/src/IOWrapper/ROS/ROSOutput3DWrapper.cpp
${PROJECT_SOURCE_DIR}/src/IOWrapper/OpenCV/ImageDisplay_OpenCV.cpp
)
include_directories(
${EIGEN3_INCLUDE_DIR}
${PROJECT_SOURCE_DIR}/src
${PROJECT_SOURCE_DIR}/thirdparty/Sophus
${CSPARSE_INCLUDE_DIR} #Has been set by SuiteParse
${CHOLMOD_INCLUDE_DIR} #Has been set by SuiteParse
)
# build shared library.
rosbuild_add_library(lsdslam SHARED ${SOURCE_FILES})
target_link_libraries(lsdslam ${FABMAP_LIB} g2o_core g2o_stuff csparse cxsparse g2o_solver_csparse g2o_csparse_extension g2o_types_sim3 g2o_types_sba X11 opencv_core opencv_imgproc opencv_highgui opencv_imgcodecs)
rosbuild_link_boost(lsdslam thread)
# build live ros node
rosbuild_add_executable(live_slam src/main_live_odometry.cpp)
target_link_libraries(live_slam lsdslam)
# build image node
rosbuild_add_executable(dataset_slam src/main_on_images.cpp)
target_link_libraries(dataset_slam lsdslam)
Do you have multi-versions Opencv? if you have, maybe you should add the path to OpenCVConfig.cmake into CmakeList.txt. Just under the cmake_minimum_required(VERSION 2.8.12),like so:
set(OpenCV_DIR "/home/ubuntu/src/opencv-3.1.0/build")
That's all.
I also had the samme issue. Could not comment Osian's solution due to lack of rep, but this is the procedure I used:
sudo apt-get remove libopencv*
If you for some reason have OpenCV installed from source, enter your build directory and do:
sudo make uninstall
Then finally
sudo apt-get install ros-indigo-desktop-full