【问题标题】:How can I link static libraries defined in CMake subprojects to targets in other subprojects?如何将 CMake 子项目中定义的静态库链接到其他子项目中的目标?
【发布时间】:2015-03-03 16:31:46
【问题描述】:

我有一个大型的模块化 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 模块的 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

【问题讨论】:

    标签: c++ linker cmake static-libraries


    【解决方案1】:

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

    【讨论】:

    • 如果您想澄清问题,请考虑发表评论。是的,我正在使用 target_link_libraries,还有什么?
    • 这里没有足够的信息来提供帮助。也许描述您的项目架构、文件夹、您如何将 CMakeLists.txt 用于主项目和子项目。
    • 查看我添加的编辑。根据我的经验,太长的问题会吓跑人们,所以我怀疑这对我有帮助。
    • 嗯,好像挺对的,没有细节,跑起来,不好说。如果链接命令行完全相同,则意味着库不一样。除非由于库路径不同而未找到库,否则您将收到有关未找到库的错误。也许将库与两种架构进行比较,以确保它们内部包含所有符号。
    • 看符号是个好主意,谢谢。我一定会尝试的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-22
    相关资源
    最近更新 更多