Add Arm support to your Windows app

Arm-based devices are becoming increasingly popular due to their power-frugal nature, longer battery life, and impressive processing power, in addition to the Windows on Arm support for Neural Processing Units (NPUs) tuned for the increasingly popular AI and Machine Learning workloads.

This guide will cover the steps for adding support to your Windows app(s) for devices powered by Arm64 processors. Guidance will also cover ways to address any potential issues or blockers (such as 3rd party dependencies or plug-ins) that may interfere with creating an Arm64-based version of your app.

Emulation on Arm-based devices for x86 or x64 Windows apps

Arm versions of Windows 10 include emulation technology that enables existing unmodified x86 apps to run on Arm devices. Windows 11 extends that emulation to run unmodified x64 Windows apps on Arm-powered devices.

While the ability to emulate x64 and x86 on Arm devices is a great step forward, this guide will help you to add Arm-native support, so that your app can take advantage of native performance gains and the unique qualities of Arm64-powered devices, including:

  • Optimizing the power-consumption of your app to extend device battery life.
  • Optimizing performance for CPU, GPU, and NPUs to accelerate workflows, particularly when working with AI.

Additionally, Kernel drivers are required to be built as native Arm64. There is no emulation present in the kernel. This primarily impacts virtualization scenarios. For apps that utilize device drivers requiring direct access to the internals of the OS or hardware running in kernel mode, rather than user mode, and that have not yet been updated to support Arm64 processors, see Building Arm64 Drivers with the WDK.

Note

Progressive Web Apps (PWAs) will already execute with native Arm64 performance.

Prerequisites

