QT CMake项目中spdlog编译优化实战:从30秒到毫秒级的构建优化

news/2025/12/9 22:21:23/文章来源:https://www.cnblogs.com/tlink/p/19328578

前言

在CMake + Qt项目开发中,我们引入了spdlog作为日志库。起初采用直接包含头文件的方式,但发现每次构建都要额外花费30秒的时间。经过一系列排查和优化,最终将这部分时间降到了毫秒级别。本文将完整记录这个优化过程。

问题现象

项目结构如下:

project/
├── CMakeLists.txt
├── third_party/
│   └── spdlog/          # spdlog头文件
└── src/└── ...              # 项目源码

CMake配置:

target_include_directories(MachineDog PRIVATEthird_party${CURL_INCLUDE_DIR}
)

问题:每次构建时,即使只修改了一个小文件,整个编译过程也要额外花费30秒左右。

初步分析

spdlog是一个功能强大的C++日志库,但它大量使用了模板和头文件内联实现。这导致:

  1. 编译膨胀:每个包含spdlog的源文件都要重新解析所有模板代码
  2. 重复编译:相同的模板代码在不同编译单元中重复编译
  3. 依赖扩散:修改spdlog头文件会导致所有依赖文件重新编译

解决方案探索

方案1:预编译头文件(PCH)

target_precompile_headers(MachineDog PRIVATE<vector><string><memory>third_party/spdlog/spdlog.h
)

效果:有一定改善,但仍不理想,因为spdlog内部还有大量嵌套包含。

方案2:将spdlog作为预编译库

这是最终选择的方案,但实施过程遇到了坑。

实施过程

第一步:编译spdlog静态库

cd third_party/spdlog
mkdir build && cd build
cmake -G "MinGW Makefiles" ..
mingw32-make.exe

得到 libspdlog.a 文件。

第二步:在CMake中配置

初始配置:

set(SPDLOG_LIB_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/spdlog/build)
set(SPDLOG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/spdlog/include)add_library(spdlog STATIC IMPORTED)
set_target_properties(spdlog PROPERTIESIMPORTED_LOCATION ${SPDLOG_LIB_DIR}/libspdlog.aINTERFACE_INCLUDE_DIRECTORIES ${SPDLOG_INCLUDE_DIR}
)target_link_libraries(MachineDog PRIVATE spdlog)

问题:构建时间仍然很长,链接还需要9秒!

第三步:关键发现 - SPDLOG_COMPILED_LIB 宏

添加关键配置:

set_target_properties(spdlog PROPERTIESIMPORTED_LOCATION ${SPDLOG_LIB_DIR}/libspdlog.aINTERFACE_INCLUDE_DIRECTORIES ${SPDLOG_INCLUDE_DIR}INTERFACE_COMPILE_DEFINITIONS "SPDLOG_COMPILED_LIB"  # 关键!
)

效果:构建时间从9秒降到毫秒级别!

原理深度解析

spdlog的两种工作模式

1. 头文件模式(默认)

  • 所有实现代码都在头文件中
  • 每个编译单元重复编译相同代码
  • 编译时间长,二进制体积大

2. 编译库模式(SPDLOG_COMPILED_LIB)

  • 实现代码编译到静态库中
  • 头文件只包含声明
  • 编译快,二进制体积小

宏的作用机制

查看spdlog源码:

// spdlog/common.h
#ifdef SPDLOG_COMPILED_LIB// 编译库模式:只声明template<typename... Args>void info(const char* fmt, const Args&... args);
#else// 头文件模式:完整实现template<typename... Args>void info(const char* fmt, const Args&... args) {// 大量模板代码...}
#endif

为什么需要这个宏?

  1. 没有宏的情况

    • 即使链接了 libspdlog.a,仍然使用头文件模式
    • 静态库可能包含空实现或未被使用
    • 编译时间没有优化
  2. 有宏的情况

    • 切换到真正的编译库模式
    • 头文件只生成声明
    • 实现从静态库链接

完整优化配置

最佳实践配置

