Aracılığıyla paylaş


Arm64X ikili dosyaları oluşturma

x64/Arm64EC ve Arm64 işlemlerine tek bir ikili dosya yüklemeyi desteklemek amacıyla,Arm64X PE dosyaları olarak da bilinen Arm64X ikili dosyaları oluşturabilirsiniz.

Visual Studio projesinden Arm64X ikili dosyası oluşturma

Arm64X ikili dosyalarının oluşturulmasını etkinleştirmek için Arm64EC yapılandırmasının özellik sayfalarında proje dosyasında BuildAsX olarak bilinen yeni bir "BUILD Project as ARM64X" özelliği vardır.

Arm64EC yapılandırması için ARM64X olarak Proje Oluştur seçeneğini gösteren Özellik sayfası

Bir proje oluşturduğunuzda, Visual Studio normalde Arm64EC için derleme yapar ve çıkışları bir Arm64EC ikilisine bağlar. BuildAsX öğesini true olarak ayarladığınızda, Visual Studio hem Arm64EC hem de Arm64 için derler. Arm64EC bağlantı adımı her iki çıkışı da tek bir Arm64X ikilisine bağlar. Bu Arm64X ikili dosyasının çıkış dizini , Arm64EC yapılandırması altında ayarlanan çıkış dizinidir.

Düzgün çalışması için BuildAsX Arm64EC yapılandırmasına ek olarak mevcut bir Arm64 yapılandırmanız olmalıdır. Arm64 ve Arm64EC yapılandırmaları aynı C çalışma zamanını ve C++ standart kitaplığını kullanmalıdır (örneğin, her ikisi de /MT olarak ayarlanmıştır). Derleme yerine tam Arm64 projeleri oluşturma gibi derleme verimsizliklerini önlemek için projenin tüm doğrudan ve dolaylı başvuruları için true olarak ayarlayın BuildAsX .

Derleme sistemi, Arm64 ve Arm64EC yapılandırmalarının aynı isme sahip olduğunu varsayar. Arm64 ve Arm64EC yapılandırmalarının farklı adları varsa (Debug|ARM64 ve MyDebug|ARM64ECgibi), Arm64EC yapılandırmasının adını sağlayan Arm64EC yapılandırmasına bir özelliği eklemek için Directory.Build.props veya ARM64ConfigurationNameForX dosyasını el ile düzenleyebilirsiniz.

Arm64X ikili dosyasının biri Arm64, diğeri Arm64EC olmak üzere iki ayrı projeyi birleştirmesini istiyorsanız, arm64EC projesinin vxcproj'unu el ile düzenleyerek bir ARM64ProjectForX özellik ekleyebilir ve Arm64 projesinin yolunu belirtebilirsiniz. İki projenin aynı çözümde olması gerekir.

CMake ile Arm64X DLL oluşturma

CMake proje ikili dosyalarınızı Arm64X olarak oluşturmak için Arm64EC olarak oluşturmayı destekleyen herhangi bir CMake sürümünü kullanın. İlk olarak Arm64 bağlayıcı girişlerini oluşturmak için Arm64'i hedefleyen projeyi oluşturun. Ardından, Arm64 ve Arm64EC girişlerini birleştirerek Arm64X ikili dosyalarını oluşturmak amacıyla projeyi Arm64EC'yi hedefleyerek yeniden inşa edin. Aşağıdaki adımlarda CMakePresets.jsonnasıl kullanılacağı gösterilmektedir.

  1. Arm64 ve Arm64EC'i hedefleyen ayrı yapılandırma ön ayarlarına sahip olduğunuzdan emin olun. Örneğin:

     {
       "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"
           }
         }
       ]
     }
    
  2. Önceki adımda oluşturduğunuz Arm64 ve Arm64EC ön ayarlarından devralan iki yeni yapılandırma ekleyin. BUILD_AS_ARM64X'ı Arm64EC'den devralan yapılandırmada ARM64EC olarak, diğerinde BUILD_AS_ARM64X'yi ARM64 olarak ayarlayın. Bu değişkenler, bu iki ön ayardan gelen derlemelerin Arm64X'in bir parçası olduğunu belirtir.

         {
           "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"
           }
           }
    
  3. CMake projenize arm64x.cmakeadlı yeni bir .cmake dosyası ekleyin. Aşağıdaki kod parçacığını yeni .cmake dosyasına kopyalayın.

     # 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 yalnızca Visual Studio 17.11 veya sonraki sürümlerinden MSVC bağlayıcısını kullanarak derlemeniz durumunda desteklenir.

