Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Puede compilar archivos binarios Arm64X, también conocidos como archivos ARM64X PE, para admitir la carga de un solo archivo binario en procesos x64/Arm64EC y Arm64.
Compilación de un binario arm64X desde un proyecto de Visual Studio
Para habilitar la compilación de archivos binarios arm64X, las páginas de propiedades de la configuración de Arm64EC tienen una nueva propiedad llamada "Build Project as ARM64X", conocida como BuildAsX en el archivo de proyecto.
Al compilar un proyecto, Visual Studio normalmente compila el código para Arm64EC y, a continuación, vincula los resultados en un binario Arm64EC. Cuando se establece BuildAsX en true, Visual Studio compila código compatible con Arm64EC y Arm64. El paso de vínculo Arm64EC vincula ambas salidas en un único binario Arm64X. El directorio de salida de este binario Arm64X es el directorio de salida establecido en la configuración de Arm64EC.
Para que BuildAsX funcione correctamente, debe tener una configuración Arm64 ya existente, además de la configuración de Arm64EC. Las configuraciones arm64 y Arm64EC deben usar el mismo entorno de ejecución de C y la misma biblioteca estándar de C++ (por ejemplo, ambos establecidos en /MT). Para evitar ineficacias de construcción, como construir proyectos completos de Arm64 en lugar de simplemente compilar, establezca BuildAsX en verdadero para todas las referencias directas e indirectas del proyecto.
El sistema de compilación supone que las configuraciones de Arm64 y Arm64EC tienen el mismo nombre. Si las configuraciones de Arm64 y Arm64EC tienen nombres diferentes (como Debug|ARM64 y MyDebug|ARM64EC), puede editar manualmente el archivo vcxproj o Directory.Build.props para añadir una propiedad ARM64ConfigurationNameForX a la configuración de Arm64EC que proporcione el nombre de la configuración de Arm64.
Si desea que el binario Arm64X combine dos proyectos independientes, uno como Arm64 y otro como Arm64EC, puede editar manualmente el vxcproj del proyecto arm64EC para agregar una ARM64ProjectForX propiedad y especificar la ruta de acceso al proyecto arm64. Los dos proyectos deben estar en la misma solución.
Creación de un archivo DLL de Arm64X con CMake
Para compilar los archivos binarios del proyecto de CMake como Arm64X, use cualquier versión de CMake que admita la compilación como Arm64EC. En primer lugar, compile el proyecto destinado a Arm64 para generar las entradas del enlazador arm64. A continuación, vuelva a compilar el proyecto con el objetivo de Arm64EC, combinando las entradas Arm64 y Arm64EC para formar archivos binarios Arm64X. En los pasos siguientes se muestra cómo usar CMakePresets.json.
Asegúrese de que tiene valores preestablecidos de configuración independientes destinados a Arm64 y Arm64EC. Por ejemplo:
{ "version": 3, "configurePresets": [ { "name": "windows-base", "hidden": true, "binaryDir": "${sourceDir}/out/build/${presetName}", "installDir": "${sourceDir}/out/install/${presetName}", "cacheVariables": { "CMAKE_C_COMPILER": "cl.exe", "CMAKE_CXX_COMPILER": "cl.exe" }, "generator": "Visual Studio 17 2022", }, { "name": "arm64-debug", "displayName": "arm64 Debug", "inherits": "windows-base", "hidden": true, "architecture": { "value": "arm64", "strategy": "set" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } }, { "name": "arm64ec-debug", "displayName": "arm64ec Debug", "inherits": "windows-base", "hidden": true, "architecture": { "value": "arm64ec", "strategy": "set" }, "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } } ] }Agregue dos nuevas configuraciones que heredan de los valores preestablecidos arm64 y Arm64EC que creó en el paso anterior. Establezca
BUILD_AS_ARM64XenARM64ECen la configuración que hereda de Arm64EC yBUILD_AS_ARM64XenARM64en la otra. Estas variables indican que las compilaciones a partir de estos dos valores preestablecidos forman parte de Arm64X.{ "name": "arm64-debug-x", "displayName": "arm64 Debug (arm64x)", "inherits": "arm64-debug", "cacheVariables": { "BUILD_AS_ARM64X": "ARM64" } }, { "name": "arm64ec-debug-x", "displayName": "arm64ec Debug (arm64x)", "inherits": "arm64ec-debug", "cacheVariables": { "BUILD_AS_ARM64X": "ARM64EC" } }Agregue un nuevo archivo .cmake al proyecto de CMake denominado
arm64x.cmake. Copie el siguiente fragmento de código en el nuevo archivo .cmake.# directory where the link.rsp file generated during arm64 build will be stored set(arm64ReproDir "${CMAKE_CURRENT_SOURCE_DIR}/repros") # This function reads in the content of the rsp file outputted from arm64 build for a target. Then passes the arm64 libs, objs and def file to the linker using /machine:arm64x to combine them with the arm64ec counterparts and create an arm64x binary. function(set_arm64_dependencies n) set(REPRO_FILE "${arm64ReproDir}/${n}.rsp") file(STRINGS "${REPRO_FILE}" ARM64_OBJS REGEX obj\"$) file(STRINGS "${REPRO_FILE}" ARM64_DEF REGEX def\"$) file(STRINGS "${REPRO_FILE}" ARM64_LIBS REGEX lib\"$) string(REPLACE "\"" ";" ARM64_OBJS "${ARM64_OBJS}") string(REPLACE "\"" ";" ARM64_LIBS "${ARM64_LIBS}") string(REPLACE "\"" ";" ARM64_DEF "${ARM64_DEF}") string(REPLACE "/def:" "/defArm64Native:" ARM64_DEF "${ARM64_DEF}") target_sources(${n} PRIVATE ${ARM64_OBJS}) target_link_options(${n} PRIVATE /machine:arm64x "${ARM64_DEF}" "${ARM64_LIBS}") endfunction() # During the arm64 build, create link.rsp files that containes the absolute path to the inputs passed to the linker (objs, def files, libs). if("${BUILD_AS_ARM64X}" STREQUAL "ARM64") add_custom_target(mkdirs ALL COMMAND cmd /c (if not exist \"${arm64ReproDir}/\" mkdir \"${arm64ReproDir}\" )) foreach (n ${ARM64X_TARGETS}) add_dependencies(${n} mkdirs) # tell the linker to produce this special rsp file that has absolute paths to its inputs target_link_options(${n} PRIVATE "/LINKREPROFULLPATHRSP:${arm64ReproDir}/${n}.rsp") endforeach() # During the ARM64EC build, modify the link step appropriately to produce an arm64x binary elseif("${BUILD_AS_ARM64X}" STREQUAL "ARM64EC") foreach (n ${ARM64X_TARGETS}) set_arm64_dependencies(${n}) endforeach() endif()
/LINKREPROFULLPATHRSP solo se admite si se compila mediante el enlazador MSVC desde Visual Studio 17.11 o posterior.
Si necesita usar un enlazador anterior, copie el siguiente fragmento de código en su lugar. Esta ruta usa una marca /LINK_REPRO anterior. El uso de la ruta /LINK_REPRO da como resultado un tiempo de compilación general más lento debido a la copia de archivos y tiene problemas conocidos al usar el generador Ninja.
# directory where the link_repro directories for each arm64x target will be created during arm64 build.
set(arm64ReproDir "${CMAKE_CURRENT_SOURCE_DIR}/repros")
# This function globs the linker input files that was copied into a repro_directory for each target during arm64 build. Then it passes the arm64 libs, objs and def file to the linker using /machine:arm64x to combine them with the arm64ec counterparts and create an arm64x binary.
function(set_arm64_dependencies n)
set(ARM64_LIBS)
set(ARM64_OBJS)
set(ARM64_DEF)
set(REPRO_PATH "${arm64ReproDir}/${n}")
if(NOT EXISTS "${REPRO_PATH}")
set(REPRO_PATH "${arm64ReproDir}/${n}_temp")
endif()
file(GLOB ARM64_OBJS "${REPRO_PATH}/*.obj")
file(GLOB ARM64_DEF "${REPRO_PATH}/*.def")
file(GLOB ARM64_LIBS "${REPRO_PATH}/*.LIB")
if(NOT "${ARM64_DEF}" STREQUAL "")
set(ARM64_DEF "/defArm64Native:${ARM64_DEF}")
endif()
target_sources(${n} PRIVATE ${ARM64_OBJS})
target_link_options(${n} PRIVATE /machine:arm64x "${ARM64_DEF}" "${ARM64_LIBS}")
endfunction()
# During the arm64 build, pass the /link_repro flag to linker so it knows to copy into a directory, all the file inputs needed by the linker for arm64 build (objs, def files, libs).
# extra logic added to deal with rebuilds and avoiding overwriting directories.
if("${BUILD_AS_ARM64X}" STREQUAL "ARM64")
foreach (n ${ARM64X_TARGETS})
add_custom_target(mkdirs_${n} ALL COMMAND cmd /c (if exist \"${arm64ReproDir}/${n}_temp/\" rmdir /s /q \"${arm64ReproDir}/${n}_temp\") && mkdir \"${arm64ReproDir}/${n}_temp\" )
add_dependencies(${n} mkdirs_${n})
target_link_options(${n} PRIVATE "/LINKREPRO:${arm64ReproDir}/${n}_temp")
add_custom_target(${n}_checkRepro ALL COMMAND cmd /c if exist \"${n}_temp/*.obj\" if exist \"${n}\" rmdir /s /q \"${n}\" 2>nul && if not exist \"${n}\" ren \"${n}_temp\" \"${n}\" WORKING_DIRECTORY ${arm64ReproDir})
add_dependencies(${n}_checkRepro ${n})
endforeach()
# During the ARM64EC build, modify the link step appropriately to produce an arm64x binary
elseif("${BUILD_AS_ARM64X}" STREQUAL "ARM64EC")
foreach (n ${ARM64X_TARGETS})
set_arm64_dependencies(${n})
endforeach()
endif()
En la parte inferior del archivo de nivel
CMakeLists.txtsuperior del proyecto, agregue el siguiente fragmento de código. Asegúrese de sustituir el contenido de los corchetes angulares por valores reales. Este paso consume elarm64x.cmakearchivo que acaba de crear.if(DEFINED BUILD_AS_ARM64X) set(ARM64X_TARGETS <Targets you want to Build as ARM64X>) include("<directory location of the arm64x.cmake file>/arm64x.cmake") endif()Compila tu proyecto de CMake utilizando el preajuste habilitado para Arm64X (arm64-debug-x).
Compile el proyecto CMake utilizando el valor preestablecido arm64ec habilitado para Arm64X (arm64ec-debug-x). Los archivos DLL finales del directorio de salida de esta compilación son archivos binarios arm64X.
Compilación de un archivo DLL reenviador puro Arm64X
Un archivo DLL reenviador puro Arm64X es un pequeño archivo DLL Arm64X que reenvía las API a archivos DLL independientes en función de su tipo:
Las API de Arm64 se reenvieron a un archivo DLL de Arm64.
las API x64 se reenvían a un archivo DLL x64 o Arm64EC.
Un reenviador puro Arm64Xpermite las ventajas de utilizar un archivo binario Arm64X incluso si hay problemas al compilar un archivo binario Arm64X combinado que contenga todo el código Arm64EC y Arm64. Para obtener más información, vea Archivos ARM64X PE.
Puede crear un reenviador puro arm64X desde el símbolo del sistema para desarrolladores de Arm64 siguiendo los pasos que se indican a continuación. El reenviador puro arm64X resultante enruta las llamadas x64 a foo_x64.DLL y las llamadas arm64 a foo_arm64.DLL.
Cree archivos vacíos
OBJque el enlazador usa para crear el reenviador puro. Estos archivos están vacíos porque el reenviador puro no contiene código. Para crear estos archivos, cree un archivo vacío. En el ejemplo siguiente, el archivo se denomina empty.cpp. Useclpara crear archivos vacíosOBJ, con uno para Arm64 (empty_arm64.obj) y otro para Arm64EC (empty_x64.obj):cl /c /Foempty_arm64.obj empty.cpp cl /c /arm64EC /Foempty_x64.obj empty.cppSi ve el mensaje de error "cl : advertencia de línea de comandos D9002 : omitir la opción desconocida '-arm64EC'", está usando el compilador incorrecto. Para corregir este problema, cambie al símbolo del sistema para desarrolladores de Arm64.
Cree archivos
DEFpara x64 y Arm64. Estos archivos enumeran todas las exportaciones de API del archivo DLL y apuntan el cargador al nombre del archivo DLL que puede cumplir esas llamadas API.foo_x64.def:EXPORTS MyAPI1 = foo_x64.MyAPI1 MyAPI2 = foo_x64.MyAPI2foo_arm64.def:EXPORTS MyAPI1 = foo_arm64.MyAPI1 MyAPI2 = foo_arm64.MyAPI2Use
linkpara crearLIBarchivos de importación para x64 y Arm64:link /lib /machine:x64 /def:foo_x64.def /out:foo_x64.lib link /lib /machine:arm64 /def:foo_arm64.def /out:foo_arm64.libVincule los archivos vacíos
OBJe importadosLIBmediante la marca/MACHINE:ARM64Xpara generar el archivo DLL del reenviador puro arm6X: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
El foo.dll resultante se puede cargar en un proceso Arm64 o x64/Arm64EC. Cuando un proceso de Arm64 carga foo.dll, el sistema operativo carga foo_arm64.dll inmediatamente en su lugar y las llamadas a la API se controlan mediante foo_arm64.dll.