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

8

我正在尝试使用/clr:pure和/clrimagetype:pure标志从C++/CLI项目创建纯MSIL程序集,但输出程序集明确针对x86目标。

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

2个回答

14
您可以使用C++/CLI创建一个AnyCPUDLL,但在最简单的情况下,您将无法使用MFC、ATL或CRT。然而,如果您只想在C++/CLI中编写纯托管的.NET代码,包括托管指针(/clr:safe不允许),并获得更详细的C++/CLI编译器的代码优化,请继续进行以下操作:
  1. 为了取得最佳效果,请从托管类库项目模板开始全新项目。将C++/CLI项目属性设置为DLL类库上的/clr:pure。这在Visual Studio 2010的“Configuration Properties”页面上。
  2. 在C/C++选项卡上,将Omit Default Library Name设置为Yes /Zl
  3. 对于链接器,请禁用Incremental LinkingLink Library Dependencies
  4. 在链接器的“高级”页面上,我将目标机器设置为Not Set,CLR图像类型设置为Force Pure IL Image /CLRIMAGETYPE:PURE,但显然这些设置并不被遵守,因为32BIT+标志仍然由链接器设置在PE32头文件中。
  5. 因此,在构建中添加一个corflags步骤。做到这一点的最佳方法是退出Visual Studio并使用文本编辑器编辑vcxproj文件。在该文件的底部添加:
        <!-- 在文件底部... -->
        <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")() { }

就这样,您现在可以构建AnyCPUDLL;它是纯MSIL,因为使用了'pure'设置,而且由于corflags的调整,它将作为x64x86加载。在运行时,请避免使用任何不兼容的功能,例如Interop。但是,与仅仅使用/clr:safe模式(也会生成一个AnyCPU库)的区别在于,您可以使用不安全的托管指针来访问托管值类型。


[编辑:]为了详细说明Ben Voight的评论,这种C++/CLI AnyCPU DLL中不起作用的一件事是使用C/C++初始化语法来初始化非托管(即本机的)静态基元、结构或(数组):

static int my_arr[] = { 1, 2, 3 };

链接器会发出以下警告:warning LNK4210: .CRTMA section exists; there may be unhandled static initializers or terminators。然而,您可以声明并手动初始化这些静态初始化程序或终止程序,并使用它们--即获取它们的地址--并从托管代码中读取/写入它们(如果您想将这样的数组声明为const,则必须为其提供空括号 { }作为初始化器,并将指针转换为volatile以进行初始化):

static int my_arr[3];

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

你问为什么要使用本机静态资源?因为它们可以快速访问而无需固定内存。一个好处是,C++/CLI 在这里仍然可以为您自动创建一个托管值类型(struct),以覆盖每个本机静态资源,这样 IL 代码就可以直接使用 IL 指针访问它们,从而保持程序集的/pure属性。

[编辑:更正了关于 AnyCPU 程序集中“本机”指针的错误陈述] [编辑:澄清:纯程序集中的“不安全” C# 代码使用的是通过 IL 指令(例如 ldloca 等)的托管指针。]


我还应该承认一下Kornél Pál,他被认为是发现如何制作模块构造函数存根的人。 - Glenn Slayden
你应该注意到,这会破坏任何全局对象,因为你正在删除CRT初始化代码,这些代码构造了它们。 - Ben Voigt
@BenVoight:说得好,而且肯定是真的。如果你的模块与CRT或MFC有任何关系,我认为我不会去碰上面描述的技术。相反,这是一种访问C++/CLI优化IL生成器并使用不安全构造的方法,仅适用于纯.NET模块。 - Glenn Slayden
你是否也知道一种去除对“Microsoft.VisualC”程序集引用的方法? - mmmmmmmm
看起来这个模块构造函数存根也会破坏所有虚方法调用,因为CRT还初始化了vtable。有人知道如何处理吗? - Amomum
谢谢!这非常有帮助。你知道为什么指针数组似乎不起作用吗:https://dev59.com/Zqzka4cB1Zd3GeqP_6eh - Imbue

4
如果您使用的是Visual Studio,则应该能够在链接器->高级设置下设置目标机器项目属性。
如果您要将C++/CLI项目编译为“任何CPU”,则需要在/clr:safe和/clrimagetype:safe中进行编译。有关更多信息,请参见以下链接:

http://bytes.com/topic/net/answers/660475-any-cpu-build-c-cli


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接