You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CMake构建依赖自定义库的复杂项目:链接失败问题排查及结构评估

问题描述

我试图创建一个生成单一可执行文件的项目,项目包含两个依赖同一接口库的BHV库和HAL库,项目结构如下:

.
├── BHV
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libBHV_Library.so
│   ├── Makefile
│   └── sources
├── HAL
│   ├── check_libraries.cmake
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libHAL_Library.so
│   ├── Makefile
│   └── sources
├── Interface
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libInterface_Library.a
│   ├── Makefile
│   └── sources
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── main.cpp
├── Makefile
├── README.md

目前无法将各库正确连接,执行检查时持续收到“库未找到”的提示。

Interface库的CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(Interface_Library)

#requires at least C++17
set(CMAKE_CXX_STANDARD 17)


# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")

# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")

# Add main.cpp to the project
add_library(Interface_Library STATIC ${SOURCES} ${HEADERS})

HAL库的CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(HAL_Library)

# requires at least C++17
set(CMAKE_CXX_STANDARD 17)

################################### DIR_MANAGMENT #########################################

# Get the parent directory
get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)

#Set the directory of the parent file as the current directory
set(CMAKE_CURRENT_LIST_DIR ${PARENT_DIR})

message("MYPROJECT_DIR directory: ${CMAKE_CURRENT_LIST_DIR}")

################################### HAL_LIB #########################################

# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")

# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")

# Add main.cpp to the project
add_library(HAL_Library SHARED ${SOURCES} ${HEADERS})

################################### INTERFACE_LIB #########################################

target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Interface)

# Link the Interface_Library into the HAL_Library
target_link_libraries(HAL_Library Interface_Library)

# check if libraries were included
set(TARGET_NAME HAL_Library)
include(check_libraries.cmake)

检查库的check_libraries.cmake

# Get a list of referenced libraries
get_target_property(LINK_LIBS ${TARGET_NAME} LINK_LIBRARIES)

# Print the list of referenced libraries
message("Odkazované knihovny: ${LINK_LIBS}")

# Verify that libraries are available on the system
foreach(LIB ${LINK_LIBS})
    execute_process(COMMAND ldd $<TARGET_FILE:${TARGET_NAME}> | grep ${LIB}
                    RESULT_VARIABLE res
                    OUTPUT_QUIET ERROR_QUIET)
    if(res EQUAL "0")
        message("Library ${LIB} was successfully linked with ${TARGET_NAME}")
    else()
        message(FATAL_ERROR "Error: Library ${LIB} not found.")
    endif()
endforeach()

问题分析与解决

1. 核心错误:静态库无法通过ldd检测

Interface是静态库(.a文件),静态库在链接时会被直接嵌入到目标文件(这里是HAL的.so)中,不会成为动态依赖。而ldd工具只能检测动态链接库的依赖关系,所以用ldd检查静态库的存在本身就是错误逻辑,这是你收到“库未找到”提示的根本原因。

修复check_libraries.cmake

修改检查逻辑,跳过静态库的ldd检测,或者只针对动态库做检查:

# Get a list of referenced libraries
get_target_property(LINK_LIBS ${TARGET_NAME} LINK_LIBRARIES)

# Print the list of referenced libraries
message("Odkazované knihovny: ${LINK_LIBS}")

# Verify that libraries are available on the system
foreach(LIB ${LINK_LIBS})
    # 获取库类型,判断是否为静态库
    get_target_property(LIB_TYPE ${LIB} TYPE)
    if(LIB_TYPE STREQUAL "STATIC_LIBRARY")
        message("Static library ${LIB} does not require dynamic linking check")
        continue()
    endif()
    
    execute_process(COMMAND ldd $<TARGET_FILE:${TARGET_NAME}> | grep ${LIB}
                    RESULT_VARIABLE res
                    OUTPUT_QUIET ERROR_QUIET)
    if(res EQUAL "0")
        message("Library ${LIB} was successfully linked with ${TARGET_NAME}")
    else()
        message(FATAL_ERROR "Error: Library ${LIB} not found.")
    endif()
endforeach()

2. HAL库CMake中的目录操作错误

你手动修改了CMAKE_CURRENT_LIST_DIR这个CMake内置变量,这会破坏CMake的路径管理逻辑。正确的做法是直接使用PARENT_DIR来引用父目录,不要修改内置变量:

修复HAL的CMakeLists.txt(目录管理部分)

################################### DIR_MANAGMENT #########################################

# Get the parent directory
get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)

# 不要修改CMAKE_CURRENT_LIST_DIR,直接用PARENT_DIR引用父目录
message("MYPROJECT_DIR directory: ${PARENT_DIR}")

同时,链接Interface库时,更可靠的方式是通过add_subdirectory引入,而不是仅指定链接目录:

################################### INTERFACE_LIB #########################################

# 直接引入Interface子项目,CMake会自动处理其目标和依赖
add_subdirectory(${PARENT_DIR}/Interface ${CMAKE_CURRENT_BINARY_DIR}/Interface)

# 链接Interface_Library,此时CMake已知道该目标的所有信息
target_link_libraries(HAL_Library PRIVATE Interface_Library)

# 暴露HAL的头文件路径(如果需要上层项目引用)
target_include_directories(HAL_Library PUBLIC include)

3. 项目结构与根CMake的优化

你的项目结构本身是合理的,但根目录的CMakeLists.txt应该统一管理所有子项目,而不是让每个子库单独构建。根CMakeLists.txt示例:

cmake_minimum_required(VERSION 3.10)
project(MainProject)
set(CMAKE_CXX_STANDARD 17)

# 依次引入所有子库
add_subdirectory(Interface)
add_subdirectory(HAL)
add_subdirectory(BHV)

# 构建主可执行文件
add_executable(MainExec main.cpp)

# 链接HAL和BHV库,CMake会自动传递它们的依赖(包括Interface静态库)
target_link_libraries(MainExec PRIVATE HAL_Library BHV_Library)

这样修改后,整个项目的依赖关系会被CMake清晰管理,避免手动路径操作带来的问题,同时静态库会被正确嵌入到最终的可执行文件中,生成单一可执行文件的目标也能实现。


内容的提问来源于stack exchange,提问作者Vojta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 09:56:21