- Cross-OS with native AOT is not supported; x64↔ARM64 is supported with the appropriate toolchain.
- Visual Studio integrates MSBuild, CMake, Xamarin, and VSTU for cross-platform workflows.
- Build servers can be created without VS by copying SDKs, Registry and GAC.
- Debug in Windows y Linux from the IDE with CMakeSettings and connection SSH.

Mastering cross-compiling in Visual Studio from Windows is not trivial: there are nuances between architectures, OS, toolchains and linkers that define what can and can't be done. In this practical and detailed guide, we've gathered all the relevant knowledge for configuring and cross-compiling with Visual Studio, MSBuild, and CMake, including scenarios with native AOT, mobile development, multi-machine environments, and remote debugging on Linux.
The idea is that, with a single reading, you are clear about what each technology supports, what Visual Studio components you need to install, how to prepare dependencies on Linux, what paths and registry keys are needed on build servers without VS, and how to move the same code between Windows and Linux using CMake and Visual Studio integration.
What is cross-compilation and the real limits of native AOT?
Cross compilation consists of generating binaries for a platform other than the one the compiler runs on, either by change of operating system or architectureFor example, producing Windows executables from Linux or targeting ARM64 from an x64 host.
In the context of .NET with native AOT, the process uses platform linkers and libraries to combine compiled managed code with native dependencies (static or dynamic). This introduces an important limitation: the availability of cross-linkers and target libraries determines which OS/architecture pairs are viable.
As of today, there is no standardized and supported way to get the native macOS SDK on Windows/Linux, the Windows SDK on Linux/macOS, or a Linux SDK on Windows/macOS. Therefore, Native AOT does not support cross-compilation between operating systemsIf you need to compile between different OSes, the practical way is to use emulation, a virtual machine, or WSL on Windows.
Where there is room for improvement is in cross-compiling between architectures within the same OS. As long as you install the right toolchain, it's possible. cross-compile between x64 and ARM64 on Windows, macOS, or Linux. This is most commonly used when you want to produce ARM64 binaries from an x64 desktop host.

System requirements and tools: Windows, macOS, and Linux
To be successful with cross-compiling, you need to install the appropriate native toolchains and its utilities (linkers, objcopy/strip, C runtime, zlib, etc.). Availability varies by operating system and distro.
Windows (x64 ↔ ARM64). Cross-compiling from Windows x64 to Windows ARM64 (and vice versa) works by installing the correct C++ Build Tools from Visual Studio 2022. If you are targeting ARM64, make sure to include the component «VS 2022 C++ ARM64/ARM64EC build tools (Latest)». If you are targeting x64, look for the component «Visual Studio 2022 C++ x64/x86 build tools (Latest)».
MacOS. Xcode comes with the x64 and ARM64 toolchains by default, so you can target both architectures with the standard installation. In this environment, Visual Studio for Mac and CMake also rely on these Apple toolchains.
Linux. Each distribution handles native dependencies differently. At a minimum, you'll need: a linker capable of outputting to the target (e.g., clang), utilities objcopy/strip compatible with the target if you enable StripSymbols, and the objects of the C runtime and zlib for the target architecture.
On Ubuntu 22.04 amd64, the following commands may be sufficient for linux-arm64 (not documented or guaranteed by Ubuntu, but usually works):
sudo dpkg --add-architecture arm64
sudo bash -c 'cat > /etc/apt/sources.list.d/arm64.list <<EOF
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ jammy main restricted
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ jammy-updates main restricted
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ jammy-backports main restricted universe multiverse
EOF'
sudo sed -i -e 's/deb http/deb [arch=amd64] http/g' /etc/apt/sources.list
sudo sed -i -e 's/deb mirror/deb [arch=amd64] mirror/g' /etc/apt/sources.list
sudo apt update
sudo apt install -y clang llvm binutils-aarch64-linux-gnu gcc-aarch64-linux-gnu zlib1g-dev:arm64

Cross-platform development with Visual Studio: mobile, games, and UWP
Visual Studio is not limited to the desktop: it allows you to create apps all with Android, iOS and Windows with C#, .NET, C++, or even HTML/JS. You can share code, strings, and resources between projects, and in some cases even interfaces with frameworks like Xamarin.Forms.
If you are targeting Android/iOS/Windows with .NET, install the option «Development for mobile devices with .NET» (Xamarin). You'll get dedicated project templates, full access to native APIs, and the productivity of Visual Studio (designers, IntelliSense, emulators, and running on tethered devices). Plus, Xamarin.Forms allows you to define a common UI that renders natively on each platform.
For immersive gaming and graphics, Visual Studio offers Tools for Unity (VSTU), integrating C# script editing and debugging. The current release adds Unity 2019.4 support, ShaderLab coloring, improved synchronization, more comprehensive debugging, and improved code generation for MonoBehavior.
If you want to target your Windows 10 device portfolio with a single app and an adaptive interface model, you can create an app UWPStarting with UWP templates, Visual Studio makes it easy to design visually, preview various form factors, and select emulators and simulators from the toolbar.

