Странная проблема с переменными в пакете конфигурации cmake-файла - PullRequest
5 голосов
/ 17 мая 2019

Мы можем использовать файл конфигурации cmake для импорта целей.Например, данный машинный в том числе foobarConfig.cmake.in

set(FOOBAR_VERSION @VERSION@)

@PACKAGE_INIT@

set_and_check(FOOBAR_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
set_and_check(FOOBAR_LIBRARY_DIR "@PACKAGE_LIBRARY_INSTALL_DIR@")
set_and_check(FOOBAR_LIBRARY "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so")
set_and_check(FOOBAR_STATIC_LIBRARY @PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.a")
include("${CMAKE_CURRENT_LIST_DIR}/FoobarLibTargets.cmake")

message(STATUS "foobar version: ${FOOBAR_VERSION}")
message(STATUS "foobar include location: ${FOOBAR_INCLUDE_DIR}")
message(STATUS "foobar library location: ${FOOBAR_LIBRARY_DIR}")

для экспортируемого целевого foobar

Мы можем сделать:

find_package(foobar)

add_executable(usesfoo 
               usesfoo.cpp)
target_link_libraries(usesfoo
               ${FOOBAR_LIBRARY})
target_include_directories(usesfoo PUBLIC
               ${FOOBAR_INCLUDE_DIR})

иэто обычно просто работает.Тем не менее, у меня есть странный случай, когда переменные, установленные в Config.cmake, не доступны после find_package.Например, дано:

find_package(foobar REQUIRED)
if (foobar_FOUND)
   message(STATUS "found foobar")
endif()

message(STATUS "foobar include location2: ${FOOBAR_INCLUDE_DIR}")
message(STATUS "foobar library location2: ${FOOBAR_LIBRARY_DIR}")

Вывод:

foobar include location: /test-import/opt/foobar/include
foobar library location: /test-import/opt/foobar/lib
found foobar
foobar include location2:
foobar library location2:

Что здесь может происходить?

Как я могу:

  • Найти эту проблему?
  • Избежать подобных проблем в будущем?
  • Создать эти файлы безопасным и каноническим способом?

Я очень запутался, пытаясь отладить это, и начал задаваться вопросом, как должны работать пакеты Config.Должен ли я использовать свойства импортированных целей вместо переменных?В какой области работает find_package?Я думал, что это было похоже на include (), а не add_subdirectory () - который вводит свою собственную область.Как эти переменные могут стать неустановленными?Что делает find_package под капотом?

См. Также , чтобы правильно установить местоположение импортированных целей cmake для установленного пакета .Этот вопрос содержит код для воспроизведения этой проблемы, который похож на код этой проблемы.


Полный набор файлов для воспроизведения проблемы:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.7)
set(VERSION 1.3.3)

project(FoobarLib VERSION "${VERSION}" LANGUAGES CXX)

SET(CMAKE_INSTALL_PREFIX "/opt/foo")
set(INSTALL_LIB_DIR lib)

add_library(foobar SHARED
   foobar.cpp
)

# Create the distribution package(s)
set(CPACK_PACKAGE_VERSION ${VERSION})
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})

set(CPACK_PACKAGE_NAME "foobar")
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")

set(LIBRARY_INSTALL_DIR lib)
set(INCLUDE_INSTALL_DIR include)

INSTALL(TARGETS foobar
  EXPORT FoobarLibTargets
  LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
  ARCHIVE DESTINATION ${LIBRARY_INSTALL_DIR}
  INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR})

include(CMakePackageConfigHelpers)
set(ConfigFileInstallDir lib/cmake/FoobarLib)
set(INCLUDE_INSTALL_DIR include CACHE PATH "install path for include files")
set(LIBRARY_INSTALL_DIR lib CACHE PATH "install path for libraries")
configure_package_config_file(FoobarLibConfig.cmake.in
  "${CMAKE_CURRENT_BINARY_DIR}/FoobarLibConfig.cmake"
  INSTALL_DESTINATION "${ConfigFileInstallDir}"
  PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR
  )
write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/FoobarLibConfigVersion.cmake"
  VERSION "${VERSION}"
  COMPATIBILITY SameMajorVersion)

