CMake: include library dependencies in a static library

后端 未结 2 915
心在旅途
心在旅途 2020-11-29 02:37

I am building a static library in CMake, which is dependent on many other static libraries. I would like them all to be included in the output .lib/.a file,

2条回答
  •  轻奢々
    轻奢々 (楼主)
    2020-11-29 03:02

    I'd like to enhance the other solutions by providing my CMakeLists.txt file that actually works also in terms of building dependencies.

    Solution misusing CMake

    cmake_minimum_required(VERSION 2.8)
    
    add_library(lib1 test1.cpp)
    add_library(lib2 test2.cpp)
    include_directories(${CMAKE_CURRENT_DIR})
    add_executable(mainexec main.cpp)
    target_link_libraries(mainexec combinedLib)  # Important to place before add_custom_target
    
    set(LIBNAME "combinedLib.lib")
    
    add_custom_command(
        OUTPUT ${LIBNAME}
        COMMAND lib.exe /OUT:${LIBNAME} $ $
        DEPENDS lib1 lib2
        COMMENT "Combining libs..."
    )
    
    add_custom_target(combinedLib
        DEPENDS ${LIBNAME}
    )
    

    Note that this solution works so far with Visual Studio but I guess it can be made multi-platform compliant. I can imagine that the following version might work for Unix-based platforms:

    set(LIBNAME "libCombinedLib.a")
    
    add_custom_command(
        OUTPUT ${LIBNAME}
        COMMAND ar -rcT ${LIBNAME} $ $
        DEPENDS lib1 lib2
        COMMENT "Combining libs..."
    )
    

    Note that these solutions somehow misuse CMake as it would complain about a target of type UTILITY (instead of STATIC or SHARED) if you place the target_link_libraries call after the add_custom_target declaration.

    CMake target-declaration-compliant solution

    To make it CMake compliant, you can replace the `target_link_libraries' call by

    target_link_libraries(mainexec ${LIBNAME})
    add_dependencies(mainexec combinedLib)
    

    In my case it is not entirely satisfactory because mainexec has to know about combinedLib although it expects all dependencies to be handled by the target_link_libraries call.

    Alternative solution with less coupling

    Looking a bit further towards imported targets I eventually found a solution that solves my last problem:

    cmake_minimum_required(VERSION 2.8)
    
    add_library(lib1 test1.cpp)
    add_library(lib2 test2.cpp)
    include_directories(${CMAKE_CURRENT_DIR})
    add_executable(mainexec main.cpp)
    
    set(LIBNAME "combinedLib.lib")
    
    add_custom_command(
        OUTPUT ${LIBNAME}
        COMMAND lib.exe /OUT:${LIBNAME} $ $
        DEPENDS lib1 lib2
        COMMENT "Combining libs..."
    )
    
    add_custom_target(combinedLibGenerator
        DEPENDS ${LIBNAME}
    )
    
    add_library(combinedLib STATIC IMPORTED)
    set_property(TARGET combinedLib PROPERTY IMPORTED_LOCATION ${LIBNAME})
    add_dependencies(combinedLib combinedLibGenerator)
    
    target_link_libraries(mainexec combinedLib)
    

    If you intend to modularize the whole add GLOBAL after STATIC IMPORTED to make the imported target globally visible.

    Portable CMake solution

    With the current CMake versions CMake provides full support for transitive dependencies and interface libraries. An interface library can then "link" against other libraries and this interface library can, in turn, be "linked" against. Why quotation marks? While this works good, this actually doesn't create a physical, combined library but rather creates a kind of an alias to the set of "sub-libs". Still this was the solution we eventually needed, which is why I wanted to add it here.

    add_library(combinedLib INTERFACE)
    target_link_libraries(combinedLib INTERFACE lib1 lib2)
    
    target_link_libraries(mainexec combinedLib)
    

    That's it!

提交回复
热议问题