Build environments without Visual Studio on the server: multi-machine
In companies, it is common to need build servers without full Visual Studio licenses. It is possible to create an internal build environment by installing Visual Studio on a host computer and copying files and settings to the build team. However, it doesn't give you the right to redistribute software externally or offer build environments to third parties.
Also note that the documentation tested these steps on systems such as Windows 8 (x86/x64), Windows 7 Ultimate and Windows Server 2008 R2 Standard. After completing the process, you will be able to compile C++ desktop apps with the Windows 8 SDK or VB/C# apps for the .NET Framework 4.5, but there are exceptions: it does not work for UWP nor for .NET Framework ≤ 4.0 without additional tools.
Previous requirements. Have Visual Studio installed with the workload «.NET Desktop Development» on the host. On the build machine, install at least . NET Framework 4.5 (validates the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\Version).
Copy Windows SDK and Tools. Starting from the default installation path (%ProgramFiles%), it recursively copies to the build machine, among others, the following folders: Windows Kits 8.0 (bin, Catalogs, DesignTime, include, Lib, Redist, References), Microsoft SDKs Windows v8.0A (NETFX 4.0 Tools), Common Files\Merge Modules, and key directories of VC and MSBuild. Respect the license terms of each installed kit, especially if you have WDk/ADK.
Additionally, it moves specific files such as msobj110.dll, mspdb110.dll, mspdbcore.dll, mspdbsrv.exe, msvcdis110.dll, makehm.exe, VCVarsQueryRegistry.bat y vsvars32.bat. To run binaries on the build server (e.g. tests), also copy the Visual C++ runtimes (msvcp110.dll, msvcr110.dll, atl110.dll, vcamp110.dll, etc.) to System32/SysWOW64 depending on architecture, and debug variants from Debug_NonRedist (msvcp110d.dll, msvcr110d.dll, etc.).
Required Registry Keys. You must create entries to configure MSBuild values. The root depends on the architecture: on x86, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft; on x64, HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft (hereafter %RegistryRoot%). Create the following string (REG_SZ) entries, reflecting the values available on the host:
%RegistryRoot%\.NETFramework\v4.0.30319\AssemblyFoldersEx\VCMSBuild Public Assemblies@(Default)
%RegistryRoot%\Microsoft SDKs\Windows\v8.0@InstallationFolder
%RegistryRoot%\Microsoft SDKs\Windows\v8.0A@InstallationFolder
%RegistryRoot%\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools@InstallationFolder
%RegistryRoot%\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools-x86@InstallationFolder
%RegistryRoot%\VisualStudio\11.0@Source Directories
%RegistryRoot%\VisualStudio\11.0\Setup\VC@ProductDir
%RegistryRoot%\VisualStudio\SxS\VC7@FrameworkDir32
%RegistryRoot%\VisualStudio\SxS\VC7@FrameworkDir64
%RegistryRoot%\VisualStudio\SxS\VC7@FrameworkVer32
%RegistryRoot%\VisualStudio\SxS\VC7@FrameworkVer64
%RegistryRoot%\VisualStudio\SxS\VC7@11.0
%RegistryRoot%\VisualStudio\SxS\VS7@11.0
%RegistryRoot%\Windows Kits\Installed Roots@KitsRoot
%RegistryRoot%\MSBuild\ToolsVersions\4.0\11.0@VCTargetsPath
%RegistryRoot%\MSBuild\ToolsVersions\4.0\11.0@VCTargetsPath10
%RegistryRoot%\MSBuild\ToolsVersions\4.0\11.0@VCTargetsPath11
On x64 computers it also adds: %RegistryRoot%\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools-x64@InstallationFolderIf you're using native 64-bit MSBuild (or TFS Build Service on x64), add these entries to your native 64-bit registry: HKLM\SOFTWARE\Microsoft\VisualStudio\11.0\Setup\VS@ProductDir and the three values of HKLM\SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0\11.0 for VCTargetsPath, VCTargetsPath10 and VCTargetsPath11.
Environment VariablesThe direct way is to execute vcvarsall.bat from …\VC\vcvarsall.bat. You can specify the target toolchain as an argument; if you omit it, x86 is used. These are the key arguments:
| Argument | Compiler type | Host | Destination |
|---|---|---|---|
| x86 | Native 32-bit | x86, x64 | x86 |
| x86_amd64 | Crossover to x64 | x86, x64 | x64 |
| amd64 | Native 64-bit | x64 | x64 |
If you prefer, you can adjust PATH manually adding the paths to Common7\IDE and the 32/64-bit MSBuild directories as appropriate, although using vcvarsall.bat It prevents you from forgetting.
GAC for MSBuild assemblies. There are additional assemblies that MSBuild requires in the GAC. Copy from the host to any folder on the build server and register with gacutil -i (you will find it in Microsoft SDKs\Windows\v8.0A\bin\NETFX 4.0 Tools):
%ProgramFiles%\MSBuild\Microsoft.Cpp\v4.0\v110\Microsoft.Build.CPPTasks.Common.v110.dll
%ProgramFiles%\Microsoft Visual Studio\<versión>\<edición>\Common7\IDE\CommonExtensions\Microsoft\VC\Project\Microsoft.VisualStudio.Project.VisualC.VCProjectEngine.dll
%ProgramFiles%\Microsoft Visual Studio\<versión>\<edición>\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.VCProjectEngine.dll
Compilation. On the server command line, you can invoke msbuild directly or integrate the process into Azure Pipelines, which automatically selects the MSBuild executable that matches the agent's architecture. A basic example would be: msbuild solution.sln.
If you need a portable, versioned source control environment, you can create a "Depot» copying the directories to %Depot% and adjusting MSBuild files (Microsoft.CPP.Targets, etc.) to reference AssemblyFile=»$(VCTargetsPath11)Microsoft.Build.CppTasks.Common.v110.dll» instead of the GAC, in addition to using a Partner.AutoImports.props with properties like VCTargetsPath, MSBuildExtensionsPath, VCInstallDir y WindowsSdkDir, imported at the start of each project.

