从C++/CLI项目创建纯MSIL程序集?

Anz*_*rio 8 clr c++-cli visual-c++

我试图使用/ clr:pure和/ clrimagetype:pure flags从C++/CLI项目创建纯MSIL程序集,但是,输出程序集专门针对x86.

我是否遗漏了可能阻止我的项目仅编译为MSIL的任何内容?

Gle*_*den 13

您可以使用C++/CLI创建AnyCPU dll ,但在最简单的情况下,您将无法使用MFC,ATL或CRT.但是,如果您只想在C++/CLI中编写纯托管.NET代码(包括托管指针(不允许)),并获得C++/CLI编译器的更精细的代码优化,请继续阅读:/clr:safe

  1. 为获得最佳结果,请从托管类库项目模板中的新项目开始.将DLL类库的C++/CLI项目属性设置为/clr:pure.这是Configuration Properties在Visual Studio 2010 的页面上.
  2. 在C/C++面板上,设置Omit Default Library NameYes /Zl
  3. 对于链接器,禁用Incremental LinkingLink Library Dependencies
  4. 在链接器的"高级"页面上,我将目标机器设置为Not Set和CLR图像类型为Force Pure IL Image /CLRIMAGETYPE:PURE,但是其中一些显着的设置不受尊重,因为32BIT +标志仍然由PE32头中的链接器设置.
  5. 因此,请corflags为您的构建添加一个步骤.执行此操作的最佳方法是退出Visual Studio并使用文本编辑器编辑vcxproj文件.在文件的底部,添加:
        <!-- at the bottom of the file... -->
        <Target Name="AfterBuild">
            <Exec Command="corflags $(TargetPath) /32BIT-" />
        </Target>
    </Project>
    这将运行该corflags工具来关闭DLL中的32BIT标志.确保corflags.exe您的路径中有该工具.
  6. 最后,将一个存根条目添加到C++/CLI源文件中.这是模块静态构造函数.对我有用的是将以下内容放在任何名称空间之外:
    #pragma warning(disable:4483)
    void __clrcall __identifier(".cctor")() { }

就是这样,你现在可以建立AnyCPU dll; 它是纯粹MSIL的'纯'设置,并且由于调整它将加载为x64x86corflags.您可以在运行时避免使用任何不兼容的功能,例如Interop.但是 - 这与仅使用/clr:safe模式(也产生AnyCPU库)的差异 - 您可以使用不安全的托管指针来访问托管值类型.


[编辑:]详细说明Ben Voight的评论,在这种类型的C++/CLI AnyCPU dll中无效的一件事是使用C/C++初始化语法初始化非托管(即本机),静态原语,结构,(或数组):

static int my_arr[] = { 1, 2, 3 };
Run Code Online (Sandbox Code Playgroud)

链接器发出此效果的警告warning LNK4210: .CRTMA section exists; there may be unhandled static initializers or terminators.但是,你可以声明它们,自己初始化它们,然后使用它们 - 也就是说,获取它们的地址 - 并从托管代码读取/写入它们(如果你想声明这样的数组const,那么你必须为{ }初始化程序提供空括号并转换指针volatile以初始化它.):

static int my_arr[3];
Run Code Online (Sandbox Code Playgroud)

具有讽刺意味的是,初始化这些本机静态资源或表的一种方法是在模块构造函数或类静态构造函数中从托管变量或资源复制它们.

你问,为什么要打扰原生静电?因为它们可以快速访问而无需固定.C++/CLI在这里仍然为您做的一件好事是静默创建一个托管值类型(struct)来覆盖每个本机静态,以便IL代码可以直接使用IL指针获取它们,从而保持程序集/纯洁.

[编辑:纠正了关于AnyCPU程序集中"本机"指针的错误陈述] [编辑:澄清:'不安全'纯程序集中的C#代码通过IL指令使用托管指针,如ldloca等.