【问题标题】:How to correctly link static library build and installed previously如何正确链接先前构建和安装的静态库
【发布时间】:2023-01-24 04:08:18
【问题描述】:

有一个名为 revolta 的静态库正在构建,然后安装到 sysroot 中:

set( CMAKE_INSTALL_PREFIX <path to sysroot> )

# ReVolta c++ library name
set( TARGET_LIBREVOLTA "revolta" )

add_library( ${TARGET_LIBREVOLTA} STATIC )

target_include_directories( ${TARGET_LIBREVOLTA}
PUBLIC
    # Once the librevolta targets are being exported, this include directory in which the lib is installed is used
    $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
PRIVATE
    # Include directory used privately just to build the library itself
    $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>
)

target_sources( ${TARGET_LIBREVOLTA}
PUBLIC 
    ...
)

之后,一旦构建了 librevolta,就会使用以下命令将其安装到系统根目录中:

# Install all the revolta headers into include directory and copy the built library
install( TARGETS ${TARGET_LIBREVOLTA} EXPORT ${TARGET_LIBREVOLTA}
    FILE_SET HEADERS    DESTINATION "${CMAKE_INSTALL_PREFIX}/include"
    ARCHIVE             DESTINATION "${CMAKE_INSTALL_PREFIX}/lib"
)

和连接的自定义命令:

# Once the librevolta is built, install it to the sysroot as specified by 'install()' commands
add_custom_command( TARGET ${TARGET_LIBREVOLTA} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS --install . )

到目前为止,一切都很好。这按预期工作,一旦 CMake 构建了“revolta”目标,它就会构建并安装到使用 ${CMAKE_INSTALL_PREFIX} 安装的 sysroot 中。

我的问题是,一旦我尝试将目标添加为其他 lib/可执行文件中的链接目标,它就会以某种方式自动将 librevolta 源路径包含到 include 中,并使用构建目录中的相对路径而不是安装到 sysroot 中的路径链接库在 librevolta 构建之后的步骤中执行。

其他一些库/可执行文件:

target_link_libraries( ${APP_EXECUTABLE}
PRIVATE
    revolta
)

构建完成后,包含路径 -I/home/martin/git/revolta/source/librevolta 被添加(源位置),即使它在上面的片段中被声明为 PRIVATE:

PRIVATE
        # Include directory used privately just to build the library itself
        $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}>

并且只有${CMAKE_INSTALL_PREFIX}/include 是公开的...

此外,该库是从构建树中获取的,而不是从它的安装位置获取的:

../../librevolta/librevolta.a

代替

/home/martin/git/revolta/sysroot/lib/librevolta.a

您能否建议我如何正确设置 revolta 目标,使其正确使用其源代码来构建自身,但一旦在其他地方使用,它会从同一位置(尊重标准位置)提供 sysroot 安装的标头和构建的库?

暗示:我还尝试从应用程序中完全删除 revolta 目标,指定仅使用 sys root(gcc 选项 --sysroot=/home/martin/git/revolta/sysroot),它工作正常,正确的标头和 lib 被使用但是一旦 librevolta 未构建和安装,目标不会在应用程序构建之前运行,因为那时没有定义依赖关系......

【问题讨论】:

    标签: cmake static-linking


    【解决方案1】:

    TL;DR:您需要执行此处所做的操作:

    How to create a ProjectConfig.cmake file


    我发现这些 CMakeLists.txt 文件存在一些问题,但它们与您的问题无关,因为如果我正确理解您在这里尝试做什么,那么就没有问题,并且可以按预期使用。

    让我澄清一下:

    • 您有一个库项目,它有自己的CMakeLists.txt,您在其中定义了目标revolta
    • 您有一个可执行项目,它有自己的CMakeLists.txt,您可以在其中定义可执行目标然后添加 revolta 目标通过add_subdirectory()target_link_libraries(my_executable revolta)

    如果是这样的话,那就太糟糕了:

    # Once the librevolta is built, install it to the sysroot as specified by 'install()' commands
    add_custom_command( TARGET ${TARGET_LIBREVOLTA} POST_BUILD COMMAND ${CMAKE_COMMAND} ARGS --install . )
    

    强制你的构建自动安装这个库不是可行的方法(例如,你首先需要提升权限来构建它,因为这个命令会带来安全风险)。

    话虽如此,正在发生的事情非常好,因为从 my_executable's CMakeLists.txt 的角度来看,您仍在构建,即您使用 BUILD_INTERFACE。然而,这是您不想做的事情。


    相反,您想要做的是:

    revoltaConfig.cmake 文件创建生成器文件。为此,我将向您推荐本教程:

    How to create a ProjectConfig.cmake file

    在你创建这样的文件之后,即在构建和安装revolta之后。您还将(在此过程中)创建一个 revoltaConfig.cmake 文件。这可以帮助您通过 find_package(revolta) 填充 my_executable 项目。

    以上可能是您感兴趣的内容。

    生成器表达式您用来区分BUILD_INTERFACEINSTALL_INTERFACE 主要用于头文件位置(或其他链接库)。因为当您构建库时,头文件的结构可能与您安装时的结构不同(正如您已经知道的那样)。因此在你的CMakeLists.txt 中工作得很好,因为当你考虑它时:

    • 您不想将更改复制到您的库文件(到安装目录中)只是为了在您的可执行文件中测试正在进行的开发(功能/错误修复)。

    • 在可执行文件的构建过程中,如果您构建另一个目标未安装反而正在建设.而且您很可能将其添加为内置目标。

    所以总结一下这里最有可能发生的事情(使用你的旧CMakeLists.txt)是

    • 当您开始构建通过add_subdirectory 将目标库添加为依赖项的可执行文件时,您正在隐式使用BUILD_INTERFACE,因为您正在构建。
    • 如果你当时安装可执行文件和库它会再次使用正确的安装路径,即你会隐式开始使用INSTALL_INTERFACE

    你可以在没有 projectConfig 文件的情况下使用相同的生成器表达式来破解它,方法是将它们混合起来,但我不推荐它,因为如果不事先执行一些奇怪的步骤,CMakeLists.txt 将无法工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-08-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多