MSBuild, CMake, and Pipelines: Supported Build Methods
Visual Studio lets you compile from the IDE, but also with MSBuild in CLI, CMake y Azure Pipelines. Each method offers advantages:
- IDE: Instant builds, integrated debugging, multi-threaded compilation, and key customization.
- CMake: Unifies the C++ build system between Linux and Windows without .vcxproj projects, ideal if your base is already CMake.
- MSBuild (CLI): compiles without installing the full Visual Studio, allows parallel builds and extensive customization via properties and targets.
- Azure Pipelines: Integrate CI/CD, run automated tests, and scale in the cloud with highly customizable tasks.
Within the IDE you can adjust settings by platform (Windows or Linux) and by mode (Debug/Release), with options such as output directories, post-build events, project dependencies, logs and suppression of warnings. This flexibility is essential when managing multiple architectures or toolchains in the same solution.
CMake Flow: Building and Debugging on Windows and Linux from Visual Studio
For C++ builds that use CMake, Visual Studio makes it easy to open the repo folder (with CMakeLists.txt), generate the cache automatically and configure IntelliSense by target. From there you can create explicit configurations (e.g. x64-Debug) that are persisted in CMakeSettings.json.
A typical flow starts with cloning the project, for example: git clone https://github.com/bulletphysics/bullet3.gitFrom Visual Studio, open the root CMakeLists and, after generating the cache, you'll see the "CMake Targets View" with libraries and executables.
To debug on Windows, select the target executable (for example, AppBasicExampleGui.exe in the Bullet SDK), set a breakpoint in a key function (e.g., mouseButtonCallback) and start it with F5. You can inspect variables, objects, threads, and memory with the built-in debugger.
For Linux, add a setting «Linux-Debug» In CMakeSettings, select the "Unix Makefiles" generator if applicable and connect to the remote machine via SSH (Visual Studio manages ssh/rsync, gdb, make and CMake on the Linux host). The typical tools are required (build-essential, gdb, rsync, make, zip) and a recent version of CMake (at least 3.8; Microsoft provides universal binaries that you can install with --prefix=/usr).
If the app is a desktop app on Linux, it may be necessary to export DISPLAY. Get the value with echo $DISPLAY and adds in launch.vs.json from the configuration the corresponding prefix in pipeArgs: For example, "export DISPLAY=:1;${debuggerCommand}" to make sure that gdb start with the correct graphical context.
Once the binary is running on the remote machine, Visual Studio brings it to the foreground when the breakpoint is reached and displays the call stack (for example, callbacks like CommonRigidBodyBase::mouseMoveCallback, X11OpenGLWindow::pumpMessage, etc.). Additionally, you will see a console with the remote output and you can send standard input if necessary.
This approach allows you to iterate in a single IDE on both Windows and Linux, while maintaining Same sources, different toolchains and a consistent debugging experience.
Additional notes and considerations
Please note the official limits: Native AOT is not supported. cross-OS without virtualization/emulation, but architecture switching (x64 ↔ ARM64) within the same OS with the correct toolchain. On Linux, be aware that the utilities objcopy/strip that you use support the objective if you have activated Strip Symbols.
In server scenarios, check the license terms of each component you copy (Windows Kits, WDK, ADK, etc.). Microsoft cautions that these guides are provided "as is" and that the steps may not be tested in all possible configurations; it is recommended validate the pipeline in your environment before standardizing it.
Finally, when you configure multiple platforms in the same solution, name and separate your configurations and outputs (for example, different folders per architecture/OS), automate with MSBuild and, if you can, integrate everything into one CI/CD pipeline with Azure Pipelines to gain repeatability and traceability.
With the right toolchains, careful MSBuild/CMake configuration, and IDE support, it is feasible to generate binaries for different architectures from Windows, orchestrate builds on servers without VS, and move the same code between Windows and Linux with a consistent debugging experience. productive for mixed teams.
Passionate writer about the world of bytes and technology in general. I love sharing my knowledge through writing, and that's what I'll do on this blog, show you all the most interesting things about gadgets, software, hardware, tech trends, and more. My goal is to help you navigate the digital world in a simple and entertaining way.