2017-05-15

Compiling desktop ARM or ARM64 applications with Visual Studio 2017

Unlike what I was led to think, and despite the relative failure of Windows RT (which was kind of a given, considering Microsoft's utterly idiotic choice for its branding), it doesn't look like Microsoft has abandoned the idea of Windows on ARM/ARM64, including allowing developers to produce native desktop Windows applications for that platform.

However, there are a couple caveats to work through, before you can get Visual Studio 2017 to churn out Windows native ARM/ARM64 applications.

Caveat #1 - Getting the ARM/ARM64 compiler and libraries installed


In Visual Studio 2017 setup, Microsoft seem to have done their darnedest to prevent people from installing the MSVC ARM compilers. This is because, they are not allowing the ARM development components to be listed in the default "Workloads" view, and if you want them, you will need to go fetch them in the "Individual components" view as per the screenshot below:


It is important to note that you will need Visual Studio 2017 Update 4 (version 15.4) or later for the ARM64 compiler to be available for installation. ARM64 was silently added by Microsoft late in the Visual Studio 2017 update cycle, so if it's ARM64 you are after, you will need an updated version of the Visual Studio installer.

Caveat #2 - Error MSB8022: Compiling Desktop applications for the ARM/ARM64 platform is not supported.


Okay, now that you have the ARM/ARM64 compiler set, you created your nice project, set the target to ARM/ARM64 (while cursing Microsoft for even making that step painful), hit "Build Solution", and BAM!, you are only getting a string of:

Toolset.targets(53,5): error MSB8022: Compiling Desktop applications for the ARM platform is not supported.


What gives?

Short answer is, Microsoft doesn't really want YOU to develop native desktop ARM/ARM64 applications. Instead, they have this grand vision where you should only develop boring, limited UWP interpreted crap (yeah, I know the intermediary CIL/bytecode gets compiled to a reusable binary on first run, but it is still interpreted crap - I mean, if it is so great, then why isn't the Visual Studio dev env using it?), that they'll then be able to provide from the App Store. God forbid, in this day and age, you would still want to produce a native win32 executable!

So, they added an extra hurdle to produce native ARM/ARM64 windows binaries, which you need to overcome by doing the following:

  1. Open every single .vcxproj project file that is part of your solution
  2. Locate all the PropertyGroup parts that are relevant for ARM/ARM64. There should usually be two for each, one for Release|ARM[64] and one for Debug|ARM[64] and they should look something like this:

      <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM[64]'" Label="Configuration">
        <ConfigurationType>Application</ConfigurationType>
        <CharacterSet>Unicode</CharacterSet>
        <WholeProgramOptimization>true</WholeProgramOptimization>
        <PlatformToolset>v141</PlatformToolset>
      </PropertyGroup> 

  3. Insert a new <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> or <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support> property, so that you have (ARM64):

      <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
        <ConfigurationType>Application</ConfigurationType>
        <CharacterSet>Unicode</CharacterSet>
        <WholeProgramOptimization>true</WholeProgramOptimization>
        <PlatformToolset>v141</PlatformToolset>
        <WindowsSDKDesktopARM64Support>true</WindowsSDKDesktopARM64Support>
      </PropertyGroup> 

If you do just that, then Visual Studio should now allow you to compile your ARM application without complaining. However, this may not be the end of it because...

Caveat #3 - You may still be missing some libraries unless you use a recent SDK


Depending on the type of desktop application you are creating, you may find that the linker will complain about missing libraries. Some of which are fairly easy to sort out, and are due to the Win32 and x64 default configs being more forgiving about not explicitly specifying libraries such as gdi32, advapi32, comdlg32.lib or shell32 for linking. However, if you are using the default 8.1 SDK in your project, you may also find that some very important libraries are missing for ARM, such as setupapi.lib and other ones. These libraries seem to only have been added by Microsoft recently, so it might be a good idea to switch to using a recent Windows SDK in your project, such as 10.0.15063.0:


Be mindful however that the default SDK that Visual Studio automatically installs if you select the C/C++ components is not full-featured, and will be missing important libraries for ARM/ARM64 compilation, so there again, you must go to the individual components and explicitly select the SDK you want, so that the full version gets installed.

With all the above complete, you should now be able to join the select club of developers who are able to produce actual native Windows applications for ARM/ARM64, and this just in time for the release of Windows 10 on ARM64.

Of course, and as usual, if you want a real-life example of how it's done, you can look at how Rufus does it...

3 comments:

  1. Wow, that's a lot of work. What ARM apps are you developing these days, Pete?

    ReplyDelete
  2. Well, it's not that much work once you've done it a few times... ;)

    As to what I've been developing for ARM, the most recent thing I did was port Rufus to Windows ARM (https://github.com/pbatard/rufus/commit/23d71ae0f113ba55a152eafd144e5288d9a7c0fd, with the binary at https://rufus.akeo.ie/testing/). But of course, without a Windows/ARM platform, that's a bit pointless. Hopefully, by the end of the year, Microsoft will have released its new version of Windows/ARM(64), along with devices that run it, and, more importantly, added ARM64 native compilation support to Visual Studio 2015, since this is something they already have internally.

    Before that, I've been porting the EDK2's EBC Debugger to ARM using Visual Studio (https://github.com/pbatard/EbcDebugger - which I still haven't had a chance to update for VS2017). And then there's always efifs (https://github.com/pbatard/efifs) as well as uefi-simple (https://github.com/pbatard/uefi-simple) that enable UEFI/ARM compilation from Visual Studio...

    ReplyDelete
  3. thanks for the guide. Indeed, it worked as described!

    ReplyDelete