如何将CMake子项目中定义的静态库链接到其他子项目中的目标?

时间:2015-03-03 16:31:47

标签: c++ linker cmake static-libraries

我有一个大型的模块化CMake项目。 一些模块是静态库,一些是可执行文件,可能会也可能不会使用其中一些库。我已经有一个需要/依赖性检查系统,它会停止cmake并告诉用户他是否正在尝试构建可执行文件而不是它所需的库。

该项目按原样编译。我想将其拆分为子项目,即为每个模块的CMakeLists.txt设置project(${module_name})。不幸的是,只要我将这一行插入适当的宏,我就会立即得到链接器错误,即可执行文件无法再看到静态库中定义的符号。

在可执行文件上调用的c ++命令(我碰巧使用gcc 4.8)没有改变,所以其他东西必须是不同的。如何解决这个问题并保留子项目结构?

编辑:根据@ Gerald的评论,附加信息。

项目文件夹结构:

root
 |
 |-bin
 |-lib
 |-cmake(various CMake scripts, added to module path)
 |-third_party
 |-...
 |-CMakeLists.txt
 |-modules(top-level module directory, expanded)
      |
      |-CMakeLists.txt
      |-exec_module_a
      |-exec_module_b
      |-... (other exec modules)
      |-lib_module_a
      |-lib_module_b
      |- ... (other lib modules)
      |-lib_module_N (expanded)
             |
             |-CMakeLists.txt
             |-include/root/module_N (various include files)
             |-src (various source files)
             |-tests

典型叶级CMakeLists.txt的结构(对于lib和exec模块,只有一个arg。到root_add_subproject):

include(RootUtils)

set(module_name ${EXEC_MODULE_A})
#---------------------------CHECK REQUIREMENTS---------------------------------#
root_check_module_requirements(module_name
    BUILD_${LIB_MODULE_A}
    BUILD_${LIB_MODULE_G}
    #...
    WITH_QT
    WITH_THIRD_PARTY_BLAH1
    WITH_THIRD_PARTY_BLAH2
    #...
)
#---------------------------ADD SOURCES AND TARGET-----------------------------#
root_add_subproject(${module_name} executable qt_on)
#---------------------------ADD INCLUDES---------------------------------------#
target_include_directories(${TARGET_NAME} PUBLIC

    #third-party includes
    ${THIRD_PARTY_BLAH1_INCLUDE_DIRS} 
    ${THIRD_PARTY_BLAH1_INCLUDE_DIRS}
    #...

    #module includes
    "${MODULES_DIR}/${LIB_MODULE_A}/include"
    "${MODULES_DIR}/${LIB_MODULE_B}/include"
    #...
)
#---------------------------LINK LIBRARIES-------------------------------------#
target_link_libraries(${TARGET_NAME} PUBLIC

    #third-party libraries
    ${QT5_TARGETS}
    ${THIRD_PARTY_BLAH1_LIBRARIES}
    ${THIRD_PARTY_BLAH2_LIBRARIES}
    #...

    #module libraries
    ${LIB_MODULE_A}
    ${LIB_MODULE_B}
    #...
)
if(UNIX)
    #... link third-party dependencies conditional on platform
endif()
#---------------------------ADD TESTS------------------------------------------#
#SET(BUILD_TESTS FALSE)#comment out to build the local unit tests
root_add_tests(${module_name})

#==============================================================================#

RootUtils.cmake中的相关脚本如下所示:

