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

如何将C++ Makefile旧项目迁移至CMake并集成GoogleTest框架

问题背景

我正在将基于Makefile构建的老旧C++项目改造为使用CMakeLists.txt构建、集成GoogleTest测试框架的现代化项目,目前无法正确处理各类依赖关系。

现有项目目录结构

Project-LG
    src/
        app/
          main.cpp
          A.cpp
          A.hpp
          B.cpp
          B.hpp
          C.cpp
          C.hpp
          ...
        cpp-utils/
          D.cpp
          D.hpp
          E.hpp
          F.hpp
        json/
            json.hpp
        hiredis/    # 自带Makefile的子项目
        orane2/     # 自带Makefile的子项目
        rmr/        # 自带Makefile的子项目
        spdlog/     # 头文件库,存在嵌套目录
        Makefile

原有src目录下Makefile内容

CC=gcc
CPP=g++

SRCDIR = .
APPDIR = $(SRCDIR)/app
UTILSDIR = $(SRCDIR)/cpp-utils

TARGETDIR =./../out
OBJDIR =./../out/obj
APP_OBJDIR =$(OBJDIR)/app
UTILS_OBJDIR =$(OBJDIR)/cpp-utils

LIBSDIR = ./../libs

INCLUDE_FILE = \
    -Iapp \
    -Icpp-utils \
    -Irmr/si \
    -Irmr/si/si95 \
    -Irmr/common \
    -Ijson \
    -Iorane2 \
    -I. \
    -Ihiredis

SUBDIRS := \
    $(SRCDIR)/rmr \
    $(SRCDIR)/orane2 \
    $(SRCDIR)/hiredis

LFLAGS =
LIBS += -pthread -static-libstdc++ \
    -L$(LIBSDIR) -l:librmr.a -l:liborane2.a -l:hiredis.a

XAPP_NAME_STR := '"app-lg"'

CFLAGS += -Wall -g -O2 -DXAPP_NAME=$(XAPP_NAME_STR) $(INCLUDE_FILE)
CPPFLAGS = $(CFLAGS) -fPIC -std=c++17

APP_EXE ?= xapp

APP_SOURCES := $(shell find $(APPDIR) -maxdepth 1 -name '*.cpp' -printf '%f\n')
UTILS_SOURCES := $(shell find $(UTILSDIR) -maxdepth 1 -name '*.cpp' -printf '%f\n')

APP_OBJS := $(addprefix $(APP_OBJDIR)/, $(APP_SOURCES:%.cpp=%.o))
UTILS_OBJS := $(addprefix $(UTILS_OBJDIR)/, $(UTILS_SOURCES:%.cpp=%.o))

.SUFFIXES: .c~.o

.PHONY: all $(SUBDIRS) clean

all: $(SUBDIRS) $(APP_EXE)

$(APP_EXE): $(APP_OBJS) $(UTILS_OBJS)
    @mkdir -p $(TARGETDIR)
    @mkdir -p $(OBJDIR)
    $(CPP) $(CFLAGS) $(LFLAGS) $(APP_OBJS) $(UTILS_OBJS) $(LIBS) -o $(TARGETDIR)/$@

$(APP_OBJDIR)/%.o : $(APPDIR)/%.cpp
    @mkdir -p $(OBJDIR)
    @mkdir -p $(APP_OBJDIR)
    $(CPP) -c $(CPPFLAGS) $(LFLAGS) $< -o $@

$(UTILS_OBJDIR)/%.o : $(UTILSDIR)/%.cpp
    @mkdir -p $(OBJDIR)
    @mkdir -p $(UTILS_OBJDIR)
    $(CPP) -c $(CPPFLAGS) $(LFLAGS) $< -o $@

$(SUBDIRS):
    $(MAKE) -C $@
clean:
    rm -rf $(TARGETDIR)

核心难点

  • 不清楚如何在CMake构建流程中调用现有子目录的Makefile完成依赖库编译
  • 不知道如何正确添加GoogleTest框架并处理其全部关联依赖

解决方案

一、调用子目录现有Makefile编译依赖库

