Categories: Compilers, LLVM, Windows

Notes on Cross-Compiling LLVM for Windows ARM64

I recently wanted an LLVM build for Windows ARM64 so I followed the instructions from my post on Building LLVM for Windows ARM64 – Saint’s Log. Unfortunately, I didn’t indicate which commits I built when I wrote that post so this time I started at commit [clang-tools-extra] Update Maintainers for Clang-Doc (#175822) · llvm/llvm-project@feeb934a3c4d825cd673f01416c39ca73ede170f. I briefly considered using the release branch instead but plowed ahead on this commit. My host platform was a Windows 11 x64 machine. I had no trouble building the native x64 LLVM configuration. The build command ended with this line: -- Installing: D:/repos/llvm/llvm-project/build_llvm/install_local/cmake/llvm/LLVMConfigExtensions.cmake, which showed that the install step succeeded. Unfortunately, I had a few hiccups with the Windows AArch64 cross-compilation.

Windows AArch64 Build Installation Error

The build failed and this was the tail of the build output:

  Building Custom Rule D:/repos/llvm/llvm-project/llvm/tools/yaml2obj/CMakeLists.txt
  yaml2obj.cpp
  yaml2obj.vcxproj -> D:\repos\llvm\llvm-project\build_llvm_AArch64\Release\bin\yaml2obj.exe
  Building Custom Rule D:/repos/llvm/llvm-project/llvm/CMakeLists.txt
  1>
  -- Install configuration: "Release"
  CMake Error at lib/Demangle/cmake_install.cmake:39 (file):
    file cannot create directory: C:/Program Files (x86)/LLVM/lib.  Maybe need
    administrative privileges.
  Call Stack (most recent call first):
    cmake_install.cmake:37 (include)


C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: The command "setlocal [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe" -DBUILD_TYPE=Release
-P cmake_install.cmake [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: if %errorlevel% neq 0 goto :cmEnd [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: :cmEnd [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: endlocal & call :cmErrorLevel %errorlevel% & goto :cmDone [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: :cmErrorLevel [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: exit /b %1 [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: :cmDone [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: if %errorlevel% neq 0 goto :VCEnd [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(166,5): error MSB3073: :VCEnd" exited with code 1. [D:\repos\llvm\llvm-project\build_llvm_AArch64\install.vcxproj]

This was strange. Why was the build trying to write into C:/Program Files (x86)/LLVM when this is an AArch64 build, setting aside that the install location was specified on the command line? The head of build_llvm/cmake/modules/cmake_install.cmake at that point is shown below:

# Install script for directory: D:/repos/llvm/llvm-project/llvm/cmake/modules

# Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
  set(CMAKE_INSTALL_PREFIX "D:/repos/llvm/llvm-project/build_llvm/install_local")
endif()
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")

The corresponding head of build_llvm_AArch64/cmake/modules/cmake_install.cmake set CMAKE_INSTALL_PREFIX to the problematic path!

# Install script for directory: D:/repos/llvm/llvm-project/llvm/cmake/modules

# Set the install prefix
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
  set(CMAKE_INSTALL_PREFIX "C:/Program Files (x86)/LLVM")
endif()
string(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}")

build_llvm/cmake/modules/CMakeFiles/LLVMConfig.cmake contained (among other things) these 3 lines:

set(LLVM_TARGET_TRIPLE "x86_64-pc-windows-msvc")

set(LLVM_TARGET_TRIPLE_ENV "")

set(LLVM_HOST_TRIPLE "x86_64-pc-windows-msvc")

build_llvm_AArch64/cmake/modules/CMakeFiles/LLVMConfig.cmake contained these 3:

set(LLVM_TARGET_TRIPLE "")

set(LLVM_TARGET_TRIPLE_ENV "")

set(LLVM_HOST_TRIPLE "x86_64-pc-windows-msvc")

The missing LLVM_TARGET_TRIPLE value prompted me to replace -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-win32-msvc with -DLLVM_TARGET_TRIPLE=aarch64-win32-msvc as follows:

cd llvm-project
mkdir build_llvm_AArch64
cd build_llvm_Aarch64

cmake ../llvm -DLLVM_TARGETS_TO_BUILD:STRING=AArch64 \
 -DCMAKE_BUILD_TYPE:STRING=Release \
 -DCMAKE_INSTALL_PREFIX=install_local \
 -DCMAKE_CROSSCOMPILING=True \
 -DLLVM_TARGET_ARCH=AArch64 \
 -DLLVM_NM=D:/repos/llvm-project/build_llvm/install_local/bin/llvm-nm.exe \
 -DLLVM_TABLEGEN=D:/repos/llvm-project/build_llvm/install_local/bin/llvm-tblgen.exe \
 -DLLVM_TARGET_TRIPLE=aarch64-win32-msvc \
 -A ARM64 \
 -T host=x64

The triple was still empty! That was my clue that something else was wrong and that I needed to take a step back. Turns out I was pasting the bash command into the Developer Command Prompt! Running it as follows was the solution!

cd llvm-project
mkdir build_llvm_AArch64
cd build_llvm_Aarch64

cmake ../llvm -DLLVM_TARGETS_TO_BUILD:STRING=AArch64 -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX=install_local -DCMAKE_CROSSCOMPILING=True -DLLVM_TARGET_ARCH=AArch64 -DLLVM_NM=D:/repos/llvm-project/build_llvm/install_local/bin/llvm-nm.exe -DLLVM_TABLEGEN=D:/repos/llvm-project/build_llvm/install_local/bin/llvm-tblgen.exe -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-win32-msvc -A ARM64 -T host=x64

The expected target triple was now set:

set(LLVM_TARGET_TRIPLE "aarch64-win32-msvc")

set(LLVM_TARGET_TRIPLE_ENV "")

set(LLVM_HOST_TRIPLE "aarch64-pc-windows-msvc")

It was at this point that I noticed a warning I had ignored:

D:\repos\llvm\llvm-project\build_llvm_AArch64> cmake ../llvm -DLLVM_TARGETS_TO_BUILD:STRING=AArch64 \
CMake Warning:
  Ignoring extra path from command line:

   "\"


-- Building for: Visual Studio 17 2022
-- Selecting Windows SDK version 10.0.26100.0 to target Windows 10.0.26200.
-- The C compiler identification is MSVC 19.44.35222.0
-- The CXX compiler identification is MSVC 19.44.35222.0
-- The ASM compiler identification is MSVC

Invalid llvm-tblgen Paths

I could now build with cmake --build . --config Release --target install but the build fails with lots of MSB8066 errors.

...
  2>Building ARMTargetParserDef.inc...
  The system cannot find the path specified.
  4>Building RISCVTargetParserDef.inc...
  The system cannot find the path specified.
  The system cannot find the batch label specified - VCEnd
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(237,5): error MSB8066: Custom build for 'D:\repos\llvm\llvm-project\build3_llvm_AArch64\CMakeFiles\4a6077c6d000b51855bb580d5619439e\ARMTargetParserDef.inc.rule' exited
with code 1. [D:\repos\llvm\llvm-project\build3_llvm_AArch64\include\llvm\TargetParser\target_parser_gen.vcxproj]
  The system cannot find the batch label specified - VCEnd
  3>Building PPCGenTargetFeatures.inc...
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(237,5): error MSB8066: Custom build for 'D:\repos\llvm\llvm-project\build3_llvm_AArch64\CMakeFiles\4a6077c6d000b51855bb580d5619439e\RISCVTargetParserDef.inc.rule' exite
d with code 1. [D:\repos\llvm\llvm-project\build3_llvm_AArch64\include\llvm\TargetParser\target_parser_gen.vcxproj]
  The system cannot find the path specified.
  The system cannot find the batch label specified - VCEnd
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(237,5): error MSB8066: Custom build for 'D:\repos\llvm\llvm-project\build3_llvm_AArch64\CMakeFiles\4a6077c6d000b51855bb580d5619439e\PPCGenTargetFeatures.inc.rule' exite
d with code 1. [D:\repos\llvm\llvm-project\build3_llvm_AArch64\include\llvm\TargetParser\target_parser_gen.vcxproj]
...

At this point, I switched to the latest release tag: llvm/llvm-project at llvmorg-21.1.8, which was at commit [Github] Remove use of setup-windows and install-ninja in llvm tests · llvm/llvm-project@2078da43e25a4623cab2d0d60decddf709aaea28

git remote add upstream https://github.com/llvm/llvm-project
git fetch upstream release/21.x
git checkout release/21.x

Building that release still failed with the same error but at least I was now using a tag that’s easy to refer to instead of a random commit. I tried building the release/13.x branch since LLVM was at major version 13 when I wrote the post on how to do this build.

git checkout release/13.x

After getting the same error, I opened the project in Visual Studio 2022 and built it there to see if I could get a hint about which files are missing:

Seeing where the error was happening (above) made it easier to diagnose. This explanation from Copilot in VS Code was invaluable because it got me to verify that the table-gen executable path was valid (it wasn’t)!

I updated the build instructions to check the two EXE paths before calling cmake as follows:

mkdir build_llvm_AArch64
cd build_llvm_Aarch64

set LLVM_NM=D:\repos\llvm\llvm-project\build_llvm\install_local\bin\llvm-nm.exe
set LLVM_TABLEGEN=D:\repos\llvm\llvm-project\build_llvm\install_local\bin\llvm-tblgen.exe

dir %LLVM_NM%
dir %LLVM_TABLEGEN%

cmake ../llvm -DLLVM_TARGETS_TO_BUILD:STRING=AArch64 -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX=install_local -DCMAKE_CROSSCOMPILING=True -DLLVM_TARGET_ARCH=AArch64 -DLLVM_NM=%LLVM_NM% -DLLVM_TABLEGEN=%LLVM_TABLEGEN% -DLLVM_DEFAULT_TARGET_TRIPLE=aarch64-win32-msvc -A ARM64 -T host=x64

cmake --build . --config Release --target install

Linker Errors: Missing Library

These are the next set of errors I ran into:

  LLVMDebugInfoPDB.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMDebugInfoPDB.lib
  LLVMOption.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMOption.lib
  LLVMSymbolize.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMSymbolize.lib
LINK : fatal error LNK1104: cannot open file 'atls.lib' [D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\tools\llvm-symbolizer\llvm-sy
mbolizer.vcxproj]
  llvm-objcopy.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\bin\llvm-objcopy.exe
  LLVMAArch64Info.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMAArch64Info.lib
  LLVMAArch64Utils.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMAArch64Utils.lib
  LLVMAArch64Desc.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMAArch64Desc.lib
  LLVMAArch64AsmParser.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMAArch64AsmParser.lib
  LLVMDlltoolDriver.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMDlltoolDriver.lib
  LLVMLibDriver.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMLibDriver.lib
  llvm-ar.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\bin\llvm-ar.exe
  llvm-dwarfdump.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\bin\llvm-dwarfdump.exe
  LLVMMCDisassembler.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMMCDisassembler.lib
  LLVMAArch64Disassembler.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\lib\LLVMAArch64Disassembler.lib
LINK : fatal error LNK1104: cannot open file 'atls.lib' [D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\tools\llvm-objdump\llvm-objdu
mp.vcxproj]
  llvm-readobj.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\bin\llvm-readobj.exe
  llvm-rc.vcxproj -> D:\repos\llvm\dups\llvm-project\build_llvm_AArch64\Release\bin\llvm-rc.exe

LINK : fatal error LNK1104: cannot open file ‘atls.lib’ llvm-objdump.vc xproj – Search led me to the solution in linker – Cannot Open File atls.lib – Stack Overflow: installing the C++ ATL. The screenshots below show the order in which I tried to install various components until I got the one I needed: C++ ATL for latest v143 build tools (ARM64/ARM64EC).

Linker Errors: Library Machine Type Conflicts

Now that atls.lib could be found, the build failed with this error:

  XCOFFDump.cpp
  llvm-objdump-driver.cpp
LLVMDebugInfoPDB.lib(DIASession.obj) : error LNK2019: unresolved external symbol "long __cdecl NoRegCoCreate(wchar_t const *,struct _GUID const &,struct _GUID const &,void * *)" (?NoRegCoCreate@@YAJPEB_WAEBU_GUID@@1PEAPEAX@Z) referenced in function "public: static class llvm::Error __cdecl llvm::pdb::DIASession::createFromExe(class llvm::StringRef,class std::unique_ptr<class llvm::pdb::IPDBSession,struct std::default_delete<class llvm::pdb::IPDBSession> > &)" (?createFromExe@DIASession@pdb@llvm@@SA?AVError@3@VStringRef@3@AEAV?$unique_ptr@VIPDBSession@pdb@llvm@@U?$default_delete@VIPDBSession@pdb@llvm@@@std@@@std@@@Z) [D:\repos\llvm\llvm-project\build_llvm_AArch64\tools\llvm-objdump\llvm-objdump.vcxproj]
LLVMDebugInfoPDB.lib(DIASession.obj) : error LNK2019: unresolved external symbol IID_IDiaDataSource referenced in function "public: static class llvm::Error __cdecl llvm::pdb::DIASession::createFromExe(class llvm::StringRef,class std::unique_ptr<class llvm::pdb::IPDBSession,struct std::default_delete<class llvm::pdb::IPDBSession> > &)" (?createFromExe@DIASession@pdb@llvm@@SA?AVError@3@VStringRef@3@AEAV?$unique_ptr@VIPDBSession@pdb@llvm@@U?$default_delete@VIPDBSession@pdb@llvm@@@std@@@std@@@Z) [D:\repos\llvm\llvm-project\build_llvm_AArch64\tools\llvm-objdump\llvm-objdump.vcxproj]
LLVMDebugInfoPDB.lib(DIASession.obj) : error LNK2019: unresolved external symbol CLSID_DiaSource referenced in function "public: static class llvm::Error __cdecl llvm::pdb::DIASession::createFromExe(class llvm::StringRef,class std::unique_ptr<class llvm::pdb::IPDBSession,struct std::default_delete<class llvm::pdb::IPDBSession> > &)" (?createFromExe@DIASession@pdb@llvm@@SA?AVError@3@VStringRef@3@AEAV?$unique_ptr@VIPDBSession@pdb@llvm@@U?$default_delete@VIPDBSession@pdb@llvm@@@std@@@std@@@Z) [D:\repos\llvm\llvm-project\build_llvm_AArch64\tools\llvm-objdump\llvm-objdump.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\DIA SDK\lib\amd64\diaguids.lib : warning LNK4272: library machine type 'x64' conflicts with target machine type 'ARM64' [D:\repos\llvm\llvm-project\build_llvm_AArch64\tools\llvm-objdump\llvm-objdump.vcxproj]
D:\repos\llvm\llvm-project\build_llvm_AArch64\Release\bin\llvm-objdump.exe : fatal error LNK1120: 3 unresolved externals [D:\repos\llvm\llvm-project\build_llvm_AArch64\tools\llvm-objdump\llvm-objdump.vcxproj]
  1>Generating ../../Release/bin/llvm-ranlib.exe
  Building Custom Rule D:/repos/llvm/llvm-project/llvm/tools/llvm-ar/CMakeLists.txt
  1>Building Opts.inc...

I ran Process Monitor to determine the command line of the failing linker operation. The command line itself was not helpful:

"C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\HostX64\arm64\link.exe" /ERRORREPORT:QUEUE @C:\Users\saint\AppData\Local\Temp\MSBuildTemp\tmpabac6ac6d830494aaaa6bcb2aa2219e7.rsp

I asked copilot why this linker error was happening. The Claude Opus 4.5 agent stated that “There is no ARM64 version of diaguids.lib provided by Microsoft“.

The DIA SDK aarch64 libraries – Search AI summary also claimed that “Microsoft does not ship prebuilt DIA SDK libraries for AArch64 (ARM64) targets” but this result, Getting Started (Debug Interface Access SDK) – Visual Studio (Windows) | Microsoft Learn, indicated otherwise. I verified that there was an arm64 equivalent path to the DIA on disk and continued with the prompt: “That’s not correct. “C:\Program Files\Microsoft Visual Studio\2022\Enterprise\DIA SDK\lib\arm64\diaguids.lib” exists on disk. Why doesn’t the build use it?

This explanation made sense. Setting the environment variable before running the first cmake command resolved this issue:

set VSCMD_ARG_TGT_ARCH=arm64

The build then concluded successfully with this line: -- Installing: D:/repos/llvm/llvm-project/build_llvm_AArch64/install_local/lib/cmake/llvm/LLVMConfigExtensions.cmake

Article info



Leave a Reply

Your email address will not be published. Required fields are marked *