如何成功重写一个 C++ 代码库

这是一篇关于成功重写 C++ 代码库的指南,包含以下主要内容:

  • 背景:继承了一个复杂的 C++ 代码库,团队中只有作者能进行修改,且代码存在诸多问题,如正确性、可维护性、安全性等方面不佳,同时没有招聘 C++ 开发者的计划,继续使用 C++ 是死路一条,引入新语言进行增量重写是更好的选择。
  • 步骤

    • 改善现有代码库:确保代码在所有支持的平台上构建和运行,通过测试,并有清晰的 README 说明本地设置,同时去除无用代码。
    • 获得支持:从队友和利益相关者那里获得支持至关重要,通过展示现状(如总线因子、内存泄漏、fuzzing 结果、linter 检测到的问题等),提出多种解决方案并进行比较,如有可能,制作小型原型以确认方案的可行性。最终选择 Rust 作为新语言。
    • 保持支持:定期向利益相关者展示进展,展示新代码解决旧代码问题的能力,重复决策过程,与队友保持沟通,确保他们对新语言有信心。
    • 准备引入新语言:创建 Git 标签以区分引入新语言前后的代码,添加新语言代码时先关注构建系统和 CI 的工作,在 README 中提供工具说明。
    • 增量重写:坚持增量重写原则,每次选择一个小的组件进行重写,在同一仓库中与现有代码并行,编写测试用例,逐步替换旧代码,避免大的 PR 和长时间运行的分支,注意一些细节,如从调用图的叶子开始、迁移代码注释、使用自动化工具等,增量重写的优势是立即有用,即使未完全完成也有改进。
    • fuzzing:添加 fuzzing 测试以发现代码中的角落情况,使用 cargo-fuzz 和 LLVM 工具可视化分支覆盖情况,从 C++ 测试中提取有用数据构建 fuzzing 语料库,使用 LLVM 的 corpus minimizer 优化语料库,还可以手动添加 reproducer 文件作为回归测试。
    • 纯 Rust 与互操作(FFI):在 Rust 中使用 unsafe {} 块进行 FFI 开发,对 FFI 代码进行隔离和转换,以提高安全性,但 FFI 开发繁琐且容易引入内存安全问题,需要使用 Miri 进行测试,Rust 的 FFI 能力虽有效但需额外小心和测试。
    • 交叉编译:Rust 有良好的交叉编译支持,通过 CMake 和 rustup 进行配置,处理各种平台的差异和编译器选项,还可以编写 Lua 脚本来交叉编译所有平台,相比之下 C++ 的交叉编译支持不佳。
  • 结论:重写尚未完成,但已有较多 Rust 代码,开发者对 Rust 满意,添加单元测试在 Rust 中很简单,工具链也很完善,但 CMake/Make/Ninja 对不熟悉的开发者有难度,希望能缓解对重写 C++ 代码库的担忧,选择合适的语言,增量重写,展示进度,保持团队支持。
阅读 12
0 条评论