Visual C 强制未使用的导入,由库引入
Visual C forces unused import, pulled in by a library
最近更新了一个项目,从 Visual Studio 2010 年到 2015 年,我们 运行 遇到了一个奇怪的 link 时间问题。
我们为 amd64 和 x86 以及调试和发布模式构建项目。
该项目有 2 个依赖项,我们称它们为 libA 和 libB。
我们有一些自定义的 post-build 脚本,可以对二进制文件进行一些验证(例如检查 NX 和 SEH 标志等)。
使用此脚本,我们还验证导入的 DLL 及其导入的函数,以尽可能减少静态导入并尝试通过动态加载解决额外的问题(为了向后兼容)。
迁移后,我们设法在每个可能的配置中构建所有内容,但在 DEBUG 模式(并且仅在 DEBUG 模式下)生成的二进制文件 - 由于代码存在于 libA - 引入一些导入 - 让我们称之为 dllA - 实际上没有使用,因此不希望存在。
libB 没有引入任何问题 - 虽然它是一个非常简单的库。
libA 引入这些导入的原因是因为它是一个多用途库,被其他一些项目使用,并且它有一些代码,可以调用来自dllA,但在我们的项目中,我们根本不调用那些 dllA-export-calling-functions。
我还用 IDA 反汇编了 dll,发现这些函数位于二进制文件中,与二进制文件的其余代码完全断开连接——它们根本没有被引用。
经过一番搜索,并尝试 link RELEASE 版本的 libA 到我们的 DEBUG 我们项目的构建,我发现,从 dllA 的导入不再被引入,让我觉得,库配置可能是问题所在。
我获取了库的调试和发布版本的命令行参数,并将它们并排比较,以找出配置上的差异。
我设法将问题定位到优化设置(在优化选项卡上):
- 对于 DEBUG 模式,默认设置为禁用 (/Od)
- 对于 RELEASE 模式,它设置为最大化速度 (/O2)
- 为 DEBUG 模式设置 Maximize Speed (/O2) 可以解决问题 - 不再导入 dllA
我的问题是,这对于调试来说确实是违反直觉的,因为编译器会优化掉太多东西,可能会使调试变得更加困难。
在 posting 之前,我到处看了看,还在我们的主项目的 Linker->Optimization 页面中查看,References 选项设置为 Yes (/OPT:REF),这应该避免 linking 未使用的代码,但在我看来,VS2015 在调试版本上完全忽略了这个设置。
经过一番搜索找到这篇文章:http://www.drdobbs.com/cpp/the-most-underused-compiler-switches-in/240166599?pgno=6。
事实证明,在 libA 中设置选项 /Gy(启用函数级链接) 不再导致未使用的 API被进口
最近更新了一个项目,从 Visual Studio 2010 年到 2015 年,我们 运行 遇到了一个奇怪的 link 时间问题。
我们为 amd64 和 x86 以及调试和发布模式构建项目。 该项目有 2 个依赖项,我们称它们为 libA 和 libB。 我们有一些自定义的 post-build 脚本,可以对二进制文件进行一些验证(例如检查 NX 和 SEH 标志等)。 使用此脚本,我们还验证导入的 DLL 及其导入的函数,以尽可能减少静态导入并尝试通过动态加载解决额外的问题(为了向后兼容)。
迁移后,我们设法在每个可能的配置中构建所有内容,但在 DEBUG 模式(并且仅在 DEBUG 模式下)生成的二进制文件 - 由于代码存在于 libA - 引入一些导入 - 让我们称之为 dllA - 实际上没有使用,因此不希望存在。 libB 没有引入任何问题 - 虽然它是一个非常简单的库。
libA 引入这些导入的原因是因为它是一个多用途库,被其他一些项目使用,并且它有一些代码,可以调用来自dllA,但在我们的项目中,我们根本不调用那些 dllA-export-calling-functions。 我还用 IDA 反汇编了 dll,发现这些函数位于二进制文件中,与二进制文件的其余代码完全断开连接——它们根本没有被引用。
经过一番搜索,并尝试 link RELEASE 版本的 libA 到我们的 DEBUG 我们项目的构建,我发现,从 dllA 的导入不再被引入,让我觉得,库配置可能是问题所在。 我获取了库的调试和发布版本的命令行参数,并将它们并排比较,以找出配置上的差异。 我设法将问题定位到优化设置(在优化选项卡上):
- 对于 DEBUG 模式,默认设置为禁用 (/Od)
- 对于 RELEASE 模式,它设置为最大化速度 (/O2)
- 为 DEBUG 模式设置 Maximize Speed (/O2) 可以解决问题 - 不再导入 dllA
我的问题是,这对于调试来说确实是违反直觉的,因为编译器会优化掉太多东西,可能会使调试变得更加困难。
在 posting 之前,我到处看了看,还在我们的主项目的 Linker->Optimization 页面中查看,References 选项设置为 Yes (/OPT:REF),这应该避免 linking 未使用的代码,但在我看来,VS2015 在调试版本上完全忽略了这个设置。
经过一番搜索找到这篇文章:http://www.drdobbs.com/cpp/the-most-underused-compiler-switches-in/240166599?pgno=6。
事实证明,在 libA 中设置选项 /Gy(启用函数级链接) 不再导致未使用的 API被进口