生成 Arm64X 二进制文件

你可以生成 Arm64X 二进制文件(也称为 Arm64X PE 文件),以支持将单个二进制文件加载到 x64/Arm64EC 和 Arm64 进程。

从 Visual Studio 项目生成 Arm64X 二进制文件

若要启用生成 Arm64X 二进制文件,Arm64EC 配置的属性页新增了“生成项目作为 ARM64X”属性,即项目文件中的 BuildAsX

Arm64EC 配置的属性页,其中显示“生成项目为 ARM64X”选项

当用户生成项目时,Visual Studio 通常会针对 Arm64EC 进行编译,然后将输出链接到 Arm64EC 二进制文件。 当 BuildAsX 别设置为 true 时,Visual Studio 将改为同时为 Arm64EC Arm64 进行编译。 然后,使用 Arm64EC 链接步骤将两者同时链接到一个 Arm64X 二进制文件。 Arm64X 二进制文件的输出目录将与 Arm64EC 配置中设置的输出目录相同。

若要让 BuildAsX 正常工作,除了 Arm64EC 配置之外,用户还必须拥有现有的 Arm64 配置。 Arm64 和 Arm64EC 配置必须具有相同的 C 运行时和 C++ 标准库(例如,同时设置 /MT)。 为了避免生成效率低下的问题,例如生成完整的 Arm64 项目,而不仅仅是编译,项目的所有直接和间接引用都应将 BuildAsX 设置为 true。

生成系统假定 Arm64 和 Arm64EC 配置具有相同的名称。 如果 Arm64 和 Arm64EC 配置的名称不同(例如 Debug|ARM64MyDebug|ARM64EC)你可以手动编辑 vcxprojDirectory.Build.props 文件,以便为提供 Arm64 配置名称的 Arm64EC 配置添加 ARM64ConfigurationNameForX 属性。

如果所需的 Arm64X 二进制文件是两个独立项目(一个是 Arm64 项目,另一个是 Arm64EC 项目)的组合,则可以手动编辑 Arm64EC 项目的 vxcproj,以便添加 ARM64ProjectForX 属性并指定 Arm64 项目的路径。 这两个项目必须在同一个解决方案中。

生成 Arm64X 纯转发器 DLL

Arm64X 纯转发器 DLL 是一个小型 Arm64X DLL,它会根据 API 的类型将 API 转发到单独的 DLL:

  • Arm64 API 会被转发到 Arm64 DLL,并且
  • x64 API 会被转发到 x64 或 Arm64EC DLL。

即使在生成包含所有 Arm64EC 和 Arm64 代码的合并 Arm64X 二进制文件时遇到困难,Arm64X 纯转发器也能发挥使用 Arm64X 二进制文件的优势。 在 Arm64X PE 文件概述页面了解有关 Arm64X 纯转发器 DLL 的更多信息。

你可以按照以下步骤从 Arm64 开发人员命令提示符生成 Arm64X 纯转发器。 生成的 Arm64X 纯转发器会将 x64 调用路由至 foo_x64.DLL,并将 Arm64 调用路由至 foo_arm64.DLL

  1. 创建稍后供链接器用来创建纯转发器的空 OBJ 文件。 这些文件都是空的,因为纯转发器中没有代码。 为此,请创建一个空文件。 对于以下示例,我们将文件命名为 empty.cpp。 然后使用 cl 来创建空 OBJ 文件,其中一个用于 Arm64 (empty_arm64.obj),而另一个用于 Arm64EC (empty_x64.obj):

    cl /c /Foempty_arm64.obj empty.cpp
    cl /c /arm64EC /Foempty_x64.obj empty.cpp
    

    如果出现错误消息“cl : Command line warning D9002 : ignoring unknown option '-arm64EC'”,则说明使用的编译器不正确。 若要解决此问题,请切换到 ARM64 开发人员命令提示符

  2. 为 x64 和 Arm64 创建 DEF 文件。 这些文件枚举了 DLL 的所有 API 导出,并将加载程序指向可实现这些 API 调用的 DLL 的名称。

    foo_x64.def:

    EXPORTS
        MyAPI1  =  foo_x64.MyAPI1
        MyAPI2  =  foo_x64.MyAPI2
    

    foo_arm64.def:

    EXPORTS
        MyAPI1  =  foo_arm64.MyAPI1
        MyAPI2  =  foo_arm64.MyAPI2
    
  3. 然后,你可以使用 link 来为 x64 和 Arm64 创建 LIB 导入文件:

    link /lib /machine:x64 /def:foo_x64.def /out:foo_x64.lib
    link /lib /machine:arm64 /def:foo_arm64.def /out:foo_arm64.lib
    
  4. 链接空的 OBJ 并使用标志 /MACHINE:ARM64X 导入 LIB 文件,以便生成 Arm6X 纯转发器 DLL:

    link /dll /noentry /machine:arm64x /defArm64Native:foo_arm64.def /def:foo_x64.def empty_arm64.obj empty_x64.obj /out:foo.dll foo_arm64.lib foo_x64.lib
    

最终的 foo.dll 可以被加载到 Arm64 或 x64/Arm64EC 进程中。 当 Arm64 进程加载 foo.dll 时,操作系统将立即加载 foo_arm64.dll 到其位置,而任何 API 调用都将由 foo_arm64.dll 处理。