How to link libraries in cmakelists.txt - cmake

I am mainly using ROS which is cmake based, where I want to link a library that I compiled previously and copied the .so and .a file to /usr/lib and .h to /usr/include.
When I compile it with gcc, there is no problem with: gcc -o test test.c -lpynq -lcma -lpthread. How can I link those libraries in the cmakelist.txt?
Thank you for the help.
EDIT: Following JohnFilleau and the answer from ChrisZZ, this is my CMakeLists.txt:
cmake_minimum_required(VERSION 3.0.2)
project(proof_of_concept_string_ips)
## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)
## Find catkin macros and libraries
## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz)
## is used, also find other catkin packages
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
## System dependencies are found with CMake's conventions
# find_package(Boost REQUIRED COMPONENTS system)
## Uncomment this if the package has a setup.py. This macro ensures
## modules and global scripts declared therein get installed
## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html
# catkin_python_setup()
################################################
## Declare ROS messages, services and actions ##
################################################
## To declare and build messages, services or actions from within this
## package, follow these steps:
## * Let MSG_DEP_SET be the set of packages whose message types you use in
## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...).
## * In the file package.xml:
## * add a build_depend tag for "message_generation"
## * add a build_depend and a exec_depend tag for each package in MSG_DEP_SET
## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
## but can be declared for certainty nonetheless:
## * add a exec_depend tag for "message_runtime"
## * In this file (CMakeLists.txt):
## * add "message_generation" and every package in MSG_DEP_SET to
## find_package(catkin REQUIRED COMPONENTS ...)
## * add "message_runtime" and every package in MSG_DEP_SET to
## catkin_package(CATKIN_DEPENDS ...)
## * uncomment the add_*_files sections below as needed
## and list every .msg/.srv/.action file to be processed
## * uncomment the generate_messages entry below
## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...)
## Generate messages in the 'msg' folder
# add_message_files(
# FILES
# Message1.msg
# Message2.msg
# )
## Generate services in the 'srv' folder
# add_service_files(
# FILES
# Service1.srv
# Service2.srv
# )
## Generate actions in the 'action' folder
# add_action_files(
# FILES
# Action1.action
# Action2.action
# )
## Generate added messages and services with any dependencies listed here
# generate_messages(
# DEPENDENCIES
# std_msgs
# )
################################################
## Declare ROS dynamic reconfigure parameters ##
################################################
## To declare and build dynamic reconfigure parameters within this
## package, follow these steps:
## * In the file package.xml:
## * add a build_depend and a exec_depend tag for "dynamic_reconfigure"
## * In this file (CMakeLists.txt):
## * add "dynamic_reconfigure" to
## find_package(catkin REQUIRED COMPONENTS ...)
## * uncomment the "generate_dynamic_reconfigure_options" section below
## and list every .cfg file to be processed
## Generate dynamic reconfigure parameters in the 'cfg' folder
# generate_dynamic_reconfigure_options(
# cfg/DynReconf1.cfg
# cfg/DynReconf2.cfg
# )
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if your package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES proof_of_concept_string_ips
# CATKIN_DEPENDS roscpp std_msgs
# DEPENDS system_lib
)
###########
## Build ##
###########
## Specify additional locations of header files
## Your package locations should be listed before other locations
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
## Declare a C++ library
# add_library(${PROJECT_NAME}
# src/${PROJECT_NAME}/proof_of_concept_string_ips.cpp
# )
## Add cmake target dependencies of the library
## as an example, code may need to be generated before libraries
## either from message generation or dynamic reconfigure
# add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Declare a C++ executable
## With catkin_make all packages are built within a single CMake context
## The recommended prefix ensures that target names across packages don't collide
# add_executable(${PROJECT_NAME}_node src/proof_of_concept_string_ips_node.cpp)
## Rename C++ executable without prefix
## The above recommended prefix causes long target names, the following renames the
## target back to the shorter version for ease of user use
## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someones_pkg_node"
# set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "")
## Add cmake target dependencies of the executable
## same as for the library above
# add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
## Specify libraries to link a library or executable target against
# target_link_libraries(${PROJECT_NAME}_node
# ${catkin_LIBRARIES}
# )
#############
## Install ##
#############
# all install targets should use catkin DESTINATION variables
# See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html
## Mark executable scripts (Python etc.) for installation
## in contrast to setup.py, you can choose the destination
# catkin_install_python(PROGRAMS
# scripts/my_python_script
# DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark executables for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_executables.html
# install(TARGETS ${PROJECT_NAME}_node
# RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
# )
## Mark libraries for installation
## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/building_libraries.html
# install(TARGETS ${PROJECT_NAME}
# ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
# RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION}
# )
## Mark cpp header files for installation
# install(DIRECTORY include/${PROJECT_NAME}/
# DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
# FILES_MATCHING PATTERN "*.h"
# PATTERN ".svn" EXCLUDE
# )
## Mark other files for installation (e.g. launch and bag files, etc.)
# install(FILES
# # myfile1
# # myfile2
# DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}
# )
#############
## Testing ##
#############
## Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/test_proof_of_concept_string_ips.cpp)
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME})
# endif()
## Add folders to be run by python nosetests
# catkin_add_nosetests(test)
add_executable(pc_pub_string src/pc_pub_string.cpp)
target_link_libraries(pc_pub_string ${catkin_LIBRARIES})
#add_dependencies(pc_pub_string0 proof_of_concept_string_ips_generate_messages_cpp)
add_executable(arm_to_fpga src/arm_to_fpga.cpp)
target_link_libraries(arm_to_fpga ${catkin_LIBRARIES})
# target_link_libraries(arm_to_fpga ${catkin_LIBRARIES}) /usr/lib/libpynq.so)
#add_dependencies(arm_to_fpga proof_of_concept_generate_messages_cpp)
# add_executable(pynq_test_api src/pynq_test_api.cpp)
# target_link_libraries(pynq_test_api ${catkin_LIBRARIES})
set(pynq_lib "/usr/lib/libpynq.so")
set(cma_lib "/usr/lib/libcma.so")
add_executable(pynq_test_api src/pynq_test_api.cpp)
target_link_libraries(pynq_test_api PUBLIC
${catkin_LIBRARIES}
${pynq_lib}
${cma_lib}
pthread
)
target_include_directories(pynq_test_api PUBLIC
"/usr/include"
)
And the error:
CMakeFiles/pynq_test_api.dir/src/pynq_test_api.cpp.o: In function `main':
pynq_test_api.cpp:(.text+0xba): undefined reference to `PYNQ_allocatedSharedMemory(shared_memory_state_struct*, unsigned int, int)'
pynq_test_api.cpp:(.text+0xc8): undefined reference to `PYNQ_allocatedSharedMemory(shared_memory_state_struct*, unsigned int, int)'
collect2: error: ld returned 1 exit status
proof_of_concept_string_ips/CMakeFiles/pynq_test_api.dir/build.make:114: recipe for target '/home/xilinx/fpga_ros_scheduler/catkin_ws/devel/lib/proof_of_concept_string_ips/pynq_test_api' failed
make[2]: *** [/home/xilinx/fpga_ros_scheduler/catkin_ws/devel/lib/proof_of_concept_string_ips/pynq_test_api] Error 1
CMakeFiles/Makefile2:449: recipe for target 'proof_of_concept_string_ips/CMakeFiles/pynq_test_api.dir/all' failed
make[1]: *** [proof_of_concept_string_ips/CMakeFiles/pynq_test_api.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....

The quick-but-not-elegant solution:
cmake_minimum_required(VERSION 3.20) # I like newer version
project(my_project)
set(pynq_lib "/usr/lib/libpynq.a") # the full path. if postfix is `.so`, change it
set(cma_lib "/usr/lib/libcma.a") # the full path. change if needed.
add_executable(test_app test.c)
target_link_libraries(test_app PUBLIC
${pynq_lib}
${cma_lib}
pthread
)
target_include_directories(test_app PUBLIC
"/usr/include"
)
The elegant way: as JohnFilleau suggested, suppose we generate pynq and cma libraries via CMake, then we treat them as "packages", and we "find package and link package", with commands like find_package() for external installed packages, or just use target_link_libraries() if build from same CMake based project.

Related

eigen3 cmake error within a docker container

I am trying to build a ROS2 package, and I get this error
CMake Error at /opt/ros/foxy/share/ament_cmake_target_dependencies/cmake/ament_target_dependencies.cmake:66 (message):
ament_target_dependencies() the passed package name 'Eigen3::Eigen' was not
found before
Call Stack (most recent call first):
CMakeLists.txt:83 (ament_target_dependencies)
I am trying to solve it using this, however i cannot identify which is my source folder for eigen3 installation.
What changes should I should make to my CMakelist?
libeigen3-dev is already the newest version (3.3.7-2).
and also
ros-foxy-eigen3-cmake-module is already the newest version(0.1.1-1focal.20210423.000604).
CMakelist:
cmake_minimum_required(VERSION 3.5)
project(avoidance)
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wpedantic")
endif()
find_package(ament_cmake REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(perception_pcl REQUIRED)
find_package(rclcpp REQUIRED)
find_package(tf2 REQUIRED)
get_default_rmw_implementation(rmw_implementation)
find_package("${rmw_implementation}" REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(px4_msgs REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(std_msgs REQUIRED)
find_package(PythonInterp REQUIRED)
find_package(eigen3_cmake_module REQUIRED)
find_package(Eigen3 REQUIRED NO_MODULE)
find_package(Boost REQUIRED COMPONENTS system)
find_package(PCL REQUIRED)
if(DISABLE_SIMULATION)
message(STATUS "Building avoidance without Gazebo Simulation")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISABLE_SIMULATION")
else()
message(STATUS "Building avoidance with Gazebo Simulation")
find_package(yaml-cpp REQUIRED)
endif(DISABLE_SIMULATION)
#################
# Setup targets #
#################
## CMake Setup
# Build in Release mode if nothing is specified
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif(NOT CMAKE_BUILD_TYPE)
## Specify additional locations of header files
include_directories(
include
${rclcpp_INCLUDE_DIRS}
${PCL_INCLUDE_DIRS}
${YAML_CPP_INCLUDE_DIR}
)
## Declare a C++ library
set(AVOIDANCE_CPP_FILES
"src/common.cpp"
"src/histogram.cpp"
"src/transform_buffer.cpp"
"src/avoidance_node.cpp"
)
if(NOT DISABLE_SIMULATION)
set(AVOIDANCE_CPP_FILES "${AVOIDANCE_CPP_FILES}" "src/rviz_world_loader.cpp")
endif()
# Add avoidance lib
add_library(avoidance SHARED "${AVOIDANCE_CPP_FILES}")
ament_target_dependencies(avoidance Eigen3 px4_msgs ${${PROJECT_NAME}_EXPORTED_TARGETS})
target_include_directories(avoidance PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/${PROJECT_NAME}>
$<INSTALL_INTERFACE:include/${PROJECT_NAME}>
${Eigen3_INCLUDE_DIRS}
)
## Specify libraries to link a library or executable target against
target_link_libraries(
avoidance
Eigen3::Eigen
${YAML_CPP_LIBRARIES}
)
# Add node dependencies
ament_target_dependencies(avoidance px4_msgs rclcpp Eigen3::Eigen)
# Export information to downstream packages
ament_export_dependencies(ament_cmake rclcpp rosidl_default_runtime eigen3_cmake_module Eigen3 px4_msgs geometry_msgs sensor_msgs std_msgs)
ament_export_interfaces(export_avoidance HAS_LIBRARY_TARGET)
ament_export_include_directories(include)
ament_export_libraries(avoidance)
#############
## Install ##
#############
# Install header files
install(DIRECTORY include/${PROJECT_NAME}/
DESTINATION include/${PROJECT_NAME}
FILES_MATCHING PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
# Install artifacts
install(TARGETS avoidance
EXPORT export_avoidance
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin
INCLUDES DESTINATION include
)
# Install launch files
install(DIRECTORY
launch
DESTINATION share/${PROJECT_NAME}
)
#############
## Testing ##
#############
# if(CATKIN_ENABLE_TESTING)
# # Add gtest based cpp test target and link libraries
# catkin_add_gtest(${PROJECT_NAME}-test test/main.cpp
# test/test_common.cpp
# test/test_usm.cpp
# test/test_transform_buffer.cpp
# )
#
# if(TARGET ${PROJECT_NAME}-test)
# target_link_libraries(${PROJECT_NAME}-test ${PROJECT_NAME}
# ${catkin_LIBRARIES}
# ${YAML_CPP_LIBRARIES})
# endif()
#
#
# if (${CMAKE_BUILD_TYPE} STREQUAL "Coverage")
# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage --coverage")
# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage --coverage")
# SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
#
# add_custom_target(${PROJECT_NAME}-test_coverage
# COMMAND lcov --zerocounters --directory ${PROJECT_BINARY_DIR}
# COMMAND lcov --capture --initial --no-external --directory ${PROJECT_BINARY_DIR} --base-directory ${${PROJECT_NAME}_SOURCE_DIR} --output-file base_coverage.info --rc lcov_branch_coverage=1
# COMMAND ${PROJECT_NAME}-test
# COMMAND lcov --capture --no-external --directory ${PROJECT_BINARY_DIR} --base-directory ${${PROJECT_NAME}_SOURCE_DIR} --output-file test_coverage.info --rc lcov_branch_coverage=1
# COMMAND lcov -a base_coverage.info -a test_coverage.info -o coverage.info --rc lcov_branch_coverage=1
# COMMAND lcov --rc lcov_branch_coverage=1 --summary coverage.info
# WORKING_DIRECTORY .
# DEPENDS ${PROJECT_NAME}-test
# )
# add_custom_target(${PROJECT_NAME}-test_coverage_html
# COMMAND genhtml coverage.info --output-directory out --branch-coverage
# COMMAND x-www-browser out/index.html
# WORKING_DIRECTORY .
# DEPENDS ${PROJECT_NAME}-test_coverage
# )
# endif()
# endif()
ament_package()
Taking a look at nav2_smac_planner/CMakeLists.txt
I found that you actually use Eigen3 inside the ament_target_dependencies instead of eigen3_cmake_module.
There they also export it in ament_export_dependencies.
So... for including the header, you should use Eigen3, but dependency-wise, eigen3_cmake_modules should be used.

Modern CMake transitive Dependency not found

I am currently working on implementing a ROS library into our company software stack. Because the library is based on ROS and thus uses catkin I am rewriting the library to use cmake exclusively and try to apply the modern CMake approach. The library is structured as follows:
.
|-- CMakeLists.txt
|-- LICENSE
|-- README.md
|-- grid_map_core
| |-- CHANGELOG.rst
| |-- CMakeLists.txt
| |-- cmake
| | `-- grid_map_core-extras.cmake
| |-- grid_map_coreConfig.cmake
| |-- include
| | `-- grid_map_core
| | `-- iterators
| |-- src
| | `-- iterators
| `-- test
If I install the library and try to add the library in a simple test_project to the target I get an error displaying the Eigen3 dependency cannot be found:
CMake Error at CMakeLists.txt:6 (find_package):
Found package configuration file:
/usr/local/lib/cmake/grid_map_core/grid_map_coreConfig.cmake
but it set grid_map_core_FOUND to FALSE so package "grid_map_core" is
considered to be NOT FOUND. Reason given by package:
grid_map_core could not be found because dependency Eigen3 could not be
found.
Unfortunately the Eigen version I have to use does not provide the Eigen3Config.cmake option and I am forced to use the cmake provided FindEigen3.cmake alternative.
(I suppose compiling a newer Eigen3 version manually would be a valid alternative, nevertheless I try to completely understand the modern cmake approach which looks very promising for exactly avoiding such issues)
From all the resources online I am not quite sure how the transitive dependency is handled in this case.
To my understanding the grid_map_coreConfig.cmake should forward the imported Eigen3 dependency.
In the grid_map_core CMakeLists the eigen is found by the command find_package(Eigen3 3.2 REQUIRED) and the find_dependency macro just wraps this exact same command.
Resources
The main CmakeLists.txt looks as follows:
# Set cmake version
cmake_minimum_required(VERSION 3.0.2)
# Set project name
project(grid_map)
# Must use GNUInstallDirs to install libraries into correct
# locations on all platforms.
include(GNUInstallDirs)
add_compile_options(-std=c++11)
# Add subdirectories
add_subdirectory(grid_map_core)
The grid_map_core CMakeLists as follows:
# Set cmake version
cmake_minimum_required(VERSION 3.0.2)
# Set project name
project(grid_map_core)
add_compile_options(-std=c++11)
# import Eigen3
find_package(Eigen3 3.2.2 REQUIRED)
## Define Eigen addons.
include(cmake/${PROJECT_NAME}-extras.cmake)
#########
# Build #
#########
# Add the library target
add_library(${PROJECT_NAME}
src/BufferRegion.cpp
src/GridMap.cpp
src/GridMapMath.cpp
src/Polygon.cpp
src/SubmapGeometry.cpp
src/iterators/CircleIterator.cpp
src/iterators/EllipseIterator.cpp
src/iterators/GridMapIterator.cpp
src/iterators/LineIterator.cpp
src/iterators/PolygonIterator.cpp
src/iterators/SlidingWindowIterator.cpp
src/iterators/SubmapIterator.cpp
)
# set target include directories
target_include_directories(${PROJECT_NAME}
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
${EIGEN3_INCLUDE_DIR}
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src
)
# add an alias
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
# set target compile options
target_compile_options(${PROJECT_NAME}
PRIVATE
$<$<CONFIG:Debug>:-Werror>
)
###########
# Install #
###########
# 'make install' to the right locations
install(TARGETS ${PROJECT_NAME}
EXPORT "${PROJECT_NAME}Targets"
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES DESTINATION include
)
# This makes the project importable from the install directory
# Put config file in per-project dir.
install(EXPORT "${PROJECT_NAME}Targets"
FILE "${PROJECT_NAME}Targets.cmake"
NAMESPACE "${PROJECT_NAME}::"
DESTINATION lib/cmake/${PROJECT_NAME})
# generate config.cmake
include(CMakePackageConfigHelpers)
write_basic_package_version_file("${PROJECT_NAME}ConfigVersion.cmake"
VERSION "${PROJECT_NAME}_VERSION"
COMPATIBILITY SameMajorVersion
)
# install config.cmake files
install(FILES "${PROJECT_NAME}Config.cmake"
DESTINATION "lib/cmake/${PROJECT_NAME}")
###########
# Testing #
###########
and the grid_map_coreConfig.cmake as follows:
include(CMakeFindDependencyMacro)
find_dependency(Eigen3 REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/grid_map_coreTargets.cmake")
and the test_project's CMakeLists.txt:
cmake_minimum_required(VERSION 3.0)
project(test_project)
set(CMAKE_MODULE_PATH /usr/share/cmake-3.0/Modules)
add_compile_options(-std=c++11)
find_package(grid_map_core REQUIRED CONFIG)
add_executable(test_project main.cpp)
target_link_libraries(test_project
PRIVATE
grid_map_core::grid_map_core
)
For completeness I'm adding the FindEigen3.cmake file:
# - Try to find Eigen3 lib
#
# This module supports requiring a minimum version, e.g. you can do
# find_package(Eigen3 3.1.2)
# to require version 3.1.2 or newer of Eigen3.
#
# Once done this will define
#
# EIGEN3_FOUND - system has eigen lib with correct version
# EIGEN3_INCLUDE_DIR - the eigen include directory
# EIGEN3_VERSION - eigen version
# Copyright (c) 2006, 2007 Montel Laurent, <montel#kde.org>
# Copyright (c) 2008, 2009 Gael Guennebaud, <g.gael#free.fr>
# Copyright (c) 2009 Benoit Jacob <jacob.benoit.1#gmail.com>
# Redistribution and use is allowed according to the terms of the 2-clause BSD license.
if(NOT Eigen3_FIND_VERSION)
if(NOT Eigen3_FIND_VERSION_MAJOR)
set(Eigen3_FIND_VERSION_MAJOR 2)
endif(NOT Eigen3_FIND_VERSION_MAJOR)
if(NOT Eigen3_FIND_VERSION_MINOR)
set(Eigen3_FIND_VERSION_MINOR 91)
endif(NOT Eigen3_FIND_VERSION_MINOR)
if(NOT Eigen3_FIND_VERSION_PATCH)
set(Eigen3_FIND_VERSION_PATCH 0)
endif(NOT Eigen3_FIND_VERSION_PATCH)
set(Eigen3_FIND_VERSION "${Eigen3_FIND_VERSION_MAJOR}.${Eigen3_FIND_VERSION_MINOR}.${Eigen3_FIND_VERSION_PATCH}")
endif(NOT Eigen3_FIND_VERSION)
macro(_eigen3_check_version)
file(READ "${EIGEN3_INCLUDE_DIR}/Eigen/src/Core/util/Macros.h" _eigen3_version_header)
string(REGEX MATCH "define[ \t]+EIGEN_WORLD_VERSION[ \t]+([0-9]+)" _eigen3_world_version_match "${_eigen3_version_header}")
set(EIGEN3_WORLD_VERSION "${CMAKE_MATCH_1}")
string(REGEX MATCH "define[ \t]+EIGEN_MAJOR_VERSION[ \t]+([0-9]+)" _eigen3_major_version_match "${_eigen3_version_header}")
set(EIGEN3_MAJOR_VERSION "${CMAKE_MATCH_1}")
string(REGEX MATCH "define[ \t]+EIGEN_MINOR_VERSION[ \t]+([0-9]+)" _eigen3_minor_version_match "${_eigen3_version_header}")
set(EIGEN3_MINOR_VERSION "${CMAKE_MATCH_1}")
set(EIGEN3_VERSION ${EIGEN3_WORLD_VERSION}.${EIGEN3_MAJOR_VERSION}.${EIGEN3_MINOR_VERSION})
if(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
set(EIGEN3_VERSION_OK FALSE)
else(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
set(EIGEN3_VERSION_OK TRUE)
endif(${EIGEN3_VERSION} VERSION_LESS ${Eigen3_FIND_VERSION})
if(NOT EIGEN3_VERSION_OK)
message(STATUS "Eigen3 version ${EIGEN3_VERSION} found in ${EIGEN3_INCLUDE_DIR}, "
"but at least version ${Eigen3_FIND_VERSION} is required")
endif(NOT EIGEN3_VERSION_OK)
endmacro(_eigen3_check_version)
if (EIGEN3_INCLUDE_DIR)
# in cache already
_eigen3_check_version()
set(EIGEN3_FOUND ${EIGEN3_VERSION_OK})
else (EIGEN3_INCLUDE_DIR)
find_path(EIGEN3_INCLUDE_DIR NAMES signature_of_eigen3_matrix_library
PATHS
${CMAKE_INSTALL_PREFIX}/include
${KDE4_INCLUDE_DIR}
PATH_SUFFIXES eigen3 eigen
)
if(EIGEN3_INCLUDE_DIR)
_eigen3_check_version()
endif(EIGEN3_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Eigen3 DEFAULT_MSG EIGEN3_INCLUDE_DIR EIGEN3_VERSION_OK)
mark_as_advanced(EIGEN3_INCLUDE_DIR)
endif(EIGEN3_INCLUDE_DIR)
The error message you got is generated by find_dependency macro, but not by find_package command, which is called internally by that macro. Because you call find_dependency with REQUIRED keyword (and this keyword is passed to inner find_package), the only possible scenario of your error is follow:
Call to find_package(Eigen3 REQUIRED) interprets Eigen3 to be found.
But when find_dependency checks find_package results, it interprets Eigen3 to be not found.
Rather strange, isn't it?
Actually, your FindEigen3.cmake script is one of the old ones, which sets upper case flow of "FOUND" variable, which denotes success of the script:
# EIGEN3_FOUND - system has eigen lib with correct version
but the correct name of such variable should be Eigen3_FOUND (the package name should be exactly the same as in find_package(Eigen3) call and in the name of the script FindEigen3.cmake).
Command find_package checks both spelling of the "FOUND" variable: correct one and upper-case one. Such way, when FindEigen3.cmake script sets EIGEN3_FOUND variable with intention "I have found the package", find_package understands that intention, marking the package as found.
But macro find_dependency checks only correct name of the variable, Eigen3_FOUND. Because this variable isn't set by the FindEigen3.cmake script, the package is treated as not found.
As a fast fix, you may replace in the FindEigen3.cmake script EIGEN3_FOUND with Eigen3_FOUND, and everything should work. (Well, the same replacement should be done on the user machine. Or you should ship corrected FindEigen3.cmake script with your library).

Include these variables into cmake

This scientific application I am using uses cmake to build its program. Attached is the CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
set(PROJECT_NAME myproject)
project(${PROJECT_NAME})
# Set verbose output while testing CMake
#set(CMAKE_VERBOSE_MAKEFILE 1)
# Set CMake behavior
cmake_policy(SET CMP0004 OLD)
# Get DOLFIN configuration data (DOLFINConfig.cmake must be in
# DOLFIN_CMAKE_CONFIG_PATH)
find_package(DOLFIN)
# Need to get VTK config because VTK uses advanced VTK features which
# mean it's not enough to just link to the DOLFIN target. See
# http://www.vtk.org/pipermail/vtk-developers/2013-October/014402.html
find_package(VTK HINTS ${VTK_DIR} $ENV{VTK_DIR} NO_MODULE QUIET)
# Default build type (can be overridden by user)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
"Choose the type of build, options are: Debug MinSizeRel Release RelWithDebInfo." FORCE)
endif()
# Compiler definitions
add_definitions(${DOLFIN_CXX_DEFINITIONS})
# Compiler flags
set(CMAKE_CXX_FLAGS "${DOLFIN_CXX_FLAGS} ${CMAKE_CXX_FLAGS}")
# Include directories
include_directories(${DOLFIN_INCLUDE_DIRS})
include_directories(SYSTEM ${DOLFIN_3RD_PARTY_INCLUDE_DIRS})
# Executable
add_executable(${PROJECT_NAME} main.cpp)
# Target libraries
target_link_libraries(${PROJECT_NAME} ${DOLFIN_LIBRARIES})
However, I need to include some additional compiler flags and libraries not included within DOLFIN. I need to incorporate this package called PAPI. On my system, the paths/environments are:
PAPI_LIBDIR=/project/cacds/apps/papi/5.4.0/lib
PAPI_INCLUDE=/project/cacds/apps/papi/5.4.0/include
PAPI_FLAG=-lpapi
Normally I would do something like this:
gcc -O3 -o -I myproject $(PAPI_LIBDIR) main.c -L $(PAPI_INCLUDE) $(PAPI_FLAG)
But again I need the additional DOLFIN libraries and third party packages. Pardon me if this is a silly or simple question, but how would I modify the above CMakeLists.txt? I am kind of new to cmake, so any help appreciated, thanks
The cleanest solution would be to create a FindPAPI.cmake. So, add to your project this file inside of a cmake/folder:
FindPAPI.cmake
# Try to find PAPI headers and libraries.
#
# Usage of this module as follows:
#
# find_package(PAPI)
#
# Variables used by this module, they can change the default behaviour and need
# to be set before calling find_package:
#
# PAPI_PREFIX Set this variable to the root installation of
# libpapi if the module has problems finding the
# proper installation path.
#
# Variables defined by this module:
#
# PAPI_FOUND System has PAPI libraries and headers
# PAPI_LIBRARIES The PAPI library
# PAPI_INCLUDE_DIRS The location of PAPI headers
find_path(PAPI_PREFIX
NAMES include/papi.h
)
find_library(PAPI_LIBRARIES
# Pick the static library first for easier run-time linking.
NAMES libpapi.a papi
HINTS ${PAPI_PREFIX}/lib ${HILTIDEPS}/lib
)
find_path(PAPI_INCLUDE_DIRS
NAMES papi.h
HINTS ${PAPI_PREFIX}/include ${HILTIDEPS}/include
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PAPI DEFAULT_MSG
PAPI_LIBRARIES
PAPI_INCLUDE_DIRS
)
mark_as_advanced(
PAPI_PREFIX_DIRS
PAPI_LIBRARIES
PAPI_INCLUDE_DIRS
)
Then, modify your CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
set(PROJECT_NAME myproject)
project(${PROJECT_NAME})
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(PAPI REQUIRED)
...
# Include directories
include_directories(${DOLFIN_INCLUDE_DIRS})
include_directories(SYSTEM ${DOLFIN_3RD_PARTY_INCLUDE_DIRS})
include_directories(${PAPI_INCLUDE_DIRS})
# Executable
add_executable(${PROJECT_NAME} main.cpp)
# Target libraries
target_link_libraries(${PROJECT_NAME} ${PAPI_LIBRARIES} ${DOLFIN_LIBRARIES})
I hope it resolves it! ;)

ROS catkin_make executable is not generated in devel

I created a ROS package and added to the CMakeLists.txt the relevant lines to create an executable.
add_executable(exe_name src/file.cpp)
target_link_libraries(exe_name $LIBRARIES)
When I run catkin_make in the root of the workspace the executable is generated in WORKSPACE/build/PACKAGE_NAME/
instead of in
WORKSPACE/devel/lib/PACKAGE_NAME/
The problem is now when I run rosrun PACKAGE_NAME exe_name the executable name (exe_name) is not found. Any ideas why this might happen?
Edit - added the complete CMakeLists.txt
cmake_minimum_required(VERSION 2.8.3)
project(flea3ros)
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
sensor_msgs
cv_bridge
image_transport
)
find_package(OpenCV 2)
include_directories(
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
/usr/include/flycapture
)
add_executable(flea3syncros src/asyncRos.cpp)
add_executable(flea3ros src/GigEGrabEx.cpp)
add_executable(flea3config src/GigEConfig.cpp)
add_executable(saveImages src/save_images.cpp)
target_link_libraries(flea3ros ${catkin_LIBRARIES} ${OpenCV_LIBS} flycapture)
target_link_libraries(flea3syncros ${catkin_LIBRARIES} ${OpenCV_LIBS} flycapture)
target_link_libraries(flea3config ${catkin_LIBRARIES} ${OpenCV_LIBS} flycapture)
target_link_libraries(saveImages ${catkin_LIBRARIES} ${OpenCV_LIBS})
The catkin_package macro is missing in your CMakeLists.txt. Add this after the find_package section:
###################################
## catkin specific configuration ##
###################################
## The catkin_package macro generates cmake config files for your package
## Declare things to be passed to dependent projects
## INCLUDE_DIRS: uncomment this if you package contains header files
## LIBRARIES: libraries you create in this project that dependent projects also need
## CATKIN_DEPENDS: catkin_packages dependent projects also need
## DEPENDS: system dependencies of this project that dependent projects also need
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES compute_cdist
# CATKIN_DEPENDS roscpp visualization_msgs robot_model_helper compute_cdist
# DEPENDS assimp Eigen mlpack
)
(You can remove the comments of course, I just copied the whole block so that the description is contained)

