【问题标题】:CMake: Imported libraries as OUTPUT or BYPRODUCTS of another custom command or targetCMake:导入的库作为另一个自定义命令或目标的 OUTPUT 或 BYPRODUCTS
【发布时间】:2015-12-23 15:35:32
【问题描述】:

我想从 ZIP 文件中提取一个静态库并链接到它。

具有以下设置:

add_library(COMSDK_LIB STATIC IMPORTED GLOBAL)
set_property(TARGET COMSDK_LIB PROPERTY IMPORTED_LOCATION "/tmp/lib/libRTSClientSdk.a")

而导入的库正在另一个CMakeLists.txt中使用:

target_link_libraries(mylib COMSDK_LIB)

会不会是导入的库是由另一个add_custom_command或add_custom_target生成的?

我尝试了以下方法,但它确实不工作:

add_custom_command(
    OUTPUT "/tmp/lib/libRTSClientSdk.a"
    COMMAND unzip -x client_sdk.zip -o /tmp
    DEPENDS client_sdk.zip
)

给定的错误信息是:

$ ninja
ninja: error: '/tmp/lib/libRTSClientSdk.a', needed by 'mylib.dll', missing and no known rule to make it

【问题讨论】:

    标签: cmake shared-libraries static-libraries


    【解决方案1】:

    问题是您的自定义命令正在make 步骤期间执行,并且它期望在cmake 执行期间更早提取依赖项。因此,基本上,您需要从 SDK 在在 CMake 规则中或在链接本身期间使用它之前获取该静态库。

    CMake mailing list 中列出了两种可能的解决方案。

    解决方案#1:(在 CMake 端执行)

    重新表述代码 sn-ps 之一,在 CMake 执行期间正在完成下载和解压缩:

    set(CLIENTSDK_ZIP "cliendsdk.zip")
    set(CLIENTSDK_URL "http://example.com/${CLIENTSDK_ZIP}")
    set(CLIENTSDK_LIB "libRTSClientSdk.a")
    set(CLIENTSDK_OUTPUT_DIR "/tmp/sdk/dir")
    
    # Basically just downloading zip file:
    message(STATUS "Downloading ${CLIENTSDK_URL}")
    execute_process(COMMAND wget ${CLIENTSDK_URL}
      WORKING_DIRECTORY ${CLIENTSDK_OUTPUT_DIR}
      RESULT_VARIABLE errno
      ERROR_VARIABLE err)
    
    if (NOT ${errno} EQUAL 0)
      message(ERROR "Failed downloading ${CLIENTSDK_URL}. Code: ${err}")
    endif()
    
    # Extracting downloaded zip file:
    message(STATUS "Extracting ${CLIENTSDK_ZIP})
    execute_process(COMMAND unzip ${CLIENTSDK_ZIP}
      WORKING_DIRECTORY ${CLIENTSDK_OUTPUT_DIR}
      RESULT_VARIABLE errno
      ERROR_VARIABLE err)
    
    if (NOT ${errno} EQUAL 0)
      message(ERROR "Failed extracting ${CLIENTSDK_ZIP}. Code: ${err}")
    endif()
    
    # Importing into CMake scope one library from extracted zip:
    add_library(specific_sdk_lib STATIC IMPORTED)
    set_target_properties(specific_sdk_lib
      PROPERTIES IMPORTED_LOCATION ${CLIENTSDK_OUTPUT_DIR}/lib/${CLIENTSDK_LIB})
    
    # Adding rule for linking to specific static library from extracted zip:
    target_link_libraries(mylib specific_sdk_lib)
    

    解决方案 #2(在 make 端执行):

    # We must include ExternalProject CMake module first!
    include("ExternalProject")
    
    set(CLIENTSDK_URL "http://example.com/clientsdk.zip")
    set(CLIENTSDK_LIB "libRTSClientSdk.a")
    set(CLIENTSDK_PREFIX "3rd_party")
    set(CLIENTSDK_EXTRACTED_DIR
        "${CMAKE_CURRENT_BINARY_DIR}/${CLIENTSDK_PREFIX}/src/DownloadClientSDK/")
    
    ExternalProject_Add("DownloadClientSDK"
        PREFIX ${CLIENTSDK_PREFIX}
        URL "${CLIENTSDK_URL}"
        # Suppress ExternalProject configure/build/install targets:
        CONFIGURE_COMMAND ""
        BUILD_COMMAND ""
        INSTALL_COMMAND "")
    
    add_library(COMSDK_LIB STATIC IMPORTED)
    set_target_properties(COMSDK_LIB PROPERTIES IMPORTED_LOCATION
        ${CLIENTSDK_EXTRACTED_DIR}/${CLIENTSDK_LIB})
    
    # Require all that download/unzip mumbojumbo only for COMSDK_LIB:
    add_dependencies(COMSDK_LIB DownloadClientSDK)
    
    target_link_libraries(my_library COMSDK_LIB)
    

    基本上,CMake 和它的ExternalProject 模块负责(生成正确的make 目标)识别存档格式,解压缩它,如果需要 - 配置,构建和安装。

    【讨论】:

    • 因为我以前将解压缩目标作为其他构建步骤的依赖项,所以在 cmake 执行期间执行下载和解压缩目标对我来说有点妥协(因为它们总是被执行)。但是,在我的情况下就足够了,并且对我有用。非常感谢您的贡献!
    • @dubbaluga 我想通常make step 比cmake step 更频繁地执行。跟踪文件更改就足够了,它可以防止一次又一次地下载有问题的clientsdk.zip。不过,我对ninja 一点也不熟悉(只是意识到您使用的是它而不是make):}
    • @dubbaluga,显然您可以使用ExternalProject_Add() 获得所需的行为。刚刚更新了我的答案:}
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-12
    相关资源
    最近更新 更多