vs debug 模式生成的exe 另一台电脑_神秘的 _DEBUG 宏从何处来?

49c2a96c50b3b9af4eedc55692693978.png

缘起

在上一篇文章 《调试实战 —— dll 加载失败之Debug Release争锋篇》中,由于两个工程中的 _ITERATOR_DEBUG_LEVEL 不同,导致了对同一个 map 的解析不同,从而导致了崩溃。在示例代码中,我是手动更改的该宏的值,在实际工程中,却另有玄机。在上文中故意省略了这部分内容的介绍。现把实际工程的问题在本文中做个相对详细的梳理总结。

先剧透一下:实际工程中的问题是因为一个工程中定义了 _DEBUG 宏,另外一个工程里没定义。但是我已经核对过,两个工程都没定义 _DEBUG 宏。其中一个工程的 _DEBUG 宏是从哪儿来的呢?

测试工程简介

为了查出 _DEBUG 宏从何而来,我特意建了一个超级简单的工程。只包含一个源文件,其内容如下:

#ifdef _DEBUG
#pragma message("---- _DEBUG defined.")
#else
#pragma message("---- _DEBUG NOT defined.")
#endif

int wmain()
{
  return 0;
}

相信大家都知道,debug 会定义 _DEBUG 宏,而 release 不会定义 _DEBUG 宏。默认的 debugrelease 中对应的 Preprocessor definition 配置对比如下图:

292a673e914c3770c47c2f6d4338c597.png

最开始,我以为简单的删掉 _DEBUG 宏,编译的时候就不会有 _DEBUG 宏了。

1e9618f5a55b3da7849836b4c56fe146.png

没想到……

顽强的 _DEBUG 宏

再次编译的时候, _DEBUG 宏还是被定义了。

240085330ff245b6531a21c0777c4650.png

误入歧途

根据经验,工程配置可以直接存储在工程文件(后缀一般是 .vcxproj),也可以存储在 .props 文件中。在 TestDebugMacro.vcxproj 中搜索 _DEBUG 宏,一无所获!会不会存储在 .props 中呢?使用 File Locator 搜索关键字 _DEBUG,搜索条件如下图:

f71d46fd37cd75e152d48af42105b670.png

只搜到了几条相关的记录,因为使用的是 vs2013,对应的版本号是 v120,所以只需要关注高亮的搜索记录。

虽然,看上去不太可能,但是抱着试试看的心态,删除 Microsoft.Cpp.AppContainerApplication.props104 行的 _DEBUG 宏,

重新编译。结果, _DEBUG 宏,依然顽强的活着。这里就不截图了。

会不会记录在注册表里呢?搜索一番,一无所获!

肯定是记录到哪里了,应该不会动态生成吧?!

继续搜索

扩大搜索范围,在所有文件中搜索,经过排查,只有 cl.exe 中的记录比较靠谱。

9e5382b9a4b1c791aa28e1168fc38ef1.png

难道写死在 cl.exe 中了?有点儿不可思议。(文中暗表,确实写死在 cl.exe 中了。)

顺着这条路已经找不到更多有价值的线索了,需要换个思路了。

换个思路

会不会是 vs 在编译的时候,根据某些条件自动添加的?为了排除这种情况,直接使用 msbuild.exe 进行构建操作(在 《全局变量初始化顺序探究》里已经介绍过了)。

662b6666aa65693b00683d1d787c8088.png

可以发现,直接使用 msbuild.exe 编译也会定义 _DEBUG 宏。可以把 vs 从怀疑名单中划掉了。

注意看传递给 cl.exe 的参数(上图黄色高亮部分)中也没有 _DEBUG 宏的踪影。

难道是 msbuild 通过进程通信手段实现的?(真佩服自己的脑洞)

试试直接使用 cl.exe TestDebugMacro.cpp 编译。

柳暗花明

居然 _DEBUG 宏消失了!!!

e8b5e6065f9102bbe385336b91549ab9.png

通过 msbuild.exe 启动的 cl.exe ,从日志可以发现 cl.exe 的参数如下:

C:Program Files (x86)Microsoft Visual Studio 12.0VCbinCL.exe /c /ZI /nologo /W3 /WX- /Od /Oy- /D WIN32 /D _CONSOLE /D _LIB
   /D _UNICODE /D UNICODE /Gm /EHsc /RTC1 /MDd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fo"Debug" /Fd"Debugvc120.pdb" /Gd /TP
   /analyze- /errorReport:queue TestDebugMacro.cpp

而手动执行的 cl.exe 只传递了需要编译的文件名。会不会是哪个神奇的参数搞的鬼呢?好办,二分法排查!

经过几次尝试,很快定位到是 /MDd 搞得鬼!

3157f2007423139ca304762b40e211f3.png

/MDd 选项是何方神圣?搜索一下,很快找到了微软官方的介绍。

/MDd 选项

官方文档很明确的描述到:/MDd 选项会定义 _DEBUG_MT_DLL ,并且会使用调试 版本的多线程运行时库。

具体请介绍参考微软官方文档截图:

3223bb3d30ab06fd5599241610b44cf3.png

贴一张工程属性设置截图。

20b9a8a64fcdd85bd99364a1e825700b.png

反思

当时没有严格按照对比的思路进行排查,浪费了很多时间!

很久之前确实对比过 /MDd 几种选项的不同,当时的关注点主要在于会链接不同的运行时库,忽略了对宏的影响。相信经过这次折腾,我永远也忘不了 /MDd 选项定义 _DEBUG 宏。这个行为不是通过配置文件发生的,而是写到了 cl.exe 的文件中!

总结

  • File Locator 真可谓文件内容搜索神器,经常排错的小伙伴儿必备!
  • 一种情况是正常,一种情况不正常,最简单粗暴有效的办法就是对比
  • 排查问题时,我们要尽量简化问题,尽可能排除无关条件的干扰。
  • /MDd 选项不仅会影响链接库,还会定义 _DEBUG 宏。

参考资料

https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library?view=vs-2019

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值