How to check if find_package found the package (boost)

I want to not add boost.cxx if cmake find_package found no boost installed. Does find_package return something that I can wrap in condition to compile boost.cxx or not. Here is my current cmake file:
add_executable (complex complex.cxx lexer.cxx boost.cxx ../../src/lili.cxx ../../src/lilu.cxx)
# Make sure the compiler can find all include files
include_directories (../../src)
include_directories (.)
# Make sure the linker can find all needed libraries
# rt: clock_gettime()
target_link_libraries(complex rt)
# Install example application
install (TARGETS complex
RUNTIME DESTINATION bin)
IF(UNIX)
find_package(Boost COMPONENTS system filesystem REQUIRED)
## Compiler flags
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-O2")
set(CMAKE_EXE_LINKER_FLAGS "-lsqlite3 -lrt -lpthread")
endif()
target_link_libraries(complex
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
#${PROTOBUF_LIBRARY}
)
ENDIF(UNIX)
The FindXXX scripts are supposed to set a variable <Packagename>_FOUND to TRUEif the package was found. So in your case, it will set Boost_FOUND if boost was found.
When compiling your Boost.cxx, I assume that you will need Boost headers as well, so you should adjust your include directories as well.*
look for Boost before creating your executable. Furhtermore, you need to set your include directories before adding the executable.
IF(UNIX)
find_package(Boost COMPONENTS system filesystem REQUIRED)
# IF( Boost_FOUND ) # checking this variable isnt even necessary, since you added
# REQUIRED to your call to FIND_PACKAGE
SET( BOOST_SRC_FILES boost.cxx )
INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIRS} ) # you could move this down as well
# as ${Boost_INCLUDE_DIRS} will be
# empty if Boost was not found
# ENDIF()
ENDIF()
add_executable (complex complex.cxx lexer.cxx ${BOOST_SRC_FILES} ../../src/lili.cxx ../../src/lilu.cxx)
# Make sure the compiler can find all include files
include_directories (../../src)
include_directories (.)
# INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIRS} ) # alternative location to
# add include dirs, see above
# Make sure the linker can find all needed libraries
# rt: clock_gettime()
target_link_libraries(complex rt)
# Install example application
install (TARGETS complex
RUNTIME DESTINATION bin)
IF(UNIX)
## Compiler flags
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "-O2")
set(CMAKE_EXE_LINKER_FLAGS "-lsqlite3 -lrt -lpthread")
endif()
target_link_libraries(complex
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
#${PROTOBUF_LIBRARY}
)
ENDIF(UNIX)
Afternote: Since you use the REQUIRED flag when looking for Boost (since you only need it on Unix platform) it is even sufficient to use the optional-source-files-in-a-variable trick.
(*) Thanks to your question, I just found out that it doesn't matter whether include_directories(...) is called before or after creating the target with ADD_EXECUTABLE or ADD_LIBRARY since the directories are added to all targets in the same project.
Yes, if the find_package(Boost COMPONENTS system filesystem REQUIRED) succeeds, Boost_FOUND will be true.
Also, there will be component-specific versions, so Boost_date_time_FOUND, Boost_filesystem_FOUND, etc.
For further info, run
cmake --help-module FindBoost
Yes, it sets variable Boost_FOUND. Example from FindBoost.cmake:
== Using actual libraries from within Boost: ==
#
# set(Boost_USE_STATIC_LIBS ON)
# set(Boost_USE_MULTITHREADED ON)
# set(Boost_USE_STATIC_RUNTIME OFF)
# find_package( Boost 1.36.0 COMPONENTS date_time filesystem system ... )
#
# if(Boost_FOUND)
# include_directories(${Boost_INCLUDE_DIRS})
# add_executable(foo foo.cc)
# target_link_libraries(foo ${Boost_LIBRARIES})
# endif()