# 设置路径
set(SPDLOG_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/third_party/spdlog)
set(SPDLOG_LIBRARY ${SPDLOG_ROOT}/build/libspdlog.a)
set(SPDLOG_INCLUDE_DIR ${SPDLOG_ROOT}/include)# 创建导入目标
add_library(spdlog::spdlog STATIC IMPORTED)set_target_properties(spdlog::spdlog PROPERTIESIMPORTED_LOCATION ${SPDLOG_LIBRARY}INTERFACE_INCLUDE_DIRECTORIES ${SPDLOG_INCLUDE_DIR}# 关键定义INTERFACE_COMPILE_DEFINITIONS "SPDLOG_COMPILED_LIB""SPDLOG_NO_EXCEPTIONS"        # 可选优化"SPDLOG_NO_THREAD_ID"         # 可选优化"SPDLOG_FMT_EXTERNAL"         # 使用外部fmt库
)# 链接fmt库(如果需要)
find_package(fmt REQUIRED)
target_link_libraries(spdlog::spdlog INTERFACE fmt::fmt)# 链接到主目标
target_link_libraries(MachineDog PRIVATE spdlog::spdlog)

编译spdlog时的优化配置

# 重新编译spdlog,启用优化
cd third_party/spdlog/build
rm -rf *
cmake -G "MinGW Makefiles" \-DCMAKE_BUILD_TYPE=Release \-DCMAKE_CXX_FLAGS="-O3 -flto -DSPDLOG_COMPILED_LIB" \-DSPDLOG_BUILD_EXAMPLE=OFF \-DSPDLOG_BUILD_TESTS=OFF \-DSPDLOG_BUILD_SHARED=OFF \-DSPDLOG_FMT_EXTERNAL=ON \..
mingw32-make.exe -j8

性能对比

配置方案 编译时间 链接时间 二进制大小 备注
纯头文件 30+秒 默认情况
预编译头 15秒 部分优化
静态库(无宏) 30秒 9秒 错误配置
静态库(有宏) 正常 正确配置

经验总结

  1. 理解库的工作模式:有些库支持多种使用方式,需要明确配置

  2. 宏定义的重要性SPDLOG_COMPILED_LIB 是切换工作模式的关键

  3. 验证配置生效:通过查看符号、编译测试程序等方式验证

  4. 完整工具链优化:从库的编译到项目的链接都需要正确配置

  5. 文档阅读:仔细阅读第三方库的文档,了解各种编译选项

扩展思考

其他类似库的优化

许多现代C++库都有类似的设计模式:

  • fmtlibFMT_HEADER_ONLY
  • Catch2CATCH_CONFIG_RUNNER 配置
  • Eigen:通过预处理器指令控制内联

通用优化策略

  1. 编译时 vs 运行时:权衡编译时间和运行效率
  2. 模板代码分离:将模板声明和实现分离
  3. 显式实例化:对常用类型进行显式模板实例化
  4. 模块化设计:C++20模块化是未来方向

结论

通过将spdlog从头文件模式切换到编译库模式,并正确配置 SPDLOG_COMPILED_LIB 宏,我们成功将构建时间从30秒优化到毫秒级别。这个过程不仅解决了具体问题,更深入理解了C++模板库的设计哲学和优化方法。

关键收获:在使用第三方库时,不仅要正确链接,还要理解其内部工作机制,通过正确的宏定义和编译选项充分发挥其性能优势。


优化永无止境,但每一次深入理解都让我们的代码更加高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/995646.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【AI】第二篇 为什么会有神经网络

根据前面的n-gram的介绍,大家都发现光靠统计次数是走不通的,我们需要一个能够脑补,举一反三的方法,而不是死板的查表机器。神经网络是--“懂得举一反三的聪明人"神经网络引入了一个划时代的的概念:词向量,它…

7-16岁少儿编程课精选推荐:从启蒙到竞赛的系统路径 - 品牌测评鉴赏家

7-16岁少儿编程课精选推荐:从启蒙到竞赛的系统路径在为7-16岁的孩子选择编程教育机构时,家长们往往面临众多选择。不同机构在课程体系、教学方式和培养方向上各有侧重。本文将基于市场口碑、课程体系完整性和家长实际…

深入解析:PostgreSQL 向量扩展插件pgvector安装和使用

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

P3385 【模板】负环 题解