使用CMake内置的ExternalProject模块即可直接调用原有Makefile完成第三方库编译,无需修改子项目任何构建逻辑,配置步骤如下:

  1. 在项目根目录新建顶层CMakeLists.txt,先配置基础编译参数
    cmake_minimum_required(VERSION 3.16)
    project(Project-LG CXX)
    # 对齐原Makefile的编译选项
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_FLAGS "-Wall -g -O2 -fPIC -DXAPP_NAME='\"app-lg\"'")
    # 对齐原Makefile的输出目录规则
    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/libs)
    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/out)
    
    include(ExternalProject)
    
  2. 逐个配置带Makefile的子项目,将编译出的静态库包装为CMake可识别的导入目标
    # 配置hiredis
    ExternalProject_Add(hiredis_build
        SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/hiredis
        CONFIGURE_COMMAND ""
        BUILD_COMMAND $(MAKE) -C ${CMAKE_SOURCE_DIR}/src/hiredis
        INSTALL_COMMAND ""
        BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/libs/libhiredis.a
    )
    add_library(hiredis STATIC IMPORTED)
    set_target_properties(hiredis PROPERTIES
        IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/libhiredis.a
        INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/src/hiredis
    )
    add_dependencies(hiredis hiredis_build)
    
    # 配置orane2
    ExternalProject_Add(orane2_build
        SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/orane2
        CONFIGURE_COMMAND ""
        BUILD_COMMAND $(MAKE) -C ${CMAKE_SOURCE_DIR}/src/orane2
        INSTALL_COMMAND ""
        BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/libs/liborane2.a
    )
    add_library(orane2 STATIC IMPORTED)
    set_target_properties(orane2 PROPERTIES
        IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/liborane2.a
        INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_SOURCE_DIR}/src/orane2
    )
    add_dependencies(orane2 orane2_build)
    
    # 配置rmr,补全所有需要的头文件搜索路径
    ExternalProject_Add(rmr_build
        SOURCE_DIR ${CMAKE_SOURCE_DIR}/src/rmr
        CONFIGURE_COMMAND ""
        BUILD_COMMAND $(MAKE) -C ${CMAKE_SOURCE_DIR}/src/rmr
        INSTALL_COMMAND ""
        BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/libs/librmr.a
    )
    add_library(rmr STATIC IMPORTED)
    set_target_properties(rmr PROPERTIES
        IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/libs/librmr.a
        INTERFACE_INCLUDE_DIRECTORIES 
            "${CMAKE_SOURCE_DIR}/src/rmr;${CMAKE_SOURCE_DIR}/src/rmr/si;${CMAKE_SOURCE_DIR}/src/rmr/si/si95;${CMAKE_SOURCE_DIR}/src/rmr/common"
    )
    add_dependencies(rmr rmr_build)
    

    注意:如果子项目Makefile编译后库存放在子项目自身目录而非libs目录,将IMPORTED_LOCATION和BUILD_BYPRODUCTS的路径替换为实际库文件位置即可。

  3. 配置自有代码与头文件-only库,编译主程序
    # 配置头文件搜索路径,spdlog、json都是头文件库,直接加根目录即可自动识别嵌套头文件
    include_directories(
        ${CMAKE_SOURCE_DIR}/src/app
        ${CMAKE_SOURCE_DIR}/src/cpp-utils
        ${CMAKE_SOURCE_DIR}/src/json
        ${CMAKE_SOURCE_DIR}/src/spdlog
    )
    
    # 收集自有业务源码
    file(GLOB APP_SOURCES ${CMAKE_SOURCE_DIR}/src/app/*.cpp)
    file(GLOB UTILS_SOURCES ${CMAKE_SOURCE_DIR}/src/cpp-utils/*.cpp)
    
    # 生成主可执行文件,链接所有依赖,注意静态库链接顺序:被依赖的库放在后面
    add_executable(xapp ${APP_SOURCES} ${UTILS_SOURCES})
    target_link_libraries(xapp PRIVATE
        rmr orane2 hiredis
        pthread
        -static-libstdc++
    )
    

二、集成GoogleTest测试框架

使用CMake内置的FetchContent模块直接引入GTest源码编译,自动处理所有依赖关联,不需要提前手动安装库:

  1. 在顶层CMakeLists.txt中追加测试相关配置
    enable_testing()
    include(FetchContent)
    FetchContent_Declare(
        googletest
        # 可提前将GTest源码放入项目third_party目录,直接引用本地路径即可
        SOURCE_DIR ${CMAKE_SOURCE_DIR}/third_party/googletest
    )
    # 避免Windows平台下GTest覆盖项目编译选项
    set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
    FetchContent_MakeAvailable(googletest)
    
  2. 在项目根目录新建tests目录存放测试用例,在目录下新建CMakeLists.txt,示例配置如下:
    # 测试A模块的可执行文件,引入对应依赖的源码
    add_executable(test_A test_A.cpp 
        ${CMAKE_SOURCE_DIR}/src/app/A.cpp
        ${CMAKE_SOURCE_DIR}/src/cpp-utils/D.cpp
    )
    # 链接GTest和业务依赖库
    target_link_libraries(test_A PRIVATE
        GTest::gtest_main
        rmr orane2 hiredis
        pthread
    )
    # 自动注册测试用例
    include(GoogleTest)
    gtest_discover_tests(test_A)
    
  3. 在顶层CMakeLists.txt末尾追加子目录声明,将测试纳入构建流程
    add_subdirectory(tests)
    

三、构建执行命令

使用标准CMake流程即可完成构建与测试:

mkdir build && cd build
cmake ..
make -j$(nproc)
# 运行所有测试用例
ctest

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 19:18:17