cmake: target_link_libraries use static library no

2020-07-01 02:27发布

问题:

Is it possible to tell cmake to link against a static library instead of shared?

At the top of my CMakeLists.txt I have the following configured:

set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})

Later, I add a binary, and tell it to link against tcmalloc in release mode:

target_link_libraries(${BIN_NAME} optimized tcmalloc_minimal)

The resulting makefile links aginst the shared version of tcmalloc:

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

Further proof:

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

Both static and shared versions of tcmalloc exist:

$ 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

Question:

How can I configure cmake to link against the static version of tcmalloc?

回答1:

If you only need to support non-Windows platforms, then this old email from the CMake mailing list from one of the Kitware developers gives the simplest method. In essence, use find_library() to find the location of the actual library, favouring static libraries over shared ones by listing them first in the names to look for. i.e.

find_library(TCMALLOC_LIB NAMES libtcmalloc_minimal.a tcmalloc_minimal)

You would then link to the library found in the usual way:

target_link_libraries(${BIN_NAME} ${TCMALLOC_LIB})

You could get smarter about how you define the static library name if you need to support platforms where a static library is named something other than lib???.a. You would use CMAKE_STATIC_LIBRARY_PREFIX and CMAKE_STATIC_LIBRARY_SUFFIX variables for that.

On Windows, the problem is that you cannot distinguish between a static library and the import library for a DLL, as discussed in this old issue in the Kitware bug tracker. Both have the file extension .lib, so you can't use the extension to work out if a particular file is a static library or not, unlike Unix-based platforms where you can.



回答2:

You can create a helper function which sets CMAKE_FIND_LIBRARY_SUFFIXES at function scope (so therefore doesn't affect the parent scope) which searches for the library in question and sets an output variable with the result

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()

You can then call this function from somewhere in your CMakeLists.txt to populate a variable with the location of the library.

Failure to find it results in a hard failure

find_static_library(tcmalloc_minimal TCMALLOC)

You can then use this variable in your call to target_link_libraries and be sure you're linking against the static version

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

Here you can see the result:

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


回答3:

You have to set your CMAKE_FIND_LIBRARY_SUFFIXES variable in this manner:

set(CMAKE_FIND_LIBRARY_SUFFIXES .a)

because in default CMAKE_FIND_LIBRARY_SUFFIXES there is also .so suffix (and it seems not searching in order of insertion). In order to allow portability other suffixes should be added (see here for default values of CMAKE_FIND_LIBRARY_SUFFIXES on different platforms).



标签: c++ linux cmake