首页 > 编程语言 >巧用CMake编译策略:C++二次开发中的Release与Debug模式切换秘籍

巧用CMake编译策略:C++二次开发中的Release与Debug模式切换秘籍

时间:2024-06-05 09:31:00浏览次数:15  
标签:CMAKE 编译 Debug 模式 Release FLAGS 二次开发 CMake

往期本博主的 C++ 精讲优质博文可通过这篇导航进行查找:
《Lemo 的C++精华博文导航:进阶、精讲、设计模式文章全收录》

前言

在C++二次开发的过程中,理解各种编译模式并能灵活切换,对于提升软件性能和调试效率至关重要。

本文将深入讨论 DebugRelease 模式的区别、默认编译模式、如何确保编译模式的一致性、编译模式不一致时可能遇到的问题及在依赖项为 Release 模式时,如何支持自身为 Debug 模式。

文章目录

什么是 Debug 模式和 Release 模式

在 C++ 项目开发中,Debug 模式和 Release 模式是两种最常见的编译配置。

  • Debug模式旨在增加调试信息,优化调试过程,而不注重运行效率和生成文件的大小。
  • Release模式会应用优化以提高程序的运行速度和效率,通常会移除调试信息,减少可执行文件的体积。

通常而言:

Debug模式会保留更多的调试信息,包括变量名、函数栈信息等,使得开发者可以使用调试器跟踪执行过程,检查变量值等,便于查找和修复错误。

Release模式通过优化代码,去除不必要的调试信息,以期望达到更快的执行速度和更高的运行效率,是向最终用户发布的首选模式。

默认编译模式介绍

大多数CMake项目支持四种默认编译模式:DebugReleaseRelWithDebInfoMinSizeRel

下面是它们各自的区别:

  • Debug模式: 保留详细的调试信息,不进行优化,适合开发和调试阶段使用。
  • Release模式: 启用优化,不保留调试信息,适用于最终的产品发布。
  • RelWithDebInfo模式: 既保留一定的调试信息,又进行优化。它提供了一种中间的选择,既可以获得较好的性能又便于调试。
  • MinSizeRel模式: 优化设置旨在减少最终产品的体积,适用于对可执行文件大小有严格要求的情况。

CMake对应地提供了变量 CMAKE_BUILD_TYPE 来管理这些编译模式。

如下例所示:

cmake -B ./build -G "Visual Studio 17 2022" -T v141 -DCMAKE_BUILD_TYPE=Debug -DProject_INSTALL_PATH="project_root_dir"

就是显式的指定是用Debug 模式来对 .sln 工程进行生成。

如果开发者不想看到这么多编译模式,可以在 CMakeLists.txt 中显式的指定能看到的编译模式:

set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configurations" FORCE)

如上例,就显式的指定了,只显式 Debug Release 两种模式在工程中。

如何保持编译模式一致

在实际开发过程中,保持整个项目及其依赖项的编译模式一致是非常重要的。不一致的编译模式不仅会引起性能问题,甚至可能导致程序错误。要确保编译模式一致,可以在CMakeLists.txt中全局设置CMAKE_BUILD_TYPE,并确保所有子项目和相关依赖采用相同的设置。

set(CMAKE_BUILD_TYPE Release)

将上述代码添加到项目的根CMakeLists.txt文件中,可以确保整个项目使用Release模式编译。

当然,开发者也可以在生成的 .sln 工程中进行调整编译模式,不过不建议这么做,这样可能会导致编译选项和链接选项混乱,因为,默认的编译选项,链接选项都是在 CMakeLists.txt 中写好了,在生成 .sln 工程时就设置在了工程中,贸然的改动会导致异常的发生。

