【问题标题】:cmake: target_link_libraries use static library not sharedcmake:target_link_libraries 使用未共享的静态库
【发布时间】:2016-08-13 17:50:24
【问题描述】:

是否可以告诉 cmake 链接到 静态库 而不是 共享

在我的CMakeLists.txt 顶部,我配置了以下内容:

set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})

稍后,我添加了一个二进制文件,并告诉它在发布模式下链接到tcmalloc

target_link_libraries(${BIN_NAME} optimized tcmalloc_minimal)

生成的生成文件链接到tcmalloc 的共享版本:

$ make VERBOSE=1 | grep tcmalloc
/usr/bin/c++ ... -Wl,-Bdynamic ltcmalloc_minimal 

进一步证明:

$ ldd app 
    ...
    libtcmalloc_minimal.so.4 => /usr/local/lib/libtcmalloc_minimal.so.4 (0x00007eff89733000)
    ...

tcmalloc 的静态和共享版本都存在:

$ ls -1 /usr/local/lib/libtcmalloc_minimal*
/usr/local/lib/libtcmalloc_minimal.a
/usr/local/lib/libtcmalloc_minimal_debug.a
/usr/local/lib/libtcmalloc_minimal_debug.la
/usr/local/lib/libtcmalloc_minimal_debug.so
/usr/local/lib/libtcmalloc_minimal_debug.so.4
/usr/local/lib/libtcmalloc_minimal_debug.so.4.2.6
/usr/local/lib/libtcmalloc_minimal.la
/usr/local/lib/libtcmalloc_minimal.so
/usr/local/lib/libtcmalloc_minimal.so.4
/usr/local/lib/libtcmalloc_minimal.so.4.2.6

问题:

如何配置 cmake 以链接 tcmalloc 的静态版本?

【问题讨论】:

    标签: c++ linux cmake


    【解决方案1】:

    您可以创建一个辅助函数,在函数范围 (so therefore doesn't affect the parent scope) 中设置 CMAKE_FIND_LIBRARY_SUFFIXES,该函数搜索相关库并使用结果设置输出变量

    function(find_static_library LIB_NAME OUT)
    
        if (WIN32 OR MSVC)
            set(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
        elseif (UNIX)
            set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
        endif()      
    
        find_library(
            FOUND_${LIB_NAME}_STATIC
            ${LIB_NAME}
            )
    
        if (FOUND_${LIB_NAME}_STATIC)
            get_filename_component(ABS_FILE ${FOUND_${LIB_NAME}_STATIC} ABSOLUTE)
        else()
            message(SEND_ERROR "Unable to find library ${LIB_NAME}")
        endif()
    
        set(${OUT} ${ABS_FILE} PARENT_SCOPE)
    
    endfunction()
    

    然后,您可以从 CMakeLists.txt 中的某个位置调用此函数,以使用库的位置填充变量。

    找不到会导致硬故障

    find_static_library(tcmalloc_minimal TCMALLOC)
    

    然后,您可以在调用 target_link_libraries 时使用此变量,并确保您链接的是静态版本

    target_link_libraries(${BIN_NAME} optimized ${TCMALLOC})
    

    在这里你可以看到结果:

    $ make VERBOSE=1 | grep tcmalloc
    
    /usr/bin/c++ ... /usr/local/lib/libtcmalloc_minimal.a ...
    

    【讨论】:

    • 您需要在 find_library 调用之前添加 `unset(FOUND CACHE)`,否则第二个 find_static_library 将不起作用。
    • @over_optimistic 回复很晚,但我更新了答案以撤消对unset的需要
    • 这是一个很好的答案,但您选择的参数顺序与cmake's built-in find_library() command 不同,这很尴尬。内置顺序是find_library(VAR name),但上面的函数是find_static_library(name VAR)。如果你修正了顺序,那将帮助我们这些盲目查找和替换的懒惰程序员。
    • 这在 OSX 上不起作用
    【解决方案2】:

    如果您只需要支持非 Windows 平台,那么来自 Kitware 开发人员之一的 CMake 邮件列表中的this old email 提供了最简单的方法。本质上,使用find_library() 来查找实际库的位置,通过将静态库列在要查找的名称中,优先使用静态库而不是共享库。即

    find_library(TCMALLOC_LIB NAMES libtcmalloc_minimal.a tcmalloc_minimal)
    

    然后您将链接到以通常方式找到的库:

    target_link_libraries(${BIN_NAME} ${TCMALLOC_LIB})
    

    如果您需要支持静态库名称不是lib???.a 的平台,您可以更明智地定义静态库名称。为此,您将使用 CMAKE_STATIC_LIBRARY_PREFIX 和 CMAKE_STATIC_LIBRARY_SUFFIX 变量。

    在 Windows 上,问题在于您无法区分静态库和 DLL 的导入库,正如 Kitware 错误跟踪器中的 this old issue 中所讨论的那样。两者都有文件扩展名.lib,所以你不能使用扩展名来确定一个特定的文件是否是一个静态库,这与你可以使用的基于 Unix 的平台不同。

    【讨论】:

      【解决方案3】:

      您必须以这种方式设置您的 CMAKE_FIND_LIBRARY_SUFFIXES 变量:

      set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
      

      因为在默认的 CMAKE_FIND_LIBRARY_SUFFIXES 中还有 .so 后缀(而且似乎没有按插入顺序搜索)。为了实现可移植性,应添加其他后缀(请参阅here 了解不同平台上 CMAKE_FIND_LIBRARY_SUFFIXES 的默认值)。

      【讨论】:

      • 那没有用 - 我按照你的建议做了,它仍然链接到共享库。根据docs,该设置仅适用于find_library,不适用于target_link_libraries
      • 是的,它需要使用 find_library。通常我使用 find_library 来查找外部库并将它们存储在 CMake 变量中;然后我使用变量将它们添加到目标库中。
      • 类似这样的东西:stackoverflow.com/questions/14243524/…。然后您需要使用 ${VAR_LIBRARY_NAME} 将库 var 添加到 TARGET_LINK_LIBRARIES。如果遇到问题,请尝试使用消息(STATUS ...)打印通过 find_library 获得的变量,以了解它是否找到了正确的库。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-15
      • 1970-01-01
      • 2021-03-18
      • 1970-01-01
      相关资源
      最近更新 更多