configure_package_config_file选项INSTALL_DESTINATION有什么用

Ney*_*r87 3 cmake

对于以下CMakeLists.txt文件

\n
cmake_minimum_required(VERSION 3.15)\nproject(Testing)\n\ninclude(CMakePackageConfigHelpers)\nconfigure_package_config_file(FooConfig.cmake.in\n  ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake\n  INSTALL_DESTINATION lib/Goo/dmake\n)\n\ninstall(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake\n        DESTINATION lib/Foo/cmake )\n
Run Code Online (Sandbox Code Playgroud)\n

FooConfig.cmake.in文件

\n
@PACKAGE_INIT@\n\ncheck_required_components(Foo)\n
Run Code Online (Sandbox Code Playgroud)\n

它最终会安装FooConfig.cmakelib/Foo/cmake\xef\xbc\x9a

\n
$ cmake ..\n$ cmake --build .\n$ cmake --install . --prefix ../install/\n$ ls -R ../install/\n../install/:\nlib\n\n../install/lib:\nFoo\n\n../install/lib/Foo:\ncmake\n\n../install/lib/Foo/cmake:\nFooConfig.cmake\n
Run Code Online (Sandbox Code Playgroud)\n

看来无论我为选项设置什么值INSTALL_DESTINATIONconfigure_package_config_file它都不会更改FooConfig.cmake安装目录。但如果我评论INSTALL_DESTINATION lib/Goo/dmake,CMake错误提示

\n
\n

没有为 CONFIGURE_PACKAGE_CONFIG_FILE() 指定 INSTALL_DESTINATION

\n
\n

那么这个INSTALL_DESINATION选项有什么用呢?它的值(具体来说,上面的设置lib/Goo/dmake)实际上会影响什么?

\n
\n

文档:

\n
\n

<path>定的 to必须是将文件安装到的INSTALL_DESTINATION目标位置。FooConfig.cmake

\n
\n

我知道正确的方法是INSTALL_DESTINATION lib/Foo/cmake。但正如我故意设置的那样lib/Goo/dmake,该 FooConfig.cmake文件仍然位于所需的目的地lib/Foo/cmake。那么,为什么这个选项被设计为必须的呢?

\n

Tsy*_*rev 10

函数configure_package_config_file 仅生成指定为第二个参数的文件。此功能既不安装生成的文件,也不影响其安装。因此,它的参数只能影响生成文件的内容。

如果您查看生成的脚本FooConfig.cmake,那么您可以找到类似的行

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
Run Code Online (Sandbox Code Playgroud)

这就是脚本根据文件路径计算安装前缀的方式FooConfig.cmake

例如,当您安装带有前缀的软件包/usr/local并且您的FooConfig.cmake脚本将位于该目录中/usr/local/lib/Foo/cmake时,引用的路径将扩展为/usr/local/lib/Foo/cmake/../../../,对应于/usr/local/.

脚本中的组件数量../等于参数中的组件数量INSTALL_DESTINATION

为什么需要“PACKAGE_PREFIX_DIR”

假设一个包将所有公共标头安装到目录中include/(相对于安装前缀),并且配置脚本需要通过变量将该目录传递给用户FOO_INCLUDE_DIR

最直接的方法是在脚本中编写以下内容:

# FooConfig.cmake.in
...
set(FOO_INCLUDE_DIR @CMAKE_INSTALL_PREFIX@/include)
Run Code Online (Sandbox Code Playgroud)

因此configure_package_config_file将替换真正的安装前缀而不是@CMAKE_INSTALL_PREFIX@.

但是将绝对路径嵌入到配置文件中会阻止程序包被重新定位。因此,一旦安装,该包只能从安装目录中使用,而不能复制到其他地方。

对于可重定位包,配置文件会计算对于配置文件本身路径的所有安装路径,因为它是脚本调用时唯一已知的路径find_package。就像可执行文件可以计算位于该可执行文件附近的文件的路径一样。

如果脚本安装到lib/Foo/cmake/FooConfig.cmake,则包含目录的相对路径将为../../../include,因此可以在该脚本中使用以下分配:

# FooConfig.cmake.in
...
set(FOO_INCLUDE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../include)
Run Code Online (Sandbox Code Playgroud)

因此,当find_package(Foo)执行此脚本时,它将变量CMAKE_CURRENT_LIST_DIR扩展到可能重定位脚本的实际目录。

使用相对路径进行操作需要编码人员的大量关注,因此 CMake 允许自动执行此任务:

# CMakeLists.txt
...
# Path to the include directory in the installation tree
set(INCLUDE_DIR 'include')

configure_package_config_file(FooConfig.cmake.in
  ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake
  INSTALL_DESTINATION lib/Foo/cmake
  # Tell CMake to handle variable `INCLUDE_DIR` as a path
  # under installation tree.
  PATH_VARS INCLUDE_DIR
)
Run Code Online (Sandbox Code Playgroud)
# FooConfig.cmake.in
@PACKAGE_INIT@

# Here we could use `@PACKAGE_INCLUDE_DIR@` as reference
# to variable 'INCLUDE_DIR' set in the CMakeLists.txt.
set_and_check(FOO_INCLUDE_DIR "@PACKAGE_INCLUDE_DIR@")
Run Code Online (Sandbox Code Playgroud)

如果您查看生成的文件,您会发现它@PACKAGE_INCLUDE_DIR@ 被扩展为${PACKAGE_PREFIX_DIR}/include,它使用变量PACKAGE_PREFIX_DIR