Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Python

Porting Your Applications to Arm64 Using Arm64EC — Series (Part 2)

0.00/5 (No votes)
13 Sep 2023CPOL5 min read 4.9K  

In the first part of this series, you learned how to use your existing or new C/C++ dynamic link libraries (DLLs) to provide efficient computations and build UI-based apps rapidly using Python and Qt. In this article, you will learn how to port each DLL to Arm64 using Arm64EC.

As the official Microsoft documentation explains, Arm64EC helps you accelerate your existing x64 apps or dependencies on Windows 11 on Arm. To use Arm64EC, you only need to configure the build target appropriately. As a result, your entire application can mix x64 dependencies with Arm64.

Microsoft also published an article about porting C/C++ apps to Arm64 with Arm64EC. However, that article used a simple application, which added two numbers. This article demonstrates a more advanced example: You create your main app using Qt bindings for Python (PySide 6), with two underlying C/C++ DLLs. This architecture mimics the typical scenario of using Python and Qt for rapid UI prototyping and DLLs for computation-intense work. The reason for using a Python application is to demonstrate an alternative way of building UI for C/C++-based DLL dependencies. However, you could still use Qt-based C/C++ UI, as shown previously.

Porting Arm64 DLLs

To follow this tutorial, ensure you have the following prerequisites (which you installed in the first tutorial of this series):

  • Visual Studio 2022
  • Arm64 build tools. These are installed through your Visual Studio Installer under Individual Components > MSVC v143 > VS 2022 C++ ARM64 build tools. Note that this is the default selected component.
  • Python installed on your machine. This demonstration uses Python version 3.11.3. As in one of our previous articles, you will need to install Python for x64 and Arm64.

For a more detailed view of the tutorial, see the complete project code.

Porting to Arm64 with Arm64EC

There are two ways of porting DLLs to Arm64 with Arm64EC. Which one you use depends on whether you use MSBuild or CMake projects. In the previous article, you used CMake, so you can use CMake here, too.

To port the DLL, modify the CMakePresets.json​ file by adding a final statement block so that the file looks like the following code snippet:

JSON
{
  "version": 3,
  "configurePresets": [
    {
      "name": "windows-base",
      "hidden": true,
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/out/build/${presetName}",
      "installDir": "${sourceDir}/out/install/${presetName}",
      "cacheVariables": {
        "CMAKE_C_COMPILER": "cl.exe",
        "CMAKE_CXX_COMPILER": "cl.exe"
      },
      "condition": {
        "type": "equals",
        "lhs": "${hostSystemName}",
        "rhs": "Windows"
      }
    },
    {
      "name": "x64-release",
      "displayName": "x64 Release",
      "inherits": "windows-base",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Release"
      }
    },
    {
      "name": "arm64EC-release",
      "displayName": "Arm64EC Release",
      "inherits": "x64-release",
      "architecture": {
        "value": "arm64ec",
        "strategy": "external"
      },
      "environment": {
        "CXXFLAGS": "/arm64EC",
        "CFLAGS": "/arm64EC"
      }
    }
  ]
}

Next, save the CMakePresets.json file. Visual Studio 2022 will automatically recognize this new build configuration and display it in the build configuration drop-down:

Image 1

From this drop-down menu, select Arm64EC Release and build the application.

Since you are using the single CMake file for both DLLs, you will find both compiled DLLs under the out/build/arm64EC-release folder. Each DLL is located in the corresponding folder: Filters or Vectors. Copy those DLLs and create a new folder called Main-app/Dependencies/Arm64EC-release in the Main-app, as follows:

  • ARM64EC.Porting/out/build/arm64EC-release/Vectors/Vectors.dll
    to
    ARM64EC.Porting/Main-app/Dependencies/Arm64EC-release/Vectors.dll
  • ARM64EC.Porting/out/build/arm64EC-release/Filters/Filters.dll
    to
    ARM64EC.Porting/Main-app/Dependencies/Arm64EC-release/Filters.dll