EXPORT(EXPORT FoobarLibTargets
  FILE FoobarLibTargets.cmake)

INSTALL(FILES
  "${CMAKE_CURRENT_BINARY_DIR}/FoobarLibConfig.cmake"
  "${CMAKE_CURRENT_BINARY_DIR}/FoobarLibConfigVersion.cmake"
  "${CMAKE_CURRENT_BINARY_DIR}/FoobarLibTargets.cmake"
  DESTINATION "${ConfigFileInstallDir}")

include(CPack)

FoobarLibConfig.cmake.in:

set(FoobarLib_VERSION @VERSION@)

@PACKAGE_INIT@

INCLUDE("${CMAKE_CURRENT_LIST_DIR}/FoobarLibTargets.cmake")

SET_AND_CHECK(FoobarLib_LIB_DIR "@PACKAGE_LIBRARY_INSTALL_DIR@")

message(STATUS "Foobar library version: ${FoobarLib_VERSION}")
message(STATUS "Foobar library location: ${FoobarLib_LIB_DIR}")

# workaround incorrect setting of location for import targets when package is installed
# see https://stackoverflow.com/q/56135785/1569204
#set_target_properties(foobar PROPERTIES
#                      IMPORTED_LOCATION_NOCONFIG "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so"
#                      IMPORTED_LOCATION_RELEASE "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so"
#                      IMPORTED_LOCATION_DEBUG "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so")

check_required_components(FoobarLib)

run.sh:

#!/bin/sh

SRC=`pwd`
mkdir -p ./target/debug && \
cd ./target/debug &&
cmake -DCMAKE_BUILD_TYPE=Debug ../../ &&
make &&
cpack -G TGZ 

cd ../..

rm -rf foo
mkdir foo

TGZ=`pwd`/target/debug/foobar-1.3.3.tar.gz

cd foo
tar -xvzf $TGZ
cat - >CMakeLists.txt <<EOF
cmake_minimum_required(VERSION 3.7)
project(useFoo VERSION 1.2.3)

find_package(FoobarLib ${MIN_FOOBARLIB_VERSION}
  HINTS "${WSDIR}/opt/foo"
  PATHS /opt/foo
  REQUIRED)

message(STATUS "Foobar library version: ${FOOBARLIB_VERSION}")
message(STATUS "Foobar library location: ${FOOBARLIB_LIB_DIR}")


message(STATUS "FoobarLib_FOUND=${FoobarLib_FOUND}")
message(STATUS "FoobarLib_PATH=${FOOBARLIB_PATH}")
message(STATUS "FoobarLib_DIR=${FoobarLib_DIR}")

message(STATUS "FOOBARLIB_FOUND=${FoobarLib_FOUND}")
message(STATUS "FOOBARLIB_PATH=${FOOBARLIB_PATH}")
message(STATUS "FOOBARLIB_DIR=${FoobarLib_DIR}")

file(GENERATE OUTPUT foobar-loc CONTENT "<TARGET_FILE:foobar>=$<TARGET_FILE:foobar>\n")

EOF
export CMAKE_PREFIX_PATH=`pwd`/opt/foo/lib/cmake:`pwd`/opt/foo/lib/cmake/
cmake . && make VERBOSE=1
echo pwd=`pwd`

# critical - check the location of the target is relative to the installation
grep $WSDIR/opt/foo/lib/libfoobar.so foobar-loc
if [ $? -ne 0 ]; then
   echo "FAIL: location of imported target 'foobar' is incorect" >&2
   cat foobar-loc >&2
   exit 1
fi

Вот сгенерированный Config.cmake по запросу @havogt Я не знаюНе думаю, что это помогает, поскольку это стандартный сгенерированный код:

# CMake configuration file for the FoobarLib package
# Use with the find_package command in config-mode to find information about
# the FoobarLib package.
#

set(FoobarLib_VERSION 1.3.3)


####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was FoobarLibConfig.cmake.in                            ########

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)

macro(set_and_check _var _file)
  set(${_var} "${_file}")
  if(NOT EXISTS "${_file}")
    message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
  endif()
endmacro()

