0
votes

Background

I am using CL and LINK from the command line to build a project composed of native C++, mixed C++/CLI, and safe C++/CLI. I need to target .NET Framework 2.0-3.5 so I am using the VC90 toolchain (I have VS2010 but installed VS2008 C++ express and the SDK for Windows 7 and .NET 3.5 SP1 to get the complete VC90 toolchain).

If I try my script with the VS100 toolchain it works fine but targets .NET v4.0. If I don't use /GL for my native and mixed code it works. I know of these solutions, so don't suggest them. I am trying to understand why this is occurring.

Problem

If I use /GL and /LTCG I get many of the following warnings in the native code:

xxx.cpp(###) : warning C4748: /GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function

And the following error in the mixed code:

c:\program files (x86)\microsoft visual studio 9.0\vc\include\vcclr.h(47) : error C4801: Return by reference is not verifiable: definition of returned local not found in basic block

The second one is for PtrToStringChars from a Microsoft header file that allows you to use a String^ as const wchar_t* and is a function that MUST be inlined (and is marked inline). The "return by reference" won't actually be a return when inlined, thus no error.

The issue is that I do use optimizations while compiling! I use the standard /O2 which has the highest level of inlining (/Ob2) and normally allows /GS.

Script

Here is my abridged compilation script

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%
1

1 Answers

2
votes

Short Version: Inlining in MSIL takes place during JIT, after the code verifier performs accessibility checking.

Long Version:

Whole-Program Optimization doesn't apply to MSIL, because MSIL always gets optimized across compile units, and even across assemblies (unless optimizations are turned off by debug). I think this is the source of your warnings.

Many optimizations are the responsibility of the JIT, including inlining. Coupled with accessibility checks, this prevents the C++ compiler from running an inlining pass on MSIL. (What happens if a member function using private members get inlined in native C++? Not much. What happens if a member function using private members gets inlined in MSIL into a function that has no access to those private members? The .NET runtime throws an absolute fit. Everything you think you know about compiler settings for inlining just doesn't apply to MSIL.) This is why...

...use of PtrToStringChars is incompatible with /clr:safe because it isn't verifiable. It should be fine with /clr though, and also with /clr:pure since neither of those try to create verifiable assemblies. As mentioned, the compiler is not allowed to inline when compiling in /clr modes. This is the source of your error.

A final problem is creation of a netmodule. I'm pretty sure that mixed-mode code has to be created as full-blown assemblies and not netmodules.