cmake 如何正确链接静态库构建和以前安装的静态库

icnyk63a  于 2023-01-26  发布在  其他
关注(0)|答案(1)|浏览(266)

有一个名为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,就使用以下命令将其安装到sys根目录中:

# 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/executable中,它会自动将librevolta源路径包含到include中,并使用build目录中的相对路径链接库,而不是像在librevolta构建之后的步骤中执行的那样安装到sysroot中。
其他一些库/可执行文件:

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根(gcc选项--sysroot=/home/martin/git/revolta/sysroot),它工作正常,使用了正确的标头和lib,但一旦未构建和安装librevolta,则在应用程序构建之前不会运行目标,因为随后未定义依赖项...

kqqjbcuj

kqqjbcuj1#

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

∮ ∮ ∮ ∮
我看到这些CMakeLists.txt文件有一些问题,但它们与您的问题无关,因为如果我正确理解了您在这里尝试做什么,那么就没有问题,它按预期使用。
让我澄清一下:

  • 您有一个库项目,它有自己的CMakeLists.txt,您可以在其中定义目标revolta
  • 您有一个可执行项目,它有自己的CMakeLists.txt,您在其中定义可执行目标**,然后通过add_subdirectory()target_link_libraries(my_executable revolta)添加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的Angular 来看,你仍然在构建,也就是说,你使用的是BUILD_INTERFACE,但这是你不想做的事情。

您要做的是:

revoltaConfig.cmake文件创建生成器文件。为此,我将参考本教程:
How to create a ProjectConfig.cmake file
在你创建了这样的文件之后,也就是在构建和安装revolta之后,你也将(在这个过程中)创建一个revoltaConfig.cmake文件,它可以帮助你通过find_package(revolta)填充my_executable项目。
以上大概是你感兴趣的。
用于区分BUILD_INTERFACEINSTALL_INTERFACE生成器表达式主要用于头文件位置(或其他链接库),因为当您构建库时,头文件的结构可能与安装库时不同(正如您所知),因此在CMakeLists.txt中运行良好,因为当您考虑它时:

  • 您不希望仅仅为了在可执行文件中测试正在进行的开发(特性/错误修复)而将对库文件的更改复制到安装目录中。
  • 在构建可执行文件期间,如果您构建另一个目标,则IT IS NOT INSTALLED而是BEING BUILT。您很可能将其添加为构建目标。

因此,总结一下(使用旧的CMakeLists.txt)这里最可能发生的情况是

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

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

相关问题