下面给一段通用的 cmake 编译模式设置代码:

    # 进行编选选项类型的设置
    set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configurations" FORCE)

    # 默认设置编译选项
    if (NOT CMAKE_BUILD_TYPE)
        set(CMAKE_BUILD_TYPE "Release")
    endif()

    if (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))
        # 设置独属于 Debug 模式时的一些宏定义、设置、编译选项、链接选项,etc
        add_definitions(...)
        string(...)
        add_compile_options(...)
        add_link_options(...)
        set(...)
        ...

    elseif (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Release"))
        # 设置独属于 Release 模式时的一些宏定义、设置、编译选项、链接选项,etc
        string(...)
        add_compile_options(...)
        add_link_options(...)
        set(...)
        ...
    endif()

    # 设置通用的编译选项、链接选项
    add_compile_options(...)
    add_link_options(...)
    ...

编译模式不一致时可能出现的问题

编译模式的不一致可能会导致许多问题,包括但不限于:

  • 性能不一致:Debug模式下的低效率可能会使整个项目或系统的性能降低。
  • 程序错误:不同编译模式下的内存布局可能不同,Debug模式可能添加了额外的检查,这可能会在Release模式下暴露出隐藏的错误。
  • 链接错误:尤其是在使用静态库或动态库时,如果编译模式不一致,可能会遇到链接错误或运行时错误。

最常见的现象是,程序能正常启动,但运行过程中出现因析构错误导致的程序崩溃问题,这类问题也不好定位。

如何在依赖项为 Release 模式时,自身为 Release 模式也可以进行调试

如果依赖项为 Release 模式,自身为 Release 模式时,如果也想进行调试,可以采用如下办法:

    elseif (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Release"))
        string(REPLACE "/O2" "/Od" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
        string(REPLACE "/O2" "/Od" CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
        add_compile_options(/Zi)
        add_link_options(/DEBUG)
    endif()

我们来一句句看上述代码:

  • 第一句,当设置当模式为 Release 模式时
  • 第二句,将 CMAKE_CXX_FLAGS_RELEASE 变量中的调试信息优化级别从/O2(最大优化)更改为/Od(不优化),即 CXX 编译时生成调试信息。
  • 第三句,将 CMAKE_C_FLAGS_RELEASE 变量中的调试信息优化级别从/O2(最大优化)更改为/Od(不优化),即 C 编译时生成调试信息。
  • 第四句,添加编译选项/Zi,表示使用 Standard Edit & Continue 调试信息格式。
  • 第五句,添加链接选项/DEBUG,请求链接器生成调试信息。

通过上述方法,就能保证 Release 模式也可以进行调试了。

如何在依赖项为Release模式时,支持自身为Debug模式

在某些情况下,可能需要在依赖项为Release模式时,使自身项目保持在Debug模式,特别是在进行调试且依赖项不方便改变时。要实现这一点,可以采用如下的方法:

    set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "Configurations" FORCE)

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

    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_RELEASE}")
    set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_RELEASE}")
    set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
    set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")

    if (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Debug"))
        string(REPLACE "/O2" "/Od" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
        string(REPLACE "/O2" "/Od" CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")

        set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Zi")
        set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Zi")

        add_link_options(/DEBUG)

    elseif (CMAKE_BUILD_TYPE AND (CMAKE_BUILD_TYPE STREQUAL "Release"))
        add_definitions(
            -DNDEBUG
        )

        # 编译器优化
        add_compile_options(/Ob1)
        add_compile_options(/Oi)
        add_compile_options(/Ot)
        add_compile_options(/GF)
        add_compile_options(/Gy)
    endif()

这是一套通用的做法。先设置编译选项的类型只有 Debug, Release 两种模式,然后对它们进行约束。

将 Release 模式的编译链接选项给 Debug 模式,覆盖它选项的设置。然后将 Debug 模式中新的不能产生调试信息和链接信息的选项全部替换掉,使其能正常调试,然后优化掉 Release 模式中的相关编译选项,使其不保留调试相关的信息。

通过这些方法,可以灵活地控制项目及其依赖项的编译方式,以适应不同的开发和部署需求。

总结

CMake的灵活性为C++项目的编译配置提供了强大支持。理解和正确使用Debug与Release模式,能有效促进项目的开发效率和产品的性能,是每个C++开发者都应掌握的重要技能。

希望本文的内容能够成为你在C++项目中更有效地使用CMake编译策略带来些帮助。

如果有不解的,欢迎私信交流!

标签:CMAKE,编译,Debug,模式,Release,FLAGS,二次开发,CMake
From: https://blog.csdn.net/qq_36631379/article/details/139418000

相关文章

  • AutoCAD .net 二次开发 PaletteSet取消允许固定
    今天在使用PaletteSet的时候偶然发现一个与预期不符的情况我需要一个用鼠标拖动到侧边不会自动贴靠在CAD侧边(或其他边)的PaletteSet,于是我将PaletteSet的Dock和DockEnabled属性设置为DockSides.None示例代码如下: 但是当我打开cad执行此段代码之后,我发现我的面板仍然可以被......
  • 寻路算法---基于AutoCAD二次开发
    在CAD中绘制首尾相连的直线,并据此构件点与点之间的连接关系,考虑到可能会有线连接的地方有一定的距离delta 点的信息,用于最开始情况下的点的信息集合///<summary>///点对应的信息///</summary>publicclassQjPointInfo{///<summary>......
  • CMakeFile.txt通过sysroot方式后生成makefile报错
    怪不得博客园干不过别家,体验真的不太好。通过openwrite发布文章,其他平台都能发布,就博客园限制了,理由是文字少的文章限制发布到该平台。哎,这种行为当真是扶不起的阿斗。以后也不要太把博客园当回事了,迟早要关门的报错信息如下:--TheCcompileridentificationisunknown--T......
  • 【Revit二次开发】Document.Regenerate方法(更新Revit文档中所有的图元)
    出处https://www.revitapidocs.com/2015/22468e2c-9772-8478-0816-c9759aa43428.htm功能更新Revit文档中的图元以反映所有更改。注意使用此方法可以在一组更改后强制更新文档。请注意,当事务被提交时,会自动调用以重新生成文档。用法FamilyInstanceinstance=doc.Create.Ne......
  • CMake -- CMake Release 编译
    1.Release和Debug的区别Debug:调试版本,包含了调试需要用到的信息,程序员可以通过这个版本对程序进行调试。通常有一个.pdb格式的文件,包含了断点等调试信息。Release:发布版本,不对程序进行调试,自然就比Debug版本容量更小。同时在编译时会对程序进行优化,速度也比Debug更快。......
  • PDPS二次开发插件流程
    PDPS二次开发插件流程一.第一步通过C#创建插件dll1.在本地安装PDPS的安装目录下找到eMpower下的Tecnomatix.Engineering.dll,Tecnomatix.Engineering.Ui.dll2.在vs中新建winform窗体,引用以上目录下的两个dll文件3.新建一个类文件例如叫FristTestPlugin,继承Engineering下的TxBut......
  • cmake配置VS工程配置使用dll
    cmake配置VS工程配置使用dllAuthor:ChrisZZTime:2024-06-0116:17:04目录cmake配置VS工程配置使用dll1.目的2.如果找不到dll,会发生什么?3.需要找到哪些dll?3.1“就那么几个文件,手动拷贝“3.2从依赖树递归查询3.3额外的dll文件4.找到dll后放到哪里?4.1VS工程属性......
  • Qt 设置软件的版本信息:QMake、CMake工程
    Qt设置软件的版本等信息对于Qt开发的软件,我们如何去方便的查看其软件的版本信息。这里提供了几种方式。在运行程序期间设置版本信息大部分的程序在运行之后都会提供一个关于的按钮,通过点击该按钮并弹出一个关于界面,则可以查看相关的程序信息。此关于界面为用户自定义的......
  • cmake构建Qt插件
    cmake构建Qt插件为什么要使用插件在进行大型客户端项目的开发时,往往需要分成很多的功能模块,这是架构在设计时候就必须考虑的,良好的架构应该易于扩展,使用动态库就可以很好的实现,但是动态库使用中会使用到具体的定义,高层模块反而依赖于底层模块的实现,这是不符合设计模式中依赖反转......
  • shopify模板二次开发 增加购物车、立即购买功能
    <divclass="promotionDiscount"data-id="{{section.settings.promotionDiscount_id}}"><divclass="promotionDiscount_contercontainer"><divclass="promotionDiscount_title">{{section.se......