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

时间:2018-06-30 05:59:33

标签: c++ cmake multiplatform

CMake安装会使用目标目录,通常使用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}

但这有一些问题:

  • 它复制了跨平台相同的包含内容。
  • 如果我将不同平台安装到同一根目录但更改了lib目录,则cmake在lib / non / standard / path / cmake / FooConfig.cmake中找不到cmake配置目标
  • 并且模块模式搜索也无法正确找到库,这在完成MODULE模式搜索时会出现问题。如果该库恰好也有一个cmake模块,该模块要求每个find_package必须指定“ CONFIG”,这会变得很奇怪,那么就会发生这种情况,特别是当第3方库被告知要考虑此安装目录的常见依赖性时,并且在find_package中指定CONFIG,因为为什么会这样?

我正在寻找一种与find_package模块模式和config模式一起使用的结构;像这样的东西:

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

目标是:

  • 可以为不同的平台,体系结构和配置共同安装库
  • 包含内容可以共享
  • 发现包含项应在典型的模块模式搜索中起作用
  • 应该只使用vanilla find_package(需要Foo),但要使用适当的平台和拱形结构。

考虑到我将在这里主要安装第三方库,如果可以通过重写GNUInstallDirs中的var来完成,那么它可能适用于许多库。我猜其余的部分要么必须进行编辑,要么我就放弃并使用包含平台和架构的单独安装目录。

2 个答案:

答案 0 :(得分:1)

如果您希望用户将某些标准目录设置为 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设置的环境中,它将为该平台设置导入的目标。

答案 1 :(得分:1)

我会尽可能地发布为止,也许会有用。如果有人遗失物品,我会进行更新。

描述搜索顺序的文档在这里: 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:多体系结构

如果设置了lib/<arch>变量,则启用带有CMAKE_LIBRARY_ARCHITECTURE的路径。 CMAKE_<LANG>_LIBRARY_ARCHITECTURE声明:

  

如果<LANG>编译器将特定于体系结构的格式传递给链接器   系统库搜索目录,例如<prefix>/lib/<arch> this   如果/由CMake检测到,则变量包含<arch>名称。

我知道这是专门针对支持多体系结构的某些发行版的,并且可以自动设置。但是,我不太确定这是否可以通过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模块模式兼容,在该模式下可以找到所有包含项,而无需配置模式以重定向到一些非标准目录。

选项2:lib变体

部分解决方案是使平台在前缀中完全分开,但是至少可以拆分libs来组合至少64位和32位体系结构。

  

lib*包含值lib64lib32libx32lib中的一个或多个   (以该顺序搜索)。

     
      
  • 如果在64位平台上搜索lib64路径,   FIND_LIBRARY_USE_LIB64_PATHS属性设置为TRUE。
  •   
  • 如果在32位平台上搜索lib32的路径,   FIND_LIBRARY_USE_LIB32_PATHS属性设置为TRUE。
  •   
  • 如果平台使用x32 ABI在平台上搜索libx32的路径,   FIND_LIBRARY_USE_LIBX32_PATHS属性设置为TRUE。
  •   
  • 总是搜索lib路径。
  •   

这至少部分有帮助。我将继续使用lib作为64位,然后仅将lib32用于32位需求。