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

如何用CMake将Git子模块依赖打包进单个静态.a库?

问题:将SDL依赖与自研代码打包为单个静态库

我正在开发一款基于C语言的图形库Pixelinator,该库依赖SDL2及其生态组件(SDL-TTF、SDL-Mixer、SDL-Image)。已将这些依赖作为Git子模块放入项目的external目录,通过CMakeLists.txt配置构建静态库,但生成的.a文件仅包含自研代码,未纳入SDL相关依赖。现咨询如何通过CMake将所有SDL依赖与自研代码打包为单个静态.a文件。


现有CMake配置代码

external目录下的CMakeLists.txt

set( BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE )

# SDL
set( SDL_LIBC ON CACHE BOOL "" FORCE )
set( SDL_TEST OFF CACHE BOOL "" FORCE )
add_subdirectory(SDL)
target_link_libraries( Pixelinator SDL2::SDL2main SDL2::SDL2-static )

# SDL_image
set( SDL2IMAGE_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2IMAGE_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2IMAGE_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2IMAGE_DEPS_SHARED OFF CACHE BOOL "" FORCE )
add_subdirectory( sdl-image )
target_link_libraries( Pixelinator SDL2_image::SDL2_image-static)

# SDL_ttf
set( SDL2TTF_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2TTF_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2TTF_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2TTF_HARFBUZZ ON CACHE BOOL "" FORCE )
add_subdirectory( sdl-ttf )
target_link_libraries( Pixelinator SDL2_ttf::SDL2_ttf-static )

# SDL_mixer
set( SDL2MIXER_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2MIXER_DEPS_SHARED OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_FLAC OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MOD OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MP3 OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MIDI OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_OPUS OFF CACHE BOOL "" FORCE )
add_subdirectory( sdl-mixer )
target_link_libraries( Pixelinator SDL2_mixer::SDL2_mixer-static )

项目根目录下的CMakeLists.txt

cmake_minimum_required(VERSION 3.21)
cmake_policy(SET CMP0075 NEW)
cmake_policy(SET CMP0091 NEW)
project(Pixelinator VERSION 1.0 DESCRIPTION "A 2D Engine using SDL and C")

set( CMAKE_CXX_STANDARD 11 CACHE STRING "" FORCE )
set( CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE BOOL "" FORCE )

if(NOT CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE Release)
endif()

if(CMAKE_BUILD_TYPE EQUAL Release)
    message("Building Release...")
endif()

set(CMAKE_C_STANDARD 11)

set(CMAKE_CXX_FLAGS "-Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g")
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast")

add_library(Pixelinator STATIC
        ../../Pixelinator/src/engine/audio/sound.c
        ../../Pixelinator/src/engine/config/config.c
        ../../Pixelinator/src/engine/core/core.c
        ../../Pixelinator/src/engine/graphics/bitmap/bitmap.c
        ../../Pixelinator/src/engine/graphics/bitmap/pixel_threading.c
        ../../Pixelinator/src/engine/graphics/sprite/sprite.c
        ../../Pixelinator/src/engine/graphics/draw/shapes.c
        ../../Pixelinator/src/engine/input/input.c
        ../../Pixelinator/src/engine/io/io.c
        ../../Pixelinator/src/engine/render/render.c
        ../../Pixelinator/src/engine/render/render_init.c
        ../../Pixelinator/src/engine/render/render_util.c
        ../../Pixelinator/src/engine/font_cache/SDL_FontCache.c
        ../../Pixelinator/src/engine/text/text.c
        ../../Pixelinator/src/engine/global.c
        ../../Pixelinator/src/engine/time.c

        # SDL (Not sure if needed)
        ../external/SDL
        ../external/sdl-image
        ../external/sdl-mixer
        ../external/sdl-ttf
)

set(APP_EXE PixelinatorDemo)

if( ${CMAKE_SYSTEM_NAME} MATCHES "Android" )
    add_library( ${APP_EXE} SHARED )
else()
    add_executable(${APP_EXE} main.c)
    set_target_properties( ${APP_EXE} PROPERTIES OUTPUT_NAME ${CMAKE_PROJECT_NAME} )
endif()

find_package(Threads REQUIRED)
if(THREADS_HAVE_PTHREAD_ARG)
    target_compile_options(${APP_EXE} PUBLIC "-pthread")
endif()
if(CMAKE_THREAD_LIBS_INIT)
    target_link_libraries(${APP_EXE} "${CMAKE_THREAD_LIBS_INIT}")
endif()

add_subdirectory("external")
add_subdirectory(glad/)
include_directories("include")
#target_link_libraries(Pixelinator SDL2::SDL2main SDL2::SDL2-static SDL2_image::SDL2_image-static SDL2_ttf::SDL2_ttf-static SDL2_mixer::SDL2_mixer-static)

# Library is generated inside of the cmake-build-debug or release folder!
target_link_libraries(${APP_EXE} glad Pixelinator)

解决方案

CMake本身不直接支持合并静态库,但可以通过自定义命令调用平台原生工具实现。以下是具体步骤:

步骤1:将自研代码改为对象库编译

把根目录中add_library(Pixelinator STATIC)改为对象库,对象库只编译代码不生成库文件,方便后续合并:

