Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Você pode criar binários Arm64X, também conhecidos como arquivos Arm64X PE, para suportar o carregamento de um único binário em processos x64/Arm64EC e Arm64.
Criar um binário Arm64X a partir de um projeto do Visual Studio
Para habilitar a criação de binários Arm64X, as páginas de propriedades da configuração Arm64EC têm uma nova propriedade "Build Project as ARM64X", conhecida como BuildAsX no arquivo de projeto.
Quando você cria um projeto, o Visual Studio normalmente compila para Arm64EC e, em seguida, vincula as saídas a um binário Arm64EC. Quando você define BuildAsX como true, o Visual Studio compila para Arm64EC e Arm64. A etapa de link Arm64EC vincula ambas as saídas a um único binário Arm64X. O diretório de saída desse binário Arm64X é o diretório de saída definido sob a configuração arm64EC.
Para BuildAsX trabalhar corretamente, você deve ter uma configuração existente do Arm64, além da configuração arm64EC. As configurações arm64 e arm64EC devem usar o mesmo runtime C e biblioteca padrão C++ (por exemplo, ambas definidas como /MT). Para evitar ineficiências de construção, como a construção de projetos completos em Arm64 ao invés de apenas compilação, defina BuildAsX como "true" para todas as referências diretas e indiretas do projeto.
O sistema de compilação assume que as configurações Arm64 e Arm64EC têm o mesmo nome. Se as configurações Arm64 e Arm64EC tiverem nomes diferentes (como Debug|ARM64 e MyDebug|ARM64EC), você poderá editar manualmente o vcxprojnome da configuração Arm64.
Se você quiser que o binário Arm64X combine dois projetos separados, um como Arm64 e outro como Arm64EC, você poderá editar manualmente o vxcproj do projeto Arm64EC para adicionar uma ARM64ProjectForX propriedade e especificar o caminho para o projeto Arm64. Os dois projetos devem estar na mesma solução.
Criando uma DLL Arm64X com o CMake
Para criar binários de projeto do CMake como Arm64X, use qualquer versão do CMake que dê suporte à criação como Arm64EC. Primeiro, crie o projeto direcionado ao Arm64 para gerar as entradas do vinculador Arm64. Em seguida, crie o projeto novamente visando o Arm64EC, combinando as entradas Arm64 e Arm64EC para formar binários Arm64X. As etapas a seguir mostram como usar CMakePresets.json.
Certifique-se de ter predefinições de configuração separadas direcionadas a Arm64 e Arm64EC. Por exemplo:
{ "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" } } ] }Adicione duas novas configurações que herdam das predefinições Arm64 e Arm64EC criadas na etapa anterior. Defina
BUILD_AS_ARM64XcomoARM64ECna configuração que herda de Arm64EC eBUILD_AS_ARM64XcomoARM64na outra. Essas variáveis significam que os builds dessas duas predefinições fazem parte do 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" } }Adicione um novo arquivo .cmake ao seu projeto CMake chamado
arm64x.cmake. Copie o snippet a seguir no novo arquivo .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 só terá suporte se você criar usando o vinculador MSVC do Visual Studio 17.11 ou posterior.
Se você precisar usar um vinculador mais antigo, copie o snippet a seguir. Essa rota usa um sinalizador /LINK_REPRO mais antigo. O uso da rota /LINK_REPRO resulta em um tempo de build geral mais lento devido à cópia de arquivos e tem problemas conhecidos ao usar o gerador 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()
Na parte inferior do arquivo de nível
CMakeLists.txtsuperior em seu projeto, adicione o snippet a seguir. Certifique-se de substituir o conteúdo dos colchetes angulares por valores reais. Esta etapa consome oarm64x.cmakearquivo que você acabou de criar.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()Crie seu projeto do CMake usando a predefinição Arm64X habilitada para Arm644 (arm64-debug-x).
Crie seu projeto do CMake usando a predefinição Arm64X compatível com Arm64EC (arm64ec-debug-x). As DLLs finais no diretório de saída para esse build são binários Arm64X.
Criando uma DLL de encaminhador puro Arm64X
Uma DLL de encaminhamento puro Arm64X é uma pequena DLL Arm64X que encaminha APIs para outras DLLs, dependendo do tipo delas:
As APIs do Arm64 são encaminhadas para uma DLL do Arm64.
APIs x64 são redirecionadas para uma DLL x64 ou Arm64EC.
Um encaminhador puro Arm64X permite as vantagens de usar um binário Arm64X, mesmo que haja desafios com a construção de um binário Arm64X mesclado contendo todo o código Arm64EC e Arm64. Para obter mais informações, consulte arquivos ARM64X PE.
Você pode criar um encaminhador puro Arm64X no prompt de comando do desenvolvedor do Arm64 seguindo as etapas abaixo. O encaminhador puro Arm64X resultante roteia chamadas x64 para foo_x64.DLL e chamadas Arm64 para foo_arm64.DLL.
Crie arquivos vazios
OBJque o vinculador usa para criar o encaminhador puro. Esses arquivos estão vazios porque o encaminhador puro não contém código. Para criar esses arquivos, crie um arquivo vazio. No exemplo a seguir, o arquivo é nomeado empty.cpp. Useclpara criar arquivos vaziosOBJ, com um para Arm64 (empty_arm64.obj) e outro para Arm64EC (empty_x64.obj):cl /c /Foempty_arm64.obj empty.cpp cl /c /arm64EC /Foempty_x64.obj empty.cppSe você vir a mensagem de erro "cl: aviso de linha de comando D9002: ignorando a opção desconhecida '-arm64EC'", você está usando o compilador errado. Para corrigir esse problema, alterne para o Prompt de Comando do Desenvolvedor do Arm64.
Crie arquivos
DEFpara x64 e Arm64. Esses arquivos listam todas as exportações de API da DLL e apontam o carregador para o nome da DLL que pode atender a essas chamadas de 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 criarLIBarquivos de importação para x64 e 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 os arquivos vazios
OBJe de importaçãoLIBusando o sinalizador/MACHINE:ARM64Xpara produzir a DLL do encaminhador 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
O resultado foo.dll pode ser carregado em um processo Arm64 ou x64/Arm64EC. Quando um processo Arm64 carrega foo.dll, o sistema operacional imediatamente carrega foo_arm64.dll em seu lugar, e todas as chamadas de API são tratadas por foo_arm64.dll.