现代CMake传递依赖未找到

问题描述 投票:0回答:1

我目前正致力于将ROS库实现到我们公司的软件堆栈中。因为该库是基于ROS并因此使用catkin我重写库以专门使用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选项,我被迫使用cmake提供的FindEigen3.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 CMakeLists如下:

# 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, <[email protected]>
# Copyright (c) 2008, 2009 Gael Guennebaud, <[email protected]>
# Copyright (c) 2009 Benoit Jacob <[email protected]>
# 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)

cmake build-system
1个回答
0
投票

您获得的错误消息由find_dependency宏生成,但不是由find_package命令生成,该命令由该宏在内部调用。因为您使用REQUIRED关键字调用find_dependency(并且此关键字传递给内部find_package),所以您的错误的唯一可能情况如下:

  1. 致电find_package(Eigen3 REQUIRED)解释Eigen3被发现。
  2. 但是当find_dependency检查find_package结果时,它解释了未找到Eigen3。

相当奇怪,不是吗?

实际上,你的FindEigen3.cmake脚本是旧的脚本之一,它设置了“FOUND”变量的大写流程,表示脚本的成功:

#EIGEN3_FOUND - 系统具有正确的lib,版本正确

但是这个变量的正确名称应该是Eigen3_FOUND(包名应该与find_package(Eigen3)调用和脚本FindEigen3.cmake的名称完全相同)。

命令find_package检查“FOUND”变量的拼写:正确一个和大写一个。这样,当FindEigen3.cmake脚本设置EIGEN3_FOUND变量意图“我找到了包”,find_package理解该意图,标记包发现。

但宏find_dependency只检查变量的正确名称Eigen3_FOUND。由于此变量未由FindEigen3.cmake脚本设置,因此该包被视为未找到。

作为一个快速修复,你可以用FindEigen3.cmake替换EIGEN3_FOUND脚本Eigen3_FOUND,一切都应该工作。 (嗯,应该在用户机器上进行相同的替换。或者你应该在你的库中发送更正的FindEigen3.cmake脚本)。

© www.soinside.com 2019 - 2024. All rights reserved.