CMake新手求助:构建依赖共享库的静态库及关联可执行文件时出现链接错误
Hey there, let's break down what's going wrong with your CMake setup and fix it step by step. The core issues are related to incorrect dependency handling (using find_library for your own libraries instead of CMake targets) and missing dependency propagation (static libraries don't carry their dependencies automatically). Here's how to fix each part:
Key Issues in Your Current Setup
- You’re using
find_libraryto locate your own built libraries (lib1,lib2), but CMake already tracks these as targets when you useadd_subdirectory—no need to hunt for.afiles manually. - Your
target_include_directorieshas a syntax error:{CMAKE_CURRENT_SOURCE_DIR}should be${CMAKE_CURRENT_SOURCE_DIR}(missing the$sign), so the include paths weren’t being set correctly. - Static libraries don’t embed their dependencies, so you need to use CMake’s
PUBLIC/PRIVATEkeywords to pass dependencies down the chain (e.g., lib1’s dependencies onrt/pthreadneed to be visible to lib2 and your executable). - You’re repeating redundant
find_librarycalls which aren’t necessary.
Corrected CMakeLists Files
1. Root CMakeLists.txt (CMakeLists1.txt)
This one is mostly fine, but we can add a C standard requirement to make it cleaner:
cmake_minimum_required(VERSION 3.14) project(MainApp VERSION 0.1 DESCRIPTION "Main Application CMake compilation project" LANGUAGES C) # Set C standard (adjust to your needs) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) add_subdirectory(lib1) add_subdirectory(lib2) add_subdirectory(executable)
2. lib1/CMakeLists.txt (CMakeLists2.txt)
We’ll clean up redundant calls and use proper dependency propagation:
cmake_minimum_required(VERSION 3.14) project(lib1 VERSION 0.1 DESCRIPTION "lib1 library" LANGUAGES C) # List your source files list(APPEND SRCS source1.c source2.c) # Create static library add_library(lib1 STATIC ${SRCS}) # Link required system libraries (use PRIVATE if lib1's headers don't expose these symbols) target_link_libraries(lib1 PRIVATE rt pthread) # Expose lib1's headers to dependent targets automatically target_include_directories(lib1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
PRIVATEmeansrt/pthreadare only needed for compiling lib1, but their linkage will still be propagated to targets that link lib1 (thanks to CMake’s target system).PUBLIContarget_include_directorieslets other targets (like lib2) automatically find lib1’s headers without hardcoding paths.
3. lib2/CMakeLists.txt (CMakeLists3.txt)
No more find_library for lib1—just use the target directly, and fix the include path syntax:
cmake_minimum_required(VERSION 3.14) project(lib2 VERSION 0.1 DESCRIPTION "lib2 library" LANGUAGES C) list(APPEND SRCS source1.c source2.c) add_library(lib2 STATIC ${SRCS}) # Link lib1 (and automatically get its dependencies: rt/pthread) target_link_libraries(lib2 PRIVATE lib1) # Expose lib2's headers to dependent targets target_include_directories(lib2 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
- We don’t need to re-link
rt/pthreadhere—CMake will pull those in automatically from lib1’s dependency chain. - No need to manually add lib1’s include path anymore, since we linked against the
lib1target (which already exposes its headers viaPUBLIC).
4. executable/CMakeLists.txt (CMakeLists4.txt)
Simplify by only linking lib2—all upstream dependencies (lib1, rt, pthread) will be propagated automatically:
cmake_minimum_required(VERSION 3.14) project(Executable VERSION 0.1 DESCRIPTION "MainApp executable" LANGUAGES C) list(APPEND SRCS source1.c source2.c) add_executable(Executable ${SRCS}) # Link against lib2—all dependencies (lib1, rt, pthread) come along for the ride target_link_libraries(Executable PRIVATE lib2) # Headers from lib1 and lib2 are available via their respective targets target_include_directories(Executable PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
Why This Fixes Your Undefined Symbol Error
The original issue was that when you linked lib1 to lib2 (and lib2 to your executable), the rt/pthread libraries weren’t being included in the final link step. Static libraries don’t store their dependency info, so CMake needs explicit instructions to pass those dependencies down. By using PRIVATE/PUBLIC and linking directly to targets instead of raw .a files, CMake automatically handles the full dependency chain—including linking rt/pthread where needed.
Quick Notes for Cross-Compilation
Since you’re cross-compiling, this target-based approach is even better: CMake uses the cross-compiler’s search paths automatically, so you don’t have to manually specify paths to .a files or system libraries. Your existing cross-compile environment setup should work seamlessly with these changes.
内容的提问来源于stack exchange,提问作者Fulgor3

