【问题标题】:Creating a pure MSIL assembly from a C++/CLI project?从 C++/CLI 项目创建纯 MSIL 程序集?
【发布时间】:2011-10-05 11:03:36
【问题描述】:

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

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

【问题讨论】:

    标签: visual-c++ c++-cli clr


    【解决方案1】:

    如果您使用的是 Visual Studio,您应该可以在 Linker -> Advanced settings 下设置 Target Machine 项目属性。

    如果您正在寻找将您的 C++/CLI 项目编译为“Any CPU”,那么您需要在 /clr:safe 和 /clrimagetype:safe 中进行编译。有关详细信息,请参阅以下链接:

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

    【讨论】:

      【解决方案2】:

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

      1. 为获得最佳结果,请从托管类库项目模板中的新项目开始。将 DLL 类库的 C++/CLI 项目属性设置为 /clr:pure。这是在 Visual Studio 2010 中的 Configuration Properties 页面上。
      2. 在 C/C++ 面板上,将 Omit Default Library Name 设置为 Yes /Zl
      3. 对于链接器,禁用Incremental Linking 和Link Library Dependencies
      4. 在链接器的“高级”页面上,我将 Target Machine 设置为 Not Set,并将 CLR Image Type 设置为 Force Pure IL Image /CLRIMAGETYPE:PURE,但其中一些明显的设置不适用,因为 32BIT+ 标志仍由PE32 标头中的链接器。
      5. 因此,在您的构建中添加一个corflags 步骤。最好的方法是退出 Visual Studio 并使用文本编辑器编辑 vcxproj 文件。在文件底部,添加:
            
            
                目标>
        
        这会运行corflags 工具来关闭 DLL 中的 32BIT 标志。确保corflags.exe 工具在您的路径中可用。
      6. 最后,向您的 C++/CLI 源文件添加一个存根条目。这是模块静态构造函数。对我有用的是将以下内容放在任何命名空间之外:
        #pragma warning(disable:4483)
        void __clrcall __identifier(".cctor")() { }

      就是这样,您现在可以构建 AnyCPU dll;由于“纯”设置,它是纯MSIL,并且由于corflags 调整,它将加载为x64 或x86。您可以在运行时避免使用任何不兼容的功能,例如互操作。然而——这是与仅仅使用/clr:safe 模式(也产生一个AnyCPU 库)的区别——你可以使用不安全的托管指针来访问托管值类型。


      [编辑:] 为了详细说明 Ben Voight 的评论,不会在这种类型的 C++/CLI AnyCPU dll 中起作用的一件事是使用 C/C++ 初始化语法初始化 unmanaged(即原生)、静态原语、结构(或数组):
      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 在这里仍然为您做的一件好事是默默地创建一个托管值类型(结构)来覆盖您的每个本机静态,以便 IL 代码可以直接使用 IL 获取它们指针,从而保持程序集 /pure.

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

      【讨论】:

      • 我还应该感谢 Kornél Pál,他发现了如何制作模块构造函数存根。
      • 您应该注意,这将破坏您可能拥有的任何全局对象,因为您正在删除构造它们的 CRT 初始化代码。
      • @BenVoight:说得好,当然是真的。如果您的模块与 CRT 或 MFC 有任何关系,我想我不会混淆上述技术。相反,这是一种访问 C++/CLI 优化 IL 生成器的方法——并对其使用不安全的构造——仅适用于纯 .NET 模块。
      • 您是否还知道摆脱对“Microsoft.VisualC”程序集的引用的方法?
      • 似乎这个模块构造函数存根也会破坏所有的虚拟方法调用,因为 CRT 也会初始化 vtables。有人知道怎么处理吗?
      猜你喜欢
      • 2018-12-13
      • 1970-01-01
      • 1970-01-01
      • 2017-04-15
      • 1970-01-01
      • 2011-01-10
      • 2019-08-15
      • 1970-01-01
      • 2010-10-02
      相关资源
      最近更新 更多