对于可重定位的多平台安装,理想的 cmake 安装目录结构是什么?

What's the ideal cmake installation directory structure for a relocatable multiple platform installation?

本文关键字:安装 结构 cmake 是什么 定位 于可重 平台 理想      更新时间:2023-10-16

CMake-install获取目标目录,通常使用GNUInstallDirs加载目标名称的标准值。例如:

include(GNUInstallDirs)
install(TARGETS Foo
EXPORT Foo
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

然而,它并没有为不同的平台或体系结构提供不同的构建路径。我一直在通过CMAKE_INSTALL_PREFIX安装到我项目中的一个特定于平台的文件夹中,如下所示:

CMAKE_INSTALL_PREFIX=dist/${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}

不过这也有一些问题:

  • 它复制了跨平台相同的include
  • 如果我将不同的平台安装到同一个根目录,但更改了lib目录,cmake将无法在lib/non/standard/path/cmake/FooConfig.cmake中找到cmake配置目标
  • 模块模式搜索也不能正确地找到库,这在进行模块模式搜索时是有问题的。如果库碰巧也有一个cmake模块,该模块要求每个find_package都必须指定"CONFIG",这开始变得很奇怪,尤其是当第三方库被告知要将此安装目录视为公共依赖项时,并且不要在find_packup中指定CONFIG,因为他们为什么要这样做

我正在寻找一种可以与find_package模块模式和配置模式配合使用的结构;像这样的东西:

<install_prefix>/
include/
foo/
foo.h
lib/
<PLAT x ARCH x CONFIG>/
cmake/
foo/
FooConfig.cmake
libFoo.a

目标是:

  • libs可以针对不同的平台、体系结构和配置进行联合安装
  • 可以共享包含
  • 查找include应该适用于典型的模块模式搜索
  • 应该只使用vanilla find_package(Foo REQUIRED),但适用于适当的平台和arch

考虑到我在这里安装的大多是第三方库,如果这可以通过重写GNUInstallDirs中的vars来完成,那么它可能适用于许多库。我想剩下的要么必须编辑,要么我放弃,使用单独的安装目录,包括平台和拱门。

我会尽我所能发布,也许它会很有用。如果有人有遗漏的部分,我会更新。

描述搜索顺序的文档如下:https://cmake.org/cmake/help/v3.12/command/find_package.html?highlight=%3Cprefix%3E

有相当多的支持排列,所以我将从消除一些开始:

  • 忽略Apple的变体,因为这是针对框架的
  • 忽略仅限Windows的路径,因为它对于任何其他平台来说都不是真正的惯用路径
  • 最后,每个脚本都有与cmake脚本所在位置相关的变体。我会选择.../cmake/<name>*/风格

这留下了(**额外的空间以显示相似性):

<prefix>/        (lib/<arch>|lib*|share)/cmake/<name>*/         (U)
<prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/         (W/U)

文档指出,某些搜索路径适用于某些平台,但从技术上讲,我认为所有的搜索路径都已尝试过。这只是平台的惯用语问题。因此,您不能使用不同的风格作为平台的区别。事实上,这应该意味着Unix选项对Windows也是有效的。

正如您在上面看到的,Windows友好Unix格式的唯一区别是名称的额外前缀。两者都是有效的选择,所以现在我只参考Unix风格,因为它符合我的偏好。最后,我并不真正关心"共享"文件夹,因为我们谈论的是C/C++库。

所以最后我们来看看这两个选择:

<prefix>/lib/<arch>/cmake/<name>*/
<prefix>/lib*/cmake/<name>*/

选项1:多拱形

如果设置了CMAKE_LIBRARY_ARCHITECTURE变量,则会启用具有lib/<arch>的路径。CMAKE_<LANG>_LIBRARY_ARCHITECTURE状态:

如果<LANG>编译器将特定于体系结构的系统库搜索目录,如<prefix>/lib/<arch>这个变量包含<arch>名称(如果CMake检测到)。

我知道这是专门针对某些支持multiarch的发行版的,并且是自动设置的。然而,我不太清楚cmake是否可以很容易地利用这一点来实现这里的目标;在cmake中,你会设置什么来控制它?在多体系系统上,Foo和Bar图书馆可能看起来像:

<prefix>/lib/x86_64-linux-gnu/
foo-1.1/
cmake/FooConfig.cmake
bar/
cmake/BarConfig.cmake
foo-1.1.so
foo-1.1.lib
foo-1.1.dll
foo-1.1.dylib
bar.so
bar.lib
bar.dll
bar.dylib

如果我们可以控制multiarch值是多少,这个选项可以很容易地用于其他平台,如:Darwin_x86_64、Windows_x86_64等。它可能与find_package模块模式兼容,在该模式下可以找到所有includes,而不需要配置模式重定向到一些非标准目录。

选项2:库变体

部分解决方案是保持平台在前缀上完全分离,但至少64位和32位体系结构可以通过拆分库来组合。

lib*包括值lib64lib32libx32lib中的一个或多个(按顺序搜索)。

  • 如果FIND_LIBRARY_USE_LIB64_PATHS属性设置为TRUE
  • 如果FIND_LIBRARY_USE_LIB32_PATHS属性设置为TRUE
  • 如果FIND_LIBRARY_USE_LIBX32_PATHS属性设置为TRUE
  • 始终搜索库路径

这至少在一定程度上有所帮助。我会继续使用lib作为64位,然后只使用lib32来满足32位的需求。

如果您希望用户将一些标准目录设置为CMAKE_PREFIX_PATH,如

/usr/local # installation prefix

但是您的项目会将东西安装到非标准的、特定于平台的子目录中,比如

/usr/local/linux/x86/ # actual root directory where things are installed

您可以将FooConfig.cmake放入标准子目录:

/usr/local/lib/FooConfig.cmake

但是编写它,以便它从特定于平台的目录中搜索适当的.cmake

# File: FooConfig.cmake
# Location: lib/
#
# This is platform-independent script.
#
# Redirect configuration to the platform-specific script <system>/<cpu>/lib/FooConfig.cmake.
include(${CMAKE_CURRENT_LIST_DIR}/../${CMAKE_SYSTEM_NAME}/${CMAKE_SYSTEM_PROCESSOR}/lib/FooConfig.cmake)

特定于平台的*Config.cmake脚本可以用通常的方式编写。

所以,如果用户要写

find_package(Foo)

在为Linux/x86设置的环境中,它将为该平台设置导入的目标。