If you are updating your app using an Arm-based device (native compiling - generating the code for the same platform on which you're running), you can use:

  • Visual Studio 2022 v17.4 or later. This is the first GA release of Visual Studio that natively supports building and debugging Arm64 apps on Arm-based processors. Both Visual Studio 2022 17.4 and Microsoft Visual C++ (MSVC) native Arm64 versions provide significantly better performance compared with previous emulated versions.

  • (Optional) LLVM (Clang) v12+ or later. LLVM 12 adds official binary release hosted on Windows on Arm64, including a Clang compiler, LLD Linker, and compiler-rt runtime libraries.

If you are updating your Windows app to support Arm using an x64 or x86 Intel-based device (cross compiling), you can use:

There are several factors to consider when choosing between cross compilation or native compilation such as available hardware and simplicity of test execution.

Note

GCC, the GNU Compiler Collection support is targeted for the near future.

Steps to add Arm64 native support

To update your app to run natively on Arm64:

  1. Add an Arm64 configuration to your project in Visual Studio
  2. Test and debug the newly built Arm64 app
  3. Build and test your app on Arm devices

Once you've confirmed that your app has successfully been optimized for Arm devices:

  1. Update your installer and publish your updated app
  2. Plan for ongoing updates

Step 1 - Add an Arm64 configuration to your project in Visual Studio

To add a new ARM64 solution platform with debug and release targets to your existing x64 or x86 app project:

  1. Open your solution (project code) in Visual Studio (see prerequisites for the supported versions).
  2. In the "Solution Platforms" drop-down menu on the Standard toolbar (or in the "Build" menu), select Configuration Manager...
  3. Open the "Active solution platform" drop-down menu and select <New...>.
  4. In the "Type or select the new platform" drop-down menu, select ARM64 and ensure that the "Copy settings from" value is set to x64 with the "Create new project platforms" checkbox enabled, then select OK.

Congratulations! You have started adding Arm support to your app. Next, check to see whether your Arm64 Solution builds successfully.

If your Solution does not build successfully, you will need to resolve the issues that are causing the build to fail. The most likely reason is that a dependency is not available for ARM64, which is covered in Troubleshooting below.

(Optional): If you want to verify first-hand that your app binary is now built for Arm64, you can open your project directory in PowerShell (right-click your app project in Visual Studio Solution Explorer and select Open in Terminal). Change directories so that your project's new bin\ARM64\Debug or Release directory is selected. Enter the command: dumpbin /headers .\<appname>.exe (replacing <appname> with the name of your app). Scroll up in your terminal's output results to find the FILE HEADER VALUES section and confirm the first line is AA64 machine (ARM64).

Step 2 - Test and debug the newly built Arm64 app

To check whether your Arm64 Solution builds successfully after adding the Arm64 solution platform to your project in Visual Studio:

  1. Close the "Active solution platform" window.
  2. Change the build setting from Debug to Release.
  3. In the "Build" drop-down menu, select Rebuild Solution and wait for the project to rebuild.
  4. You will receive a "Rebuild All succeeded" output. If not, see the Troubleshooting section below.

Once the binaries are built for your app to support Arm64, you’ll want to test them. That will require having a device or a virtual machine running Windows on Arm.

If you are doing development on a Windows on Arm device, then you have an easy setup with Visual Studio local debugging. If cross-compiling (using a device that is not running on an Arm-processor), then you will want to use remote debugging on a Windows on Arm device or a virtual machine to enable your development experience in Visual Studio while running the Arm64 app on another device.

Windows on Arm hardware or virtual machines available for testing

If you are looking for hardware to use for Continuous Integration (CI) and testing, these are a few of the Windows devices with an Arm64-based processor:

For help setting up a virtual machine (VM) running Windows on Arm to support CI and testing, see Quickstart: Create a Windows on Arm virtual machine in the Azure portal.

Step 3 - Build and test your app on Arm devices

Adding a test automation pass is an important considering for your Continuous Integrations and Continuous Delivery (CI/CD) strategy. For Arm64 solutions running on Windows, it’s important to run your test suite on Arm64 architecture -- this could be actual Windows on Arm hardware, using one of the Arm devices listed above, or a Virtual Machine, from the VMs listed above.

Compiling the app is more convenient when done on the same machine as the tests, but in many cases is not required. Instead, you can consider extending the existing build infrastructure to produce a cross-compiled output for Arm64.

Step 4 - Update your installer and publish your updated app

If you publish to the Microsoft Store, once you have built an Arm64 version of your app by following the steps above, you can update your existing app package in the Microsoft Store by visiting your Partner Center dashboard and adding the newly built ARM64 binaries to the submission.

If your app is not already published in the Microsoft Store, you can follow the instructions to create an app submission based on whether you want to submit an MSI or EXE, MSIX package, PWA, or App add-on.

If you build your own installer, you should ensure it is able to install your new Arm64 version successfully. Most installer frameworks, such as WiX, Squirrel, InnoSetup, InstallAware, and others support Windows on Arm without issue.

If you offer your app's installer from a webpage, you can use User-Agent Client Hints to detect when your customer is visiting from a Windows on Arm device and offer them the updated Arm-native version of your app. Unlike the user-agent string, User-Agent Client Hints allows you to differentiate customers on Arm from customers on x86 devices.

Step 5 - Plan for ongoing updates

Now that you have an Arm64 version of your app published, you’ll want to ensure that it stays updated the same way that other versions of your app do. It’s best to keep versions and features aligned across architectures to avoid customer confusion in the future.

Troubleshooting

Common issues that may interfere with or block you from adding an Arm64 version of your existing x64 or x86 Windows app include:

A dependency not compiled for ARM64 is blocking you from a successful build

If you can’t build due to a dependency, whether internal, from a 3rd party, or from an open-source library, you will need to either find a way to update that dependency to support ARM64 architecture or remove it.

  • For internal dependencies, we recommend rebuilding the dependency for ARM64 support.

  • For 3rd party dependencies, we recommend filing a request for the maintainer to rebuild with ARM64 support.

  • For open source dependencies, consider checking vcpkg to see if a newer version of the dependency that includes ARM64 support exists that you can update to. If no update exists, consider contributing the addition of ARM64 support to the package yourself. Many open source maintainers would be thankful for the contribution.

  • The Linaro organization also works with businesses and open source communities to develop software on Arm-based technology. You can file a request with the Linaro Service Desk to help update package support for any missing dependencies related to Windows on Arm.

  • Consider using Arm64EC. Arm64EC versions of dependencies can be used to rebuild an application while still utilizing x64 versions of dependencies. Any x64 code, including code from dependencies, in an Arm64EC process will run under emulation in your app. (Arm64 versions of dependencies won't be usable in this case.)

  • The last choice would be to remove and/or replace the dependency on your app project.

Code is written for a specific architecture other than Arm64

Your app relies on a kernel driver

Kernel drivers are required to be built as native Arm64. There is no emulation present in the kernel. This primarily impacts virtualization scenarios. For apps that utilize device drivers requiring direct access to the internals of the OS or hardware running in kernel mode, rather than user mode, and that have not yet been updated to support Arm64 processors, see Building Arm64 Drivers with the WDK.

Additionally, drivers on Windows are required to be built as Arm64 and can't be emulated. For apps that rely on software drivers that have not yet been updated to support Arm64 processors, see Building Arm64 Drivers with the WDK.

Toolchain for Windows on Arm

In addition to support for Visual Studio and LLVM (CLANG) as shared in the Prerequisites section of this guide, the following tools and frameworks are also supported for Arm64:

As well as 3rd-party frameworks, including:

Need assistance? Leverage our App Assure service

The App Assure Arm Advisory Service is available to help developers build Arm-optimized apps. This service is in addition to our existing promise: your apps will run on Windows on Arm, and if you encounter any issues, Microsoft will help you remediate them. Learn more.

Sign up for Windows Arm Advisory Services.