【问题标题】:correctly set the location of imported cmake targets for an installed package为已安装的包正确设置导入的 cmake 目标的位置
【发布时间】:2022-05-12 17:46:59
【问题描述】:

我希望能够从已安装的库中导入目标,但是 使用时:

install(TARGETS
        foobar
        EXPORT foobarLibTargets
        LIBRARY DESTINATION lib)

cmake 生成一个包含绝对路径的 foobarLibTargets.cmake

set_target_properties(foobar PROPERTIES
        IMPORTED_LOCATION_NOCONFIG "/where/I/happened/to/build/libfoobar.so"
        IMPORTED_SONAME_NOCONFIG "libfoobar.so"
)

这样使用安装中导入的目标的构建将失败,因为路径不存在。

Q 我怎样才能让它使用正确的相对位置呢?

这相当于:

set_target_properties(foobar PROPERTIES
                      IMPORTED_LOCATION_NOCONFIG "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so")

如果我查看另一个做类似事情但有效的项目:

set_target_properties(foobar PROPERTIES
         IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/libfoobar.so"
         IMPORTED_SONAME_RELEASE "libfoobar.so"
)

以下是一些重现该问题的示例文件:

CMakeLists.txt:

cmake_minimum_required(VERSION 3.7)
project(FOOBAR VERSION 1.2.3)
set(VERSION 1.2.3)

set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/")
set(CMAKE_INSTALL_PREFIX "/opt/foobar" CACHE PATH "Install path prefix" FORCE)

add_library(foobar SHARED
  foobar.cpp
)

set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_NAME "foobar")