macro(check_required_components _NAME)
  foreach(comp ${${_NAME}_FIND_COMPONENTS})
    if(NOT ${_NAME}_${comp}_FOUND)
      if(${_NAME}_FIND_REQUIRED_${comp})
        set(${_NAME}_FOUND FALSE)
      endif()
    endif()
  endforeach()
endmacro()

####################################################################################

INCLUDE("${CMAKE_CURRENT_LIST_DIR}/FoobarLibTargets.cmake")

SET_AND_CHECK(FoobarLib_LIB_DIR "${PACKAGE_PREFIX_DIR}/lib")

message(STATUS "Foobar library version: ${FoobarLib_VERSION}")
message(STATUS "Foobar library location: ${FoobarLib_LIB_DIR}")

# workaround incorrect setting of location for import targets when package is installed
# see https://stackoverflow.com/q/56135785/1569204
#set_target_properties(foobar PROPERTIES
#                      IMPORTED_LOCATION_NOCONFIG "${PACKAGE_PREFIX_DIR}/lib/libfoobar.so"
#                      IMPORTED_LOCATION_RELEASE "${PACKAGE_PREFIX_DIR}/lib/libfoobar.so"
#                      IMPORTED_LOCATION_DEBUG "${PACKAGE_PREFIX_DIR}/lib/libfoobar.so")

check_required_components(FoobarLib)

'package'_FOUND устанавливается реализацией find_package (), а не загружаемым Config.cmake.Добавление check_required_components () является хорошей практикой по другим причинам (обнаружение того, что кто-то считает, что пакет является компонентом, когда его нет), но не имеет отношения к этой проблеме.

Ответы [ 2 ]

2 голосов
/ 21 мая 2019

К сожалению. Это раздражительно. Я переместил код генерации в скрипт оболочки и забыл экранировать переменные!

cat - >CMakeLists.txt <<EOF
cmake_minimum_required(VERSION 3.7)
project(useFoo VERSION 1.2.3)

find_package(FoobarLib ${MIN_FOOBARLIB_VERSION}
  HINTS "${WSDIR}/opt/foo"
  PATHS /opt/foo
  REQUIRED)

message(STATUS "Foobar library version: ${FOOBARLIB_VERSION}")
message(STATUS "Foobar library location: ${FOOBARLIB_LIB_DIR}")


message(STATUS "FoobarLib_FOUND=${FoobarLib_FOUND}")
message(STATUS "FoobarLib_PATH=${FOOBARLIB_PATH}")
message(STATUS "FoobarLib_DIR=${FoobarLib_DIR}")

message(STATUS "FOOBARLIB_FOUND=${FoobarLib_FOUND}")
message(STATUS "FOOBARLIB_PATH=${FOOBARLIB_PATH}")
message(STATUS "FOOBARLIB_DIR=${FoobarLib_DIR}")

file(GENERATE OUTPUT foobar-loc CONTENT "<TARGET_FILE:foobar>=$<TARGET_FILE:foobar>\n")

EOF

Вопрос по-прежнему полезен для предоставления источника для соответствующего вопроса.

Чтобы ответить на мои собственные вопросы:

Как я могу найти эту проблему? Избежать подобных проблем в будущем? Создать эти файлы безопасным и каноническим способом?

  • https://en.wikipedia.org/wiki/Rubber_duck_debugging
  • Уменьшите проблему до минимально воспроизводимого примера (желательно перед публикацией при переполнении стека)
  • Избегайте (или, по крайней мере, будьте особенно внимательны) генерацию кода из сценариев оболочки
  • Снижение стресса и больше сна
0 голосов
/ 21 мая 2019

check_required_components(Foobar) должен быть вызван в конце дела. документы .

check_required_components () должен быть вызван в конце файла FooConfig.cmake. Этот макрос проверяет, все ли запрошено, были найдены необязательные компоненты, и если это не так, устанавливает переменную Foo_FOUND в FALSE, чтобы пакет считается не найденным. Это делается путем тестирования Переменные Foo__FOUND для всех запрошенных обязательных компонентов. Этот макрос должен вызываться, даже если пакет не предоставляет никаких компоненты, чтобы убедиться, что пользователи не указывают компоненты ошибочно. При использовании опции NO_CHECK_REQUIRED_COMPONENTS_MACRO, этот макрос не генерируется в файл FooConfig.cmake.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...