2017-05-15

Compiling desktop ARM 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, 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 a Win32 ARM application.

Caveat #1 - Getting the ARM compiler and libraries installed


In Visual Studio 2017 setup, Microsoft seem to have done their darnedest to prevent people from installing the MSVC ARM compiler. 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:


Oh, and while you're there, it's probably a good idea to get the "Clang/C2 (experimental)" component installed, as it also provides ARM compilation (but no libraries!), though this component does get listed in the "Workloads" view.

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


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

10>C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\VC\VCTargets\Platforms\ARM\PlatformToolsets\v141\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 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 win32 binaries, which you need to overcome by doing the following:

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

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

  3. Insert a new <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport> property, so that you have:

      <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
        <ConfigurationType>Application</ConfigurationType>
        <CharacterSet>Unicode</CharacterSet>
        <WholeProgramOptimization>true</WholeProgramOptimization>
        <PlatformToolset>v141</PlatformToolset>
        <WindowsSDKDesktopARMSupport>true</WindowsSDKDesktopARMSupport>
      </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:


If you do all the above, then you should be able to compile a native win32 desktop app for ARM.

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...

2 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