set(CPACK_PACKAGE_VERSION ${VERSION})
set(CPACK_PACKAGING_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")

include(CPack)

# Indicate the content of the distribution pakcages
install(FILES
  ${CMAKE_SOURCE_DIR}/foobar.h
  DESTINATION include
)
install(TARGETS
  foobar
  EXPORT foobarLibTargets
  LIBRARY DESTINATION lib)

include(CMakePackageConfigHelpers)
set(ConfigFileInstallDir lib/cmake/foobar)
set(INCLUDE_INSTALL_DIR include)
set(LIBRARY_INSTALL_DIR lib)
message(STATUS "CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
configure_package_config_file(foobarConfig.cmake.in
     "${CMAKE_BINARY_DIR}/foobarConfig.cmake"
    INSTALL_DESTINATION "${ConfigFileInstallDir}"
    PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR)
write_basic_package_version_file(
   "${CMAKE_BINARY_DIR}/foobarConfigVersion.cmake"
   VERSION "${VERSION}"
   COMPATIBILITY ExactVersion)
export(EXPORT foobarLibTargets
       FILE "${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake")
install(EXPORT foobarLibTargets
        FILE foobarTargets.cmake
        DESTINATION lib/cmake)
install(FILES
   "${CMAKE_CURRENT_BINARY_DIR}/foobarConfig.cmake"
   "${CMAKE_CURRENT_BINARY_DIR}/foobarConfigVersion.cmake"
   "${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake"
    DESTINATION "${ConfigFileInstallDir}")

foobarConfig.cmake.in:

set(FOOBAR_VERSION @VERSION@)

@PACKAGE_INIT@

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

# workaround - correct absolute path in the above
# this shouldn't be necessary (hence this question)
#set_target_properties(foobar PROPERTIES
#  IMPORTED_LOCATION_NOCONFIG "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so"
#)

foobar.h:

void hello();

foobar.cpp:

#include <iostream>

void hello() {
   std::cerr << "hello world\n";
}

useFoo.cmake(使用已安装库的示例项目的 CMakeLists.txt):

cmake_minimum_required(VERSION 3.7)
project(useFoo VERSION 1.2.3)
set(VERSION 1.2.3)

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

message(STATUS "FOOBAR_LIBRARY_DIR=${FOOBAR_LIBRARY_DIR}")
message(STATUS "FOOBAR_INCLUDE_DIR=${FOOBAR_INCLUDE_DIR}")

build.sh(构建并使用安装包):

#!/bin/sh

rm -rf target
mkdir target
cd target
cmake .. &&
make &&
cpack -G TGZ
if [ $? -ne 0 ]; then
   echo "doh!"
   exit 1
fi

cd ..
rm -rf install
mkdir install
cd install
tar -xvzf ../target/foobar-1.2.3.tar.gz
cp ../useFoo.cmake CMakeLists.txt
export CMAKE_PREFIX_PATH=`pwd`/opt/foobar/lib/cmake:`pwd`/opt/foobar/lib/cmake/foobar
cmake .
if [ $? -ne 0 ]; then
   echo "doh!"
   exit 1
fi
cat foobar-gen

cat foobar-gen 的输出是:

<TARGET_FILE:foobar>=/where/I/happened/to/build/libfoobar.so

我希望它是:

<TARGET_FILE:foobar>=/where/I/actually/installed/libfoobar.so

如果我取消注释解决方法,它会变成什么。 有没有办法避免变通办法?

相关问题 - Strange issue with variables in a config-file cmake package - 具有类似的代码,既重现了此问题,又在顶部添加了另一个问题。

【问题讨论】:

标签: cmake


【解决方案1】:

主要问题是foobarLibTargets.cmakefoobarTargets.cmake这两个文件都被安装了,却选错了。

您将在下面找到一个改进的项目以及用于更好地组织构建系统的备注。

ChangeLog 总结编辑

  • 2019-05-25
    • 创建 GitHub 项目以简化重用和适应。见https://github.com/jcfr/stackoverflow-56135785-answer
    • 将项目和源目录从 foobar 重命名为 FooBarLib,相应地更新“建议”部分
    • 改进build.sh
    • 更新的建议(CPACK_PACKAGING_INSTALL_PREFIX 应该是绝对的)
    • 转速:
      • 添加对使用 make package 构建 RPM 包的支持
      • 更新 build.sh 以显示 RPM 包的内容

备注

  • 应该生成两个配置文件:
    • 一个用于构建树:这允许您的项目用户直接针对您的项目构建并导入目标
    • 一个用于安装树(最终也被打包)
  • 不要强制CMAKE_INSTALL_PREFIX的值
  • CPACK_PACKAGING_INSTALL_PREFIX 不应设置为绝对目录
  • 为保持一致,请使用foobarTargets 而不是foobarLibTargets
  • 下面使用的&lt;projecname_uc&gt;占位符对应项目名称大写(ABC而不是abc
  • 要允许在与其他项目一起供应时配置您的项目,最好使用带有&lt;projecname_uc&gt;_ 的变量。这意味着&lt;projecname_uc&gt;_INSTALL_LIBRARY_DIR 优于LIBRARY_INSTALL_DIR
  • 要允许项目用户配置*_INSTALL_DIR 变量,请将它们包裹在if(DEFINED ...)
  • 始终使用变量(例如,应始终使用 LIBRARY_INSTALL_DIR 而不是 lib
  • 更喜欢命名变量&lt;projecname_uc&gt;_INSTALL_*_DIR而不是&lt;projecname_uc&gt;_*_INSTALL_DIR,这样在阅读代码时更容易知道变量的用途。
  • 由于版本已经与项目关联,无需设置VERSION变量。相反,您可以使用 PROJECT_VERSIONFOOBAR_VERSION
  • 如果开始一个新项目,请选择最新的 CMake 版本。 CMake 3.13 而不是 CMake 3.7
  • 引入变量&lt;projecname_uc&gt;_INSTALL_CONFIG_DIR
  • &lt;project_name&gt;Targets.cmake 不应使用 install(FILES ...) 安装,它已与安装规则相关联
  • 有条件地设置CMAKE_INSTALL_RPATH,只在Linux上有效
  • &lt;project_name&gt;Config.cmake.in:
    • 无需设置FOOBAR_LIBRARY,该信息已经与导出的foobar目标关联
    • FOOBAR_LIBRARY_DIR 也不需要,此信息已与导出的foobar 目标相关联
    • 不应设置 FOOBAR_INCLUDE_DIR,而应使用命令 target_include_directories
    • 删除FOOBAR_VERSION的设置,生成版本文件已经负责设置版本。
  • 在声明目标安装规则时始终指定 ARCHIVE、LIBRARY 和 RUNTIME。它避免了切换库类型时的问题。少一件需要考虑的事情。
  • 始终使用您的安装规则指定组件。它允许您的项目用户有选择地安装它的一部分,仅开发组件或仅运行时组件,...
  • 初始化 CMAKE_BUILD_TYPE 也很重要,它确保生成的 Targets 文件与配置相关联(而不是后缀 -noconfig.cmake

建议的更改

一般来说,我建议有源代码树、构建树和安装树。下面发布的文件采用以下布局:

./build.sh

./FooBarLib/FooBarLibConfig.cmake.in
./FooBarLib/CMakeLists.txt
./FooBarLib/foobar.cpp
./FooBarLib/foobar.h

./FooBarLib-build

./FooBarLib-install

./useFoo/CMakeLists.txt
./useFoo-build
  • build.sh
#!/bin/bash

set -xeu
set -o pipefail

script_dir=$(cd $(dirname $0) || exit 1; pwd)

project_name=FooBarLib
archive_name=${project_name}

# cleanup ${project_name}-build
cd $script_dir
rm -rf ${project_name}-build
mkdir ${project_name}-build
cd ${project_name}-build

# configure, build and package ${project_name}
cmake ../${project_name}
make
make package # equivalent to running "cpack -G TGZ" and "cmake -G RPM"

# extract ${project_name} archive
cd $script_dir
rm -rf ${project_name}-install
mkdir ${project_name}-install
cd ${project_name}-install
tar -xvzf ../${project_name}-build/${archive_name}-1.2.3.tar.gz

# cleanup useFoo-build
cd $script_dir
rm -rf useFoo-build
mkdir useFoo-build
cd useFoo-build

cpack_install_prefix=/opt

# configure useFoo
cmake -D${project_name}_DIR=$script_dir/${project_name}-install${cpack_install_prefix}/lib/cmake/${project_name}/ ../useFoo

cat foobar-gen

# display content of RPM. If command "rpmbuild" is available, RPM package is expected.
if command -v rpmbuild &> /dev/null; then
  rpm -qlp $script_dir/${project_name}-build/${archive_name}-1.2.3.rpm
fi
  • FooBarLib/CMakeLists.txt
cmake_minimum_required(VERSION 3.13)

project(FooBarLib VERSION 1.2.3)

if(UNIX AND NOT APPLE)
  set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib:$ORIGIN/")
endif()

#------------------------------------------------------------------------------
# Set a default build type if none was specified
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to 'Release' as none was specified.")
  set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
  mark_as_advanced(CMAKE_BUILD_TYPE)
  # Set the possible values of build type for cmake-gui
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

#------------------------------------------------------------------------------
# This variable controls the prefix used to generate the following files:
#  <export_config_name>ConfigVersion.cmake
#  <export_config_name>Config.cmake
#  <export_config_name>Targets.cmake
# and it also used to initialize FOOBARLIB_INSTALL_CONFIG_DIR value.
set(export_config_name ${PROJECT_NAME})

#------------------------------------------------------------------------------
if(NOT DEFINED FOOBARLIB_INSTALL_INCLUDE_DIR)
  set(FOOBARLIB_INSTALL_INCLUDE_DIR include)
endif()

if(NOT DEFINED FOOBARLIB_INSTALL_BIN_DIR)
  set(FOOBARLIB_INSTALL_BIN_DIR bin)
endif()

if(NOT DEFINED FOOBARLIB_INSTALL_LIBRARY_DIR)
  set(FOOBARLIB_INSTALL_LIBRARY_DIR lib)
endif()

if(NOT DEFINED FOOBARLIB_INSTALL_CONFIG_DIR)
  set(FOOBARLIB_INSTALL_CONFIG_DIR ${FOOBARLIB_INSTALL_LIBRARY_DIR}/cmake/${export_config_name})
endif()

#------------------------------------------------------------------------------
set(headers
  foobar.h
  )

# Install rule for headers
install(
  FILES ${headers}
  DESTINATION ${FOOBARLIB_INSTALL_INCLUDE_DIR}
  COMPONENT Development
  )

#------------------------------------------------------------------------------
add_library(foobar SHARED
  foobar.cpp
  )

target_include_directories(foobar
  PUBLIC
    $<BUILD_INTERFACE:${FooBarLib_SOURCE_DIR}>
    $<INSTALL_INTERFACE:${FOOBARLIB_INSTALL_INCLUDE_DIR}>
  )

install(
  TARGETS foobar
  EXPORT ${export_config_name}Targets
  ARCHIVE DESTINATION ${FOOBARLIB_INSTALL_LIBRARY_DIR} COMPONENT Development
  LIBRARY DESTINATION ${FOOBARLIB_INSTALL_LIBRARY_DIR} COMPONENT RuntimeLibraries
  RUNTIME DESTINATION ${FOOBARLIB_INSTALL_BIN_DIR} COMPONENT RuntimeLibraries
  )

#------------------------------------------------------------------------------
# Configure <export_config_name>ConfigVersion.cmake common to build and install tree
include(CMakePackageConfigHelpers)
set(config_version_file ${PROJECT_BINARY_DIR}/${export_config_name}ConfigVersion.cmake)
write_basic_package_version_file(
  ${config_version_file}
  VERSION "${FooBarLib_VERSION}"
  COMPATIBILITY ExactVersion
  )

#------------------------------------------------------------------------------
# Export '<export_config_name>Targets.cmake' for a build tree
export(
  EXPORT ${PROJECT_NAME}Targets
  FILE "${CMAKE_CURRENT_BINARY_DIR}/${export_config_name}Targets.cmake"
  )

# Configure '<export_config_name>Config.cmake' for a build tree
set(build_config ${CMAKE_BINARY_DIR}/${export_config_name}Config.cmake)
configure_package_config_file(
  ${export_config_name}Config.cmake.in 
  ${build_config}
  INSTALL_DESTINATION "${PROJECT_BINARY_DIR}"
  )

#------------------------------------------------------------------------------
# Export '<export_config_name>Targets.cmake' for an install tree
install(
  EXPORT ${export_config_name}Targets
  FILE ${export_config_name}Targets.cmake
  DESTINATION ${FOOBARLIB_INSTALL_CONFIG_DIR}
  )

set(install_config ${PROJECT_BINARY_DIR}/CMakeFiles/${export_config_name}Config.cmake)
configure_package_config_file(
  ${export_config_name}Config.cmake.in 
  ${install_config}
  INSTALL_DESTINATION ${FOOBARLIB_INSTALL_CONFIG_DIR}
  )

# Install config files
install(
  FILES ${config_version_file} ${install_config}
  DESTINATION "${FOOBARLIB_INSTALL_CONFIG_DIR}"
  )

#------------------------------------------------------------------------------
# Generate package

set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0)
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")

# Setting this variable also impacts the layout of TGZ.
set(CPACK_PACKAGING_INSTALL_PREFIX "/opt")

# Setting CPACK_SOURCE_* and CPACK_GENERATOR allow to have "make package" generates
# the expected archive.

# Disable source generator enabled by default
set(CPACK_SOURCE_TBZ2 OFF CACHE BOOL "Enable to build TBZ2 source packages" FORCE)
set(CPACK_SOURCE_TGZ  OFF CACHE BOOL "Enable to build TGZ source packages" FORCE)
set(CPACK_SOURCE_TZ OFF CACHE BOOL "Enable to build TZ source packages" FORCE)

# Select generators
if(UNIX AND NOT APPLE)
  set(CPACK_GENERATOR "TGZ")
  find_program(RPMBUILD_PATH rpmbuild)
  if(RPMBUILD_PATH)
    list(APPEND CPACK_GENERATOR "RPM")
  endif()
elseif(APPLE)
  # ...
endif()

include(CPack)
  • FooBarLib/FooBarLibConfig.cmake.in
@PACKAGE_INIT@

set(export_config_name "@export_config_name@")

set_and_check(${export_config_name}_TARGETS "${CMAKE_CURRENT_LIST_DIR}/${export_config_name}Targets.cmake")

include(${${export_config_name}_TARGETS})
  • useFoo/CMakeLists.txt
cmake_minimum_required(VERSION 3.13)

project(useFoo VERSION 1.2.3)

find_package(FooBarLib REQUIRED)

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

get_target_property(foobar_INCLUDE_DIR foobar INTERFACE_INCLUDE_DIRECTORIES)
message(STATUS "foobar_INCLUDE_DIR=${foobar_INCLUDE_DIR}")

get_target_property(imported_location foobar IMPORTED_LOCATION_RELEASE)
get_filename_component(foobar_LIBRARY_DIR ${imported_location} DIRECTORY)
message(STATUS "foobar_LIBRARY_DIR=${foobar_LIBRARY_DIR}")

build.sh 的输出

./build.sh 
+ set -o pipefail
+++ dirname ./build.sh
++ cd .
++ pwd
+ script_dir=/tmp/stackoverflow-56135785-answer
+ project_name=FooBarLib
+ archive_name=FooBarLib
+ cd /tmp/stackoverflow-56135785-answer
+ rm -rf FooBarLib-build
+ mkdir FooBarLib-build
+ cd FooBarLib-build
+ cmake ../FooBarLib
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Setting build type to 'Release' as none was specified.
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/stackoverflow-56135785-answer/FooBarLib-build
+ make
Scanning dependencies of target foobar
[ 50%] Building CXX object CMakeFiles/foobar.dir/foobar.cpp.o
[100%] Linking CXX shared library libfoobar.so
[100%] Built target foobar
+ make package
[100%] Built target foobar
Run CPack packaging tool...
CPack: Create package using TGZ
CPack: Install projects
CPack: - Run preinstall target for: FooBarLib
CPack: - Install project: FooBarLib
CPack: Create package
CPack: - package: /tmp/stackoverflow-56135785-answer/FooBarLib-build/FooBarLib-1.2.3.tar.gz generated.
CPack: Create package using RPM
CPack: Install projects
CPack: - Run preinstall target for: FooBarLib
CPack: - Install project: FooBarLib
CPack: Create package
-- CPackRPM:Debug: Using CPACK_RPM_ROOTDIR=/tmp/stackoverflow-56135785-answer/FooBarLib-build/_CPack_Packages/Linux/RPM
CPackRPM: Will use GENERATED spec file: /tmp/stackoverflow-56135785-answer/FooBarLib-build/_CPack_Packages/Linux/RPM/SPECS/foobarlib.spec
CPack: - package: /tmp/stackoverflow-56135785-answer/FooBarLib-build/FooBarLib-1.2.3.rpm generated.
+ cd /tmp/stackoverflow-56135785-answer
+ rm -rf FooBarLib-install
+ mkdir FooBarLib-install
+ cd FooBarLib-install
+ tar -xvzf ../FooBarLib-build/FooBarLib-1.2.3.tar.gz
opt/
opt/include/
opt/include/foobar.h
opt/lib/
opt/lib/libfoobar.so
opt/lib/cmake/
opt/lib/cmake/FooBarLib/
opt/lib/cmake/FooBarLib/FooBarLibTargets.cmake
opt/lib/cmake/FooBarLib/FooBarLibTargets-release.cmake
opt/lib/cmake/FooBarLib/FooBarLibConfigVersion.cmake
opt/lib/cmake/FooBarLib/FooBarLibConfig.cmake
+ cd /tmp/stackoverflow-56135785-answer
+ rm -rf useFoo-build
+ mkdir useFoo-build
+ cd useFoo-build
+ cpack_install_prefix=/opt
+ cmake -DFooBarLib_DIR=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/lib/cmake/FooBarLib/ ../useFoo
-- The C compiler identification is GNU 4.8.5
-- The CXX compiler identification is GNU 4.8.5
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- foobar_INCLUDE_DIR=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/include
-- foobar_LIBRARY_DIR=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/lib
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/stackoverflow-56135785-answer/useFoo-build
+ cat foobar-gen
<TARGET_FILE:foobar>=/tmp/stackoverflow-56135785-answer/FooBarLib-install/opt/lib/libfoobar.so
+ command -v rpmbuild
+ rpm -qlp /tmp/stackoverflow-56135785-answer/FooBarLib-build/FooBarLib-1.2.3.rpm
/opt
/opt/include
/opt/include/foobar.h
/opt/lib
/opt/lib/cmake
/opt/lib/cmake/FooBarLib
/opt/lib/cmake/FooBarLib/FooBarLibConfig.cmake
/opt/lib/cmake/FooBarLib/FooBarLibConfigVersion.cmake
/opt/lib/cmake/FooBarLib/FooBarLibTargets-release.cmake
/opt/lib/cmake/FooBarLib/FooBarLibTargets.cmake
/opt/lib/libfoobar.so

【讨论】:

  • 我只生成了一个 Targets.cmake 文件。没有 FoobarTargets.cmake,只有 FoobarLibTargets.cmake。这里的混淆可能来自我们使用包含 lib 的项目名称。所以共享库项目是 FoobarLib 而不是 Foobar。这不仅仅是匈牙利符号,而是用于区分 FoobarApi 和实现它的 FoobarLib 的服务器。
  • 如果我将 CPACK_PACKAGING_INSTALL_PREFIX 设置为相对路径,例如设置(CPACK_PACKAGING_INSTALL_PREFIX “opt/foobar”)。我得到:/home/brucea/Downloads/cmake-3.9.0/Modules/CPackRPM.cmake:1023(文件)处的 CMake 错误:必须将文件 RELATIVE_PATH 传递到目录的完整路径:opt/rtm 调用堆栈(最近首先调用):/home/brucea/Downloads/cmake-3.9.0/Modules/CPackRPM.cmake:1875 (cpack_rpm_prepare_relocation_paths) /home/brucea/Downloads/cmake-3.9.0/Modules/CPackRPM.cmake:2747 (cpack_rpm_generate_package)
  • 这是疏忽,你是对的,CPACK_PACKAGING_INSTALL_PREFIX 应该是绝对路径。我会相应地更新答案。
  • 使用FoobarLib 代替Foobar 不是问题。在我提供的 CMakeLists.txt 中,您可以通过将 FOOBAR 替换为 FOOBARLIB 并将 foobar 替换为 foobarlib 来实现。我会相应地更新答案。
  • 答案已更新,连同更改摘要,调用“make package”时也会生成一个RPM包。调用“build.sh”后,RPM包的内容也会显示出来。
【解决方案2】:

只有在检测了 cmake 本身的来源之后,我才终于能够追踪到这一点。

export 和 install 命令都能够为目标生成 cmake 文件。 导出命令例如:

export(EXPORT foobarLibTargets
       FILE "${CMAKE_CURRENT_BINARY_DIR}/foobarLibTargets.cmake")

创建一个引用构建树的 Targets.cmake。

安装命令例如:

install(EXPORT foobarLibTargets
        FILE foobarTargets.cmake
        DESTINATION lib/cmake)

创建一个引用可重定位安装位置的 Targets.cmake。

这实质上就是@J-Christophe 所说的安装了两个文件但拾取了错误的文件的意思。

我错误地认为 install 命令只负责安装文件,而 export 命令只负责生成文件。

documentation 现在有意义了

导出(导出 [命名空间] [文件])

此命令创建的文件特定于构建树,并且 永远不应该安装。查看 install(EXPORT) 命令导出 安装树中的目标。

不再需要我以前的解决方法。 作为参考,这是在包的 Config.cmake 中明确设置正确的位置,如下所示:

set(FOOBAR_VERSION @VERSION@)

@PACKAGE_INIT@

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

# workaround - correct absolute path in the above
# this shouldn't be necessary!
set_target_properties(foobar PROPERTIES
                      IMPORTED_LOCATION_NOCONFIG  "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so"
)

【讨论】:

  • 你拯救了我的一天!谢谢!
【解决方案3】:

这里的大多数解决方案都具有误导性。设计就是这样工作的:https://github.com/Kitware/CMake/blob/f46c67de0e16293a40bbbade18aa7cee9edb02b0/Source/cmExportInstallFileGenerator.cxx#L184-L192

因此,如果install(EXPORT ...) 语句中的DESTINATION 是绝对路径,则在导出的包配置文件中将其硬编码为绝对路径。否则,使用_IMPORT_PREFIX动态生成路径。

【讨论】:

    猜你喜欢
    • 2023-01-25
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    相关资源
    最近更新 更多