macro(augmentarium_add_subproject module_name proj_type qt_on)

    if(${qt_on} STREQUAL "qt_on" OR ${qt_on} STREQUAL "YES" OR ${qt_on} STREQUAL "TRUE")
        set(QT_ON TRUE)
    else()
        set(QT_ON FALSE)
    endif()

    #---------------------------DEFINE SUBPROJECT----------------------------------#
    #TODO: fix problems with macro (figure out how to set up library as a subproject w/o destroying linking capability)
    #project(${module_name}) # <------- THIS is the line that causes linker errors

    set(TARGET_NAME ${module_name})
    string(TOUPPER "${TARGET_NAME}" TARGET_NAME_UPPER)

    if(QT_ON)
        set(CMAKE_AUTOMOC ON)
    endif()


    #---------------------------DEFINE SOURCE FILES--------------------------------#
    include_directories(include)
    SET(${TARGET_NAME_UPPER}_TOP_INCLUDE_DIR include/${PROJECT_NAME}/${TARGET_NAME})

    file(GLOB ${TARGET_NAME_UPPER}_CMAKELISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt)

    file(GLOB ${TARGET_NAME_UPPER}_SOURCES src/*.cpp)
    file(GLOB ${TARGET_NAME_UPPER}_HEADERS src/*.h src/*.h.in src/*.hpp src/*.tpp
        ${${TARGET_NAME_UPPER}_TOP_INCLUDE_DIR}/*.h 
        ${${TARGET_NAME_UPPER}_TOP_INCLUDE_DIR}/*.h.in 
        ${${TARGET_NAME_UPPER}_TOP_INCLUDE_DIR}/*.hpp 
        ${${TARGET_NAME_UPPER}_TOP_INCLUDE_DIR}/*.tpp)
    file(GLOB ${TARGET_NAME_UPPER}_TEST_SOURCES  tests/*.cpp)

    if(QT_ON)
        file(GLOB_RECURSE MOC_${TARGET_NAME_UPPER}_SOURCES moc_*.cpp *_automoc.cpp qrc_*.cpp)
        #remove generated moc files
        foreach(FILE_NAME ${MOC_${TARGET_NAME_UPPER}_SOURCES})
            list(REMOVE_ITEM ${TARGET_NAME_UPPER}_SOURCES ${FILE_NAME})
        endforeach()
    endif(QT_ON)


    if(QT_ON)
    #---------------------------ADD UI FILES---------------------------------------#
        file(GLOB ${TARGET_NAME_UPPER}_UI src/*.ui)

        if(BUILD_${TARGET_NAME})
        #this macro doesn't get defined unless QtWidgets is found
            qt5_wrap_ui(${TARGET_NAME_UPPER}_UI_HEADERS ${${TARGET_NAME_UPPER}_UI})
        endif()
    #---------------------------ADD RESOUCE FILES----------------------------------#
        file(GLOB ${TARGET_NAME_UPPER}_RESOURCE_FILES *.qrc)

        if(BUILD_${TARGET_NAME})
            #this macro doesn't get defined unless QtWidgets is found
            qt5_add_resources(${TARGET_NAME_UPPER}_GENERATED_RESOURCES ${${TARGET_NAME_UPPER}_RESOURCE_FILES})
        endif()
    endif(QT_ON)

    #..........................organize source/header files........................#
    source_group("Source Files" FILES ${${TARGET_NAME_UPPER}_SOURCES})
    source_group("Header Files" FILES ${${TARGET_NAME_UPPER}_HEADERS})

    if(QT_ON)
        source_group("Resource Files" FILES ${${TARGET_NAME_UPPER}_RESOURCE_FILES})
        source_group("UI Files" FILES ${${TARGET_NAME_UPPER}_UI})
        source_group("Generated Files" FILES ${${TARGET_NAME_UPPER}_GENERATED_RESOURCES} ${${TARGET_NAME_UPPER}_UI_HEADERS})
    endif()

    #---------------------------ADD TARGET-----------------------------------------#
    set(ALL_${TARGET_NAME_UPPER}_FILES
        ${${TARGET_NAME_UPPER}_CMAKELISTS}
        ${${TARGET_NAME_UPPER}_SOURCES}
        ${${TARGET_NAME_UPPER}_HEADERS}
        ${${TARGET_NAME_UPPER}_RESOURCE_FILES}
        ${${TARGET_NAME_UPPER}_UI}
        ${${TARGET_NAME_UPPER}_GENERATED_RESOURCES}
    )

    if(${proj_type} STREQUAL "executable")
        add_executable(${TARGET_NAME} ${ALL_${TARGET_NAME_UPPER}_FILES})
    elseif(${proj_type} STREQUAL "library")
        add_library(${TARGET_NAME} STATIC ${ALL_${TARGET_NAME_UPPER}_FILES})
    else()
        add_custom_target(${TARGET_NAME} ${ALL_${TARGET_NAME_UPPER}_FILES})
    endif()

endmacro()

如果仍然不够,这里是子项目如何包含在模块级CMakeLists.txt中:

foreach (MODULE_NAME ${MODULES})
    add_subdirectory (${MODULE_NAME})
endforeach()

使用的CMake版本:3.1.3

1 个答案:

答案 0 :(得分:-1)

如何使用CMake管理libs之间的依赖关系?这应该使用TARGET_LINK_LIBRARIES(myexe mylib1 mylib2)来完成