正确设置已安装软件包的导入cmake目标的位置 [英] correctly set the location of imported cmake targets for an installed package

查看:137
本文介绍了正确设置已安装软件包的导入cmake目标的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to be able to import targets from an installed library but when using:

install(TARGETS
        foobar
        EXPORT foobarLibTargets
        LIBRARY DESTINATION lib)

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

cmake generates a foobarLibTargets.cmake containing an absolute path:

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

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

Such that a build using the imported target from the installation will fail as the path does not exist.

Q我可以让它使用正确的相对位置吗?

这等效于:

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

如果我看另一个功能类似但可行的项目,

If I look at another project which does something similar but works it has:

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






这里有一些重现此问题的示例文件:


Here are some example files that reproduce the issue:

CMakeLists.txt:

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:

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:

foobar.cpp:

#include <iostream>

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

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

useFoo.cmake (a CMakeLists.txt for an example project using the installed library):

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(构建并使用安装包):

build.sh (build and use the installation package):

#!/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

如果我取消对解决方法的评论,它将变成哪种。
是否有避免该解决方法的方法?

Which it becomes if I uncomment the workaround. Is there a way which avoids the workaround?

相关问题-配置文件cmake包中的变量存在奇怪的问题-具有相似的代码,都可以重现问题,并在顶部添加另一个。

The related question - Strange issue with variables in a config-file cmake package - has similar code which both reproduces this issue and adds another one on top.

推荐答案

只有在检测了cmake本身的来源之后,我终于能够对此进行跟踪。

Only after instrumenting the source of cmake itself was I finally able to track this down.

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

The export and install commands are both capable of generating cmake files for targets. The export command e.g.:

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

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

creates a Targets.cmake referencing the build tree.

安装命令,例如:

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

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

creates a Targets.cmake referencing the relocatable install location.

这实际上是@ J-Christophe的意思,它表示已安装了两个文件,而错误的文件被拾取。

This is essentially what @J-Christophe meant by saying that two files were installed and the wrong one was picked up.

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

I had wrongly assumed that the install command was only responsible for installing files and the export command was only responsible for generating them.

文档现在很有意义

export(导出[NAMESPACE] [FILE])

export(EXPORT [NAMESPACE ] [FILE ])

此命令创建的文件特定于生成树和
永远不要安装。请参阅install(EXPORT)命令从安装树中导出
目标。

The file created by this command is specific to the build tree and should never be installed. See the install(EXPORT) command to export targets from an installation tree.

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

The workaround I had previously is no longer necesary. For reference this was to explicitly set the correct location in the package's Config.cmake as 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!
set_target_properties(foobar PROPERTIES
                      IMPORTED_LOCATION_NOCONFIG  "@PACKAGE_LIBRARY_INSTALL_DIR@/libfoobar.so"
)

这篇关于正确设置已安装软件包的导入cmake目标的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