Daha eski bir bağlayıcı kullanmanız gerekiyorsa bunun yerine aşağıdaki kod parçacığını kopyalayın. Bu rota, /LINK_REPROgibi eski bir bayrak kullanır. /LINK_REPRO yolunun kullanılması, dosyaların kopyalanması nedeniyle genel derleme süresinin daha yavaş olmasına ve Ninja oluşturucu kullanırken bilinen sorunlara neden olur.

# 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()
  1. Projenizdeki en üst düzey CMakeLists.txt dosyanın en altına aşağıdaki kod parçacığını ekleyin. Köşeli ayraçların içeriğini gerçek değerlerle değiştirerek emin olun. Bu adım, yeni oluşturduğunuz dosyayı tüketir arm64x.cmake .

     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()
    
  2. Arm64X özellikli Arm64 ön ayarını (arm64-debug-x) kullanarak CMake projenizi oluşturun.

  3. Arm64X özellikli Arm64EC ön ayarını (arm64ec-debug-x) kullanarak CMake projenizi oluşturun. Bu derlemenin çıkış dizinindeki son DLL'ler Arm64X ikili dosyalarıdır.

Arm64X saf iletici DLL'si oluşturma

Arm64X saf iletici DLL, türlerine bağlı olarak API'leri ayrı DLL'lere ileten küçük bir Arm64X DLL'dir:

  • Arm64 API'leri bir Arm64 DLL'sine iletilir.

  • x64 API'leri bir x64 veya Arm64EC DLL'sine iletilir.

Arm64X saf bir yönlendirici, Arm64EC ve Arm64 kodunun tamamını içeren birleşik bir Arm64X ikili dosyası oluşturmayla ilgili zorluklar olsa bile, Arm64X ikilisini kullanmanın avantajlarını sağlar. Daha fazla bilgi için bkz . Arm64X PE dosyaları.

Arm64 geliştirici komut isteminden aşağıdaki adımları izleyerek Arm64X saf ileticisi oluşturabilirsiniz. Elde edilen Arm64X saf iletici, x64 çağrılarını adresine foo_x64.DLL ve Arm64 çağrılarını adresine yönlendirir foo_arm64.DLL.

  1. Bağlayıcının saf ileticiyi oluşturmak için kullandığı boş OBJ dosyalar oluşturun. Saf iletici kod içermediğinden bu dosyalar boş. Bu dosyaları oluşturmak için boş bir dosya oluşturun. Aşağıdaki örnekte, dosya empty.cpp olarak adlandırılmıştır. cl Boş OBJ dosyalar oluşturmak için kullanın, bir tanesi Arm64 (empty_arm64.obj) ve bir tanesi Arm64EC (empty_x64.obj) için.

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

    "cl : Komut satırı uyarısı D9002 : bilinmeyen '-arm64EC' seçeneğini yoksayıyor" hata iletisini görürseniz, yanlış derleyici kullanıyorsunuz demektir. Bu sorunu çözmek için Arm64 Geliştirici Komut İstemi'ne geçin.

  2. Hem x64 hem de Arm64 için DEF dosyaları oluşturun. Bu dosyalar, DLL'nin tüm API dışarı aktarmalarını listeler ve yükleyiciyi bu API çağrılarını gerçekleştirebilecek DLL'nin adına işaret eder.

    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. Both x64 ve Arm64 için içeri aktarma dosyaları oluşturmak için linkLIB kullanın.

    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. Boş OBJ ve içeri aktarma LIB dosyalarını bayrak /MACHINE:ARM64X kullanarak bağlayarak Arm6X saf iletici DLL'sini oluşturun.

    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
    

Elde edilen foo.dll bir Arm64 veya x64/Arm64EC işlemine yüklenebilir. Bir Arm64 işlemi foo.dll yüklediğinde, işletim sistemi hemen foo_arm64.dll'i onun yerine yükler ve tüm API çağrıları foo_arm64.dll tarafından işlenir.