P3385 【模板】负环 题解差分约束系统是什么? 差分约束系统指的是一个序列 \(x={x_1,x_2,\cdots x_m}\) 和以如下形式出现的 \(n\) 元一次不等式组。 \[\left\{\begin{matrix} x_{i_1}-x_{j_1}\le c_{k_1}\\x_{i_2}-x…

权威盘点:2025年中国智能舆情监控系统市场深度解析

随着数字社会信息生态的持续演进,舆情监控工作已发生根本性变革。传统的人工信息汇总模式,正被集多模态感知、大模型智能研判与前瞻性决策支持于一体的新一代舆情监控系统所取代。行业数据显示,2025年中国舆情监测市…

qemu安装aix7.2

最近想玩玩IBM的AIX系统,由于AIX系统只能运行在IBM的power cpu上,VMware、VirtualBox只支持X86架构,QEMU全仿真的特点可以模拟出power cpu实现系统安装。 AIX系统是IBM开发的一套UNIX操作系统,它可以在所有的IBM p…

编程小白必看!免费体验课大搜罗 - 品牌测评鉴赏家

编程小白必看!免费体验课大搜罗编程小白速进!免费体验课地图来啦 编程热,为何要先体验? 在当今数字化时代,编程已成为一门炙手可热的技能 ,掀起了全民学习的热潮。从职场人士渴望提升竞争力,到家长们为孩子规划…

前端半小时,上线一下午?我用这个平台工程思路统一了全栈部署

全栈开发拯救指南:别再让你的前端去碰 Nginx 和 Docker 了 我名义上是个全栈开发者,但最近感觉自己更像个“全栈救火队员”。 一个前端组件,我可能半小时就写完了。但为了把它上线,我可能需要花一下午的时间,去跟…

2025年国内诚信的微动开关制造厂家推荐榜单,家电微动开关/鼠标微动开关/防水微动开关/微动开关/小型微动开关微动开关制造厂家哪里有 - 品牌推荐师

在工业自动化、智能家居、新能源汽车等产业蓬勃发展的当下,微动开关作为关键的基础电子元件,其可靠性直接关系到终端产品的性能与安全。面对市场上众多的微动开关制造商,采购方与工程师们常常面临“工厂哪家靠谱”的…

ABC352D 题解

ABC352D 题解ABC352D - Description 给你一个 \(n\) 的排列 \(a\),让你选出一个长度为 \(k\) 的 \(a\) 的子序列 \(b=\left [ a_{p_1},a_{p_2},\cdots ,a_{p_k} \right ]\),使得 \(\min b_i +k-1=\max b_i\) 的同时控…

CF1407D 题解

CF1407D 题解CF1407D - Description 有 \(n\) 栋楼,每栋楼有高度 \(h_i\),对于第 \(i\) 栋楼和第 \(j\) 栋楼,如果 \((i,j)\) 满足以下三个条件中的任意一个,我们认为可以从第 \(i\) 栋楼跳到第 \(j\) 栋楼:\(i+1…

12月9号

今天进行了中国古诗词的学习。

C语言深度解剖:第一章关键字(五) - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

MySQL 筛选条件放 ON 后 vs 放 WHERE 后

ON 决定如何 "连接" 表,WHERE 决定连接后 "显示" 哪些行。 这个根本区别导致了在 LEFT JOIN / RIGHT JOIN 外连接中,条件放置位置会产生巨大影响;而在 INNER JOIN 中,效果通常 等价。今天我们…

明天不干是小狗

明天不干是小狗上一条必须干 我说真的 老己,你干吧,我求求你了

CF547B 题解

CF547B 题解CF547B - Description 给你个长度为 \(n\) 的序列 \(a\),对于每个 \(1\le k\le n\),有 \(n-k+1\) 个中所有长度为 \(k\) 的子串,你需要求出这 \(n-k+1\) 个子串的区间最小值的最大值,即下面式子的值: …

SAT 辅导哪里好?2025 年优质机构推荐(含精准选择指南) - 品牌测评鉴赏家

SAT 辅导哪里好?2025 年优质机构推荐(含精准选择指南)选择 SAT 辅导机构需结合自身基础、目标分数、学习习惯及地域便利性。以下是 2025 年最新优质机构推荐,涵盖线上线下资源,针对不同需求提供精准建议: 一、全…

10403_基于Springboot的旅游管理系统

1、项目包含 项目源码、项目文档、数据库脚本、软件工具等资料; 带你从零开始部署运行本套系统。 2、项目介绍 随着旅游业的发展,越来越多的人选择通过互联网来规划自己的旅行。在线旅游信息推荐系统就是为了帮助用户…

MMH_蓝桥杯Python_语法基础_列表与循环语句基础

1.列表 列表可以极大降低我们在处理多个元素时的复杂程度; 在 Python 中,列表(list) 是一种有序、可变、可存储多种数据类型的序列数据结构,使用中括号 [] 定义,元素之间用逗号分隔。 1.创建列表 代码展示 #包…

2025全屋定制十大品牌哪家好?欧蒂尼硬核实力破局,领衔品质家居新革命 - 资讯焦点

2025年,中国全屋定制行业迎来“质造升级+需求多元”的双重变革,整家定制、智能集成、年轻化设计成为行业主流趋势。在这片竞争激烈的赛道上,一批兼具实力与口碑的品牌脱颖而出,它们以技术为基、以设计为魂、以服务…