add_library(Pixelinator_OBJECTS OBJECT
        ../../Pixelinator/src/engine/audio/sound.c
        ../../Pixelinator/src/engine/config/config.c
        ../../Pixelinator/src/engine/core/core.c
        ../../Pixelinator/src/engine/graphics/bitmap/bitmap.c
        ../../Pixelinator/src/engine/graphics/bitmap/pixel_threading.c
        ../../Pixelinator/src/engine/graphics/sprite/sprite.c
        ../../Pixelinator/src/engine/graphics/draw/shapes.c
        ../../Pixelinator/src/engine/input/input.c
        ../../Pixelinator/src/engine/io/io.c
        ../../Pixelinator/src/engine/render/render.c
        ../../Pixelinator/src/engine/render/render_init.c
        ../../Pixelinator/src/engine/render/render_util.c
        ../../Pixelinator/src/engine/font_cache/SDL_FontCache.c
        ../../Pixelinator/src/engine/text/text.c
        ../../Pixelinator/src/engine/global.c
        ../../Pixelinator/src/engine/time.c
)
# 删除原SDL目录的引用,子模块会单独构建

步骤2:移除external目录的链接逻辑

修改external/CMakeLists.txt,删除所有target_link_libraries(Pixelinator ...)行,因为我们不再直接链接SDL库到自研库,而是通过合并处理:

set( BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE )

# SDL
set( SDL_LIBC ON CACHE BOOL "" FORCE )
set( SDL_TEST OFF CACHE BOOL "" FORCE )
add_subdirectory(SDL)
# 移除 target_link_libraries(Pixelinator SDL2::SDL2main SDL2::SDL2-static )

# SDL_image
set( SDL2IMAGE_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2IMAGE_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2IMAGE_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2IMAGE_DEPS_SHARED OFF CACHE BOOL "" FORCE )
add_subdirectory( sdl-image )
# 移除 target_link_libraries(Pixelinator SDL2_image::SDL2_image-static)

# SDL_ttf
set( SDL2TTF_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2TTF_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2TTF_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2TTF_HARFBUZZ ON CACHE BOOL "" FORCE )
add_subdirectory( sdl-ttf )
# 移除 target_link_libraries(Pixelinator SDL2_ttf::SDL2_ttf-static )

# SDL_mixer
set( SDL2MIXER_SAMPLES OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_INSTALL OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_VENDORED ON CACHE BOOL "" FORCE )
set( SDL2MIXER_DEPS_SHARED OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_FLAC OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MOD OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MP3 OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_MIDI OFF CACHE BOOL "" FORCE )
set( SDL2MIXER_OPUS OFF CACHE BOOL "" FORCE )
add_subdirectory( sdl-mixer )
# 移除 target_link_libraries(Pixelinator SDL2_mixer::SDL2_mixer-static )

步骤3:添加自定义合并命令

在根目录CMakeLists.txt末尾添加以下代码,自动收集所有静态库并合并为单个文件:

# 定义需要合并的组件:自研对象文件 + 所有SDL静态库 + glad
set(MERGE_LIBS
    $<TARGET_OBJECTS:Pixelinator_OBJECTS>
    $<TARGET_FILE:SDL2::SDL2-static>
    $<TARGET_FILE:SDL2_image::SDL2_image-static>
    $<TARGET_FILE:SDL2_ttf::SDL2_ttf-static>
    $<TARGET_FILE:SDL2_mixer::SDL2_mixer-static>
    $<TARGET_FILE:glad>
)

# 设置合并后的库名和路径
set(MERGED_LIB_NAME "${CMAKE_PROJECT_NAME}_merged")
set(MERGED_LIB_FILE "${CMAKE_STATIC_LIBRARY_PREFIX}${MERGED_LIB_NAME}${CMAKE_STATIC_LIBRARY_SUFFIX}")

# 跨平台执行合并操作
if(UNIX OR APPLE)
    # Linux/macOS 使用ar工具
    add_custom_command(
        OUTPUT ${MERGED_LIB_FILE}
        COMMAND rm -f ${MERGED_LIB_FILE}
        COMMAND ar crs ${MERGED_LIB_FILE} ${MERGE_LIBS}
        DEPENDS Pixelinator_OBJECTS SDL2::SDL2-static SDL2_image::SDL2_image-static SDL2_ttf::SDL2_ttf-static SDL2_mixer::SDL2_mixer-static glad
        COMMENT "Merging static libraries into ${MERGED_LIB_FILE}"
    )
elseif(WIN32)
    # Windows 使用lib.exe工具
    add_custom_command(
        OUTPUT ${MERGED_LIB_FILE}
        COMMAND lib.exe /OUT:${MERGED_LIB_FILE} ${MERGE_LIBS}
        DEPENDS Pixelinator_OBJECTS SDL2::SDL2-static SDL2_image::SDL2_image-static SDL2_ttf::SDL2_ttf-static SDL2_mixer::SDL2_mixer-static glad
        COMMENT "Merging static libraries into ${MERGED_LIB_FILE}"
    )
endif()

# 创建自定义目标,确保构建时自动执行合并
add_custom_target(MergedPixelinator ALL DEPENDS ${MERGED_LIB_FILE})

# 如需让Demo程序链接合并后的库,修改此行
# target_link_libraries(${APP_EXE} ${MERGED_LIB_FILE})

关键说明

  • 对象库是核心:它避免了重复编译,同时让我们能灵活组合编译产物。
  • 平台兼容性:通过条件判断适配不同系统的库合并工具,保证跨平台可用。
  • 依赖保障:自定义命令的DEPENDS参数确保所有依赖库编译完成后才执行合并。

内容的提问来源于stack exchange,提问作者Angle-Brackets

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 17:54:55