Visual c++ LTCG没有';我不记得/O2是在编译时指定的

Visual c++ LTCG没有';我不记得/O2是在编译时指定的,visual-c++,optimization,c++-cli,Visual C++,Optimization,C++ Cli,背景 < >我使用命令> Cl>代码>代码>链接>代码>,构建一个由C++、混合C++、CLI和安全C++ +CLI组成的项目。我需要目标.NETFramework 2.0~3.5,所以我使用VC90工具链(我有VS2010,但安装了VS2008 C++快件和SDK,用于Windows 7和.NET 3.5 SP1,以获得完整的VC90工具链)。 如果我使用VS100工具链尝试我的脚本,它可以正常工作,但目标是.NETV4.0。如果我不将/GL用于我的本机代码和混合代码,它就可以工作。我知道这些

背景

< >我使用命令> Cl>代码>代码>链接>代码>,构建一个由C++、混合C++、CLI和安全C++ +CLI组成的项目。我需要目标.NETFramework 2.0~3.5,所以我使用VC90工具链(我有VS2010,但安装了VS2008 C++快件和SDK,用于Windows 7和.NET 3.5 SP1,以获得完整的VC90工具链)。 如果我使用VS100工具链尝试我的脚本,它可以正常工作,但目标是.NETV4.0。如果我不将
/GL
用于我的本机代码和混合代码,它就可以工作。我知道这些解决方案,所以不要建议它们。我试图理解为什么会发生这种情况

问题

如果我使用
/GL
/LTCG
我会在本机代码中收到以下许多警告:

xxx.cpp(####):警告C4748:
/GS
无法保护参数和局部变量不受局部缓冲区溢出的影响,因为函数中禁用了优化

以及混合代码中的以下错误:

c:\program files(x86)\microsoft visual studio 9.0\vc\include\vcclr.h(47):错误C4801:引用返回不可验证:在基本块中找不到返回的本地文件的定义

第二个用于Microsoft头文件中的PtrToStringChars,该头文件允许您将
String^
用作
const wchar\u t*
,并且该函数必须内联(并标记为内联)。“通过引用返回”在内联时实际上不是返回,因此没有错误

问题是我在编译时确实使用了优化!我使用标准的
/O2
,它具有最高级别的内联(
/Ob2
),通常允许
/GS

脚本

这是我的简编脚本

set TARGET=x86
call "%VS90COMNTOOLS%\..\..\VC\vcvarsall.bat" %TARGET%

set CL=/nologo /Zl /Zi /W4 /O2 /Oy- /GL /GS /EHa /MP /D NDEBUG /D _UNICODE /D UNICODE /D INTEGRATED /Fdout\ /Foout\
set LINK=/nologo /LTCG /CLRIMAGETYPE:IJW /MACHINE:%TARGET% /SUBSYSTEM:WINDOWS,6.0 /OPT:REF /OPT:ICF /DEFAULTLIB:msvcrt.lib /DEFAULTLIB:msvcmrt.lib
set CSC=/nologo /w:4 /d:INTEGRATED /o+ /target:module

set CL_NATIVE=/c /FI"stdafx-native.h"
set CL_MIXED=/c /clr /LN /FI"stdafx-mixed.h"
set CL_PURE=/c /clr:safe /LN /GL /FI"stdafx-pure.h"

set NATIVE=a.cpp b.cpp ...
set MIXED=c.cpp d.cpp ...
set PURE=e.cpp f.cpp ...

cl %CL_NATIVE% %NATIVE%
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%

cl %CL_MIXED% %MIXED%
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%

cl %CL_PURE% %PURE%
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%

link /LTCG /NOASSEMBLY /DLL /OUT:"out\x.netmodule" out\*.obj
IF %ERRORLEVEL% NEQ 0 EXIT /B %ERRORLEVEL%

短版本:MSIL中的内联在JIT期间,在代码验证程序执行可访问性检查之后发生。

长版本:

整个程序优化不适用于MSIL,因为MSIL总是跨编译单元,甚至跨程序集进行优化(除非调试关闭了优化)。我认为这是你警告的来源

许多优化都是JIT的责任,包括内联。再加上可访问性检查,这就阻止了C++编译器在MSIL上运行内联传递。(如果使用私有成员的成员函数在本机C++中被内联了,那么会发生什么?如果使用私有成员的成员函数在MSIL中被内嵌到一个不能访问这些私有成员的函数中会发生什么?.NET运行时会引发绝对匹配。不适用于MSIL。)这就是为什么


…使用
PtrToStringChars
/clr:safe
不兼容,因为它不可验证。但是
/clr
/clr:pure
都可以,因为它们都不尝试创建可验证的程序集。如上所述,在
/clr
模式下编译时,不允许编译器内联。这就是你的错误的来源


最后一个问题是创建netmodule。我很确定混合模式代码必须创建为完整的程序集,而不是网络模块。

PtrToStringChars
被“混合”的代码用作
/clr:safe
和本机代码之间的互操作。它仅包含在
stdafx mixed.h
标题中。所以这是用
/clr
编译的。我告诉链接器在
netmodule
上使用
/clr
/CLRIMAGETYPE:IJW
)。这应该是可能的(我已经让它部分工作)。看看我的最终目标是什么。@thiamin:更仔细地研究那篇博客文章。本机代码永远不会出现在netmodule中。相反,C + NETMAMP模块被C++链接器拉入,以创建一个单一的混合模式PE。但是,由于编译失败,您甚至还无法访问链接。尝试将/GL和/GS移到本机编译选项,它们在编译托管代码时没有任何好处。@thaimin:对不起,上一条注释中拼写错误了句柄。再次注释以确保您得到通知。@BenVoigt Pure和一些混合托管代码确实被放入初始netmodule中。C#与该netmodule一起编译,以创建新的netmodule。然后所有的obj和C#netmodule被链接到一个EXE中。在任何一个链接步骤中,使用
LTCG
仅对使用
GL
GS
编译的本机代码和混合代码产生这些警告/错误。即使我将
LTCG
延迟到最后一个链接,它仍然无法工作。如果本机代码或混合代码都没有
GL
,我可以编译一个EXE(正如您所说的
GL
for pure code不会做任何事情,所以没有问题)。