To use those DLLs in the main application, update the following two variables in the Main-app/main.py file:

Python
vectorsLibName = os.path.join(rootPath, "Dependencies\\Arm64EC-release\\Vectors.dll")
filtersLibName = os.path.join(rootPath, "Dependencies\\Arm64EC-release\\Filters.dll")

Then, you can launch the Python app. Go to the Main-app folder and type python main.py. If you are using a virtual environment, this requires you to launch it and install all dependencies from the requirements.txt file.

The app will launch, and you can see it working as before:

Image 2

Note, though, that the computation time is always 0.00. This is because you loaded the DLLs using the x64 process.

To load them as Arm64, you would need to use Python for Arm64. However, at the time of writing, PySide 6 was not available for Arm64 via pip. You will be able to fully test the porting once it becomes available.

Here are the detailed steps for launching the Python app under the Arm64 virtual environment on Windows:

  1. Download Python for Arm64.
  2. Configure a virtual environment by running the py -3.11-arm64 -m venv venv-arm64 command.
  3. Activate a virtual environment by running venv-arm64\Scripts\activate.bat.
  4. Install dependencies by running py -3.11-arm64 -m pip install -r requirements.txt.
  5. Run the app using cd Main-app.
  6. Finally, enter -3.11-arm64 main.py.

An Alternative Approach

While this series used CMake for building and DLL porting, you can achieve a similar result using MSBuild. For the MSBuild projects, use the Console App project template:

Image 3

Then, configure the project template as follows:

  • Project name: Arm64EC.Porting.Vectors
  • Location: Select any location you want.
  • Solution name: Arm64EC.Porting.MSBuild

Remember to uncheck Place solution and project in the same directory.

After creating the project, you will have a single source file called Arm64EC.Porting.Vectors.cpp. Rename this file as Vectors.cpp.

Replace the default content of Vectors.cpp with the content of the file from the previous article.

Then, open Solution Explorer, right-click Headers, and choose Add/New Item….

In the window that appears, type "Vectors.h" and click Add.

Replace the default contents of the Vectors.h file with the following:

C++
#pragma once

#include <iostream>
#include <chrono>

using namespace std;

extern "C" __declspec(dllexport) double performCalculations();

By default, the Console App template generates an executable, but you need to change it to a DLL. To do so, go to Solution Explorer and right-click the Arm64EC.Porting.Vectors project. Then, select Properties. In the window that opens, choose Dynamic Library (.dll) from the Configuration Type drop-down list:

Image 4

Click OK to close the Property Pages window.

Now, build the DLL by clicking Build/Build solution. The DLL should be located in the \<platform (x64 or arm64)>\<configuration (Debug or Release)> folder, which may appear as Arm64EC.Porting.MSBuild\x64\Debug.

To port this library to Arm64EC, you need to configure the target platform. To do so, click Configuration Manager… from the drop-down menu:

Image 5

In the Configuration Manager, create the new solution platform for Arm64EC:

Image 6

Then, right-click on the Arm64EC.Porting.Vectors file and open the Properties window. Change the configuration type to DLL, as you did earlier for the x64 configuration. Once you have configured the solution platform, select it from the build target drop-down menu and build the solution.

The compiled DLL will be available under the ARM64EC subfolder. You can then use it in the Main-app in the same way as DLLs built using CMake.

To use MSBuild for the second DLL, you proceed the same way.

Conclusion

This article demonstrated how to port C/C++ DLLs to Arm64 using Arm64EC. It showed you how to use CMake and MSBuild projects. You also learned how to use DLLs in the Python app with ctypes. This information can help you rapidly build UIs and keep computation-intensive work in a separate DLL. You can then build those DLLs for Arm64 and mix them with your existing x64 dependencies.

Try Arm64EC on Windows 11 and use the Windows Dev Kit 2023 as a cost-effective way to test your app on Arm64 devices running Windows.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)