我目前正在将ROS库实现到我们公司的软件堆栈中。因为该库基于ROS并因此使用柔uses花色,所以我正在重写该库以仅使用cmake并尝试应用modern CMake approach。该库的结构如下:
.
|-- 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
如果我安装该库并尝试将库添加到目标的简单test_project中,则会出现错误,显示找不到Eigen3依赖项:
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.
不幸的是,我必须使用的Eigen版本没有提供Eigen3Config.cmake
选项,并且我不得不使用FindEigen3.cmake
提供的cmake选项。
(我认为手动编译较新的Eigen3版本是一种有效的选择,尽管如此,我还是试图完全理解现代的cmake方法,该方法对于完全避免此类问题看起来很有希望)
从所有在线资源中,我不确定在这种情况下如何处理传递依赖。
据我了解,grid_map_coreConfig.cmake
应该转发导入的Eigen3依赖项。
在grid_map_core
CMakeLists中,本征是通过命令find_package(Eigen3 3.2 REQUIRED)
找到的,而find_dependency
宏只是包装了这个完全相同的命令。
主要的CmakeLists.txt如下:
# 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)
grid_map_core CMakeList如下:
# 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 #
###########
和grid_map_coreConfig.cmake如下:
include(CMakeFindDependencyMacro)
find_dependency(Eigen3 REQUIRED)
include("${CMAKE_CURRENT_LIST_DIR}/grid_map_coreTargets.cmake")
和test_project
的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
)
为完整起见,我添加了FindEigen3.cmake
文件:
# - 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)
答案 0 :(得分:0)
您收到的错误消息是由find_dependency
宏生成的,而不是由find_package
命令生成的,该命令由该宏在内部调用。因为您使用 REQUIRED 关键字调用find_dependency
(并且此关键字传递到内部find_package
),所以唯一可能出现错误的情况如下:
find_package(Eigen3 REQUIRED)
会将Eigen3解释为找到。find_dependency
检查find_package
结果时,它会将Eigen3解释为未找到。不是很奇怪吗?
实际上,您的FindEigen3.cmake
脚本是旧的脚本之一,它设置了
#EIGEN3_FOUND-系统具有正确版本的本征库
,但此类变量的正确名称应为Eigen3_FOUND
(程序包名称应与find_package(Eigen3)
调用中的脚本名称和脚本{{ 1}})。
命令FindEigen3.cmake
会同时检查“ FOUND”变量的拼写:正确的一个和大写的一个。这样,当find_package
脚本设置意图为“我已找到包”的FindEigen3.cmake
变量时,EIGEN3_FOUND
会理解该意图,将包标记为 found 。 / p>
但是宏find_package
仅检查变量find_dependency
的正确名称。由于Eigen3_FOUND
脚本未设置此变量,因此该软件包被视为未找到。
作为快速解决方案,您可以将FindEigen3.cmake
脚本FindEigen3.cmake
替换为EIGEN3_FOUND
,然后一切正常。 (嗯,应该在用户计算机上进行相同的替换。或者您应该在库中附带更正的Eigen3_FOUND
脚本)。