Clang C++ Cross Compiler - Generating Windows Executable from Mac OS X
Asked Answered
H

4

44

I have created a C++ application using Xcode on my Mac using the Clang compiler.

I want to compile my source files to create an executable that can be ran on a windows machine however I cant get Clang to generate me an executable.

Here is what I've tried:

clang++ -std=c++11 -stdlib=libc++ -arch x86_64 class1.cpp class2.cpp... -o executable.exe

This creates an executable however this does not run (Windows gives me an error to do with the application being 16 bit -dont understand this- that cant run on 64 bit)

clang++ -std=c++11 -stdlib=libc++ -target i386-pc-win32 class1.cpp class2.cpp 

For some reason whenever I use the -target flag I get an error stating that the compiler cannot find the <iostream> header however any other time it never moans.
I have tried using -Ipath/to/iostreamfolder/ however this doesnt produce any better results

Any suggestions would be great! Thanks!

I have also tried the '-triple x86-pc-win32' flag however I get this warning clang: warning: argument unused during compilation: '-triple x86-pc-win32'

Hilton answered 23/4, 2014 at 15:32 Comment(4)
What executable format are you producing? What does file executable.exe say? Maybe you're making an OS X binary that just happens to have a .exe file extension.Discuss
Within the unix environment executable.exe is of type document, when i transfer it to windows and try and invoke it from command line I get the error The program or feature cannot start or run due to incompatibility with 64-bit versions of windowsHilton
I mean literally use file executable.exe to see what type it thinks it is. The file tool is usually pretty good about identifying what kind of file you've created. If it's "Mach-O 64-bit executable x86_64" then you've created the wrong kind of binary. If it's "PE32 executable for MS Windows" then you're on the right track.Discuss
Yeah im getting Mach-O 64... I understand that in the example that I provided that generated this executable I didnt specify an architecture platform hence why I get this executable. However any attempt I make to specify a platform such as win32 is ignored or not liked by the compilerHilton
S
30

Clang can in principle be used as a cross compiler: unlike most compilers clang/LLVM includes components (such as the codegen, assembler, and linker) for different platforms in the same binary.

However you'll run into a number of problems trying to use it as such in a production capacity:

  • You need platform libraries and headers. To generate an executable that will work on Windows you need Windows headers and Windows libraries you want to link to, either import libs if you're dynamically linking or static libs for static linking. You should be able to get these from an installation of Visual Studio.

  • Many C++ features such as name mangling and RTTI support are not complete on Windows. You'd have these same problems compiling for Windows on Windows with Clang. Windows C++ support is pretty much complete these days.

  • The LLVM project includes the lld linker, which is apparently far enough along that it can self host on x86 Windows and so might work for you as a cross-platform linker, however lld is not yet a standard part of clang distributions. Clang on OS X still uses the OS X platform linker ld by default as does Clang on Windows (link.exe). You'll need to get lld and figure out how to link with it, or find some other cross-platform linker.

  • The clang driver isn't written as a cross-platform compiler driver. You'll likely have to do a lot more hands-on work to run a cross-platform compilation. Take a look at the output of clang -###: the clang driver constructs that command for you, but you may have to do much of the same work as the clang driver by hand. And since clang gets much less testing at cross-platform compilation you're likely to run into more bugs.

  • Xcode is not going to help you with any of this. It can configure clang to build for OS X or iOS, but you'll have to manually configure cross-platform builds to Windows.

I'm relatively confident that one could cobble together an LLVM based environment to build a C "Hello, World" Windows exe on OS X or Linux, but it's not quite ready for Xcode to add a "Windows" item to the list of possible target platforms.


If you're not a compiler developer you're probably best off just copying your source code to a Windows machine and building with Visual Studio. If you are, or want to be, a compiler developer then by all means, help push Clang's cross-compilation abilities forward. I think the Clang universal driver project is exciting and I would really like to see progress continue.


I've successfully done the opposite cross-compilation: compiling a Mac OS X executable on Windows. This turned out to be quite easy to do manually on a small program, i.e. directly compiling a .cpp file.

First, Mac OS X development tools come with "SDKs" which contain all the system libraries and headers for a particular OS. The largest challenge here was figuring out how to transfer the SDK to Windows while preserving all the symbolic links in the SDK. (For some reason creating symbolic links on Windows requires elevated privileges, so after producing a tar.gz on OS X with the symbolic links I had to run 7zip on Windows as an administrator to correctly expand the archive.)

Once the SDK is available on Windows there's a single flag to tell clang where to get all the system dependencies: -isysroot. This combined with the -target flag were all that I needed to tell clang how to produce complete object files for OS X.

For linking I manually used lld, as the compiler driver didn't seem support using cross linking with lld. lld supports similar flags for determining the target system libraries.

The final step was simply copying the produced executable to an OS X machine, enabling the execute permission (Windows doesn't support the same file permissions so the execute bit doesn't get set when building) and running the result.

Silicosis answered 23/4, 2014 at 22:42 Comment(8)
Yeah I found that Bootcamping my Mac to run Windows and installing visual studio 2013 was the way forward. This worked a treat obviously, but I was wondering if there was a cross compilation option so hence my question. ThanksHilton
Some download link so that I can at least try to see If I can build for windowhost and multiple targets?Modred
@DarioOO You'll want to extract windows libraries and headers from installs of Visual Studio. You'll need builds of clang and lld. Since work is ongoing in these areas you should probably build from the latest source instead of using release binaries. clang lld.Silicosis
thanks! but I seems we get confused on terms, Window host means => compiler running on windows for me, so Compiling on windows for Linux & mac. Anyway I'll try, I'm bored to switch on Linux VM each time I have to compile for Linux & MacModred
@DarioOO Oh, the question was about targeting Windows. If you want to compile on Windows and target other platforms you'll probably have much better luck, as clang already fully supports linux and OS X targets. You'll need to extract headers and libraries from an install of whatever platform you want to target, instead of from VS. Otherwise the process will be the same.Silicosis
@Silicosis Could you please provide more details on how you used the lld to link the OS X binary on Windows? I am trying to do cross compilation from Windows to OS X and lld seems to only support Linux (ld.lld.exe) and Windows (ld-link.exe) targets.Hypsometry
@KarelPetranek Try: lld -flavor darwin.Silicosis
@Hilton please consider changing the accepted answer to the step-by-step instructions.Heighten
H
58

Here are step-by-step instructions for building a Hello World .exe using llvm/clang on Mac OS X.

Cross-compile Hello World for Windows using Clang/LLVM on Mac OS X

Install llvm with homebrew. This will include the clang and the llvm linker.

brew install llvm

You'll need access to Visual Studio C++ libraries and headers, which are available through Visual Studio 2017 on a Windows 10 Virtual Machine (VM) or on a Windows 10 Computer. Install Visual Studio on Window, and include the following 'Individual Components' through the Visual Studio Installer:

  • Windows Universal CRT SDK
  • Windows Universal C Runtime
  • Windows 10 SDK (X.X.X.X) for UWP: C++
  • VC++ 2017 vXXX toolset (x86,x64)
  • Visual C++ 2017 Redistributable Update
  • C++/CLI support

Get access to the MSVC libraries and headers from your Mac.

  • (Option 1) Use your Windows VM and create a shared folder between host and guest.
  • (Option 2) Create a remote share on your Windows computer and connect to it from your Mac.
  • (Option 3) Copy the libraries and headers to your Mac, following any licensing terms.

Find the specific directories on your llvm+MSVC install that correspond to the following:

// LLVM:
INCLUDES: /usr/local/Cellar/llvm/5.0.0/include

// MSVC:
INCLUDES: "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\include"
LIBS: "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.11.25503\lib\x86"

// C Runtime Library (CRT):
INCLUDES: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\ucrt"
LIBS: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\ucrt"

// User-Mode Library (UM):
INCLUDES: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\um"
LIBS: "C:\Program Files (x86)\Windows Kits\10\Lib\10.0.15063.0\um\x86"

// 'Shared' includes:
INCLUDES: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\shared"

// WinRT includes:
INCLUDES: "C:\Program Files (x86)\Windows Kits\10\Include\10.0.15063.0\winrt"

// Figure out your MSC 'version', e.g.
Visual C++ 2012 (11.0)   -->     MSC_VER=1700
Visual C++ 2013 (12.0)   -->     MSC_VER=1800
Visual C++ 2015 (14.0)   -->     MSC_VER=1900
Visual C++ 2017 (15.0)   -->     MSC_VER=1910

Create your Hello World src:

// hello.cc

#include <cstdio>

int main(int argc, char* argv[]) {
  printf("Hello, World!\n");

  return 0;
}

Compile with clang:

clang -target i686-pc-win32 \
  -fms-compatibility-version=19 \
  -fms-extensions \
  -fdelayed-template-parsing \ 
  -fexceptions \
  -mthread-model posix \
  -fno-threadsafe-statics \
  -Wno-msvc-not-found \
  -DWIN32 \
  -D_WIN32 \
  -D_MT \
  -D_DLL \
  -Xclang -disable-llvm-verifier \
  -Xclang '--dependent-lib=msvcrt' \
  -Xclang '--dependent-lib=ucrt' \
  -Xclang '--dependent-lib=oldnames' \
  -Xclang '--dependent-lib=vcruntime' \
  -D_CRT_SECURE_NO_WARNINGS \
  -D_CRT_NONSTDC_NO_DEPRECATE \
  -U__GNUC__ \
  -U__gnu_linux__ \
  -U__GNUC_MINOR__ \
  -U__GNUC_PATCHLEVEL__ \
  -U__GNUC_STDC_INLINE__  \
  -I/usr/local/Cellar/llvm/5.0.0/include \
  -I/c/Program\ Files\ (x86)/Microsoft\ Visual\ Studio/2017/Community/VC/Tools/MSVC/14.11.25503/include \
  -I/c/Program\ Files\ (x86)/Windows\ Kits/10/Include/10.0.15063.0/ucrt \
  -I/c/Program\ Files\ (x86)/Windows\ Kits/10/Include/10.0.15063.0/shared \
  -I/c/Program\ Files\ (x86)/Windows\ Kits/10/Include/10.0.15063.0/winrt \
  -c hello.cc -o hello.o

Link with the lld linker, driven by clang:

clang -fuse-ld=lld -target i686-pc-win32 -Wl,-machine:x86 -fmsc-version=1900 \
  -o hello.exe hello.o \
  -L/external/code8-cc/cc/msvctoolchain/x86/lib/msvc \
  -L/external/code8-cc/cc/msvctoolchain/x86/lib/um \
  -L/code8-cc/cc/msvctoolchain/x86/lib/ucrt
  -nostdlib -lmsvcrt -Wno-msvc-not-found 

Copy hello.exe to your Windows computer or Windows VM and run in PowerShell:

.\hello.exe

To build 64-bit versions, change to '-target x86_64-pc-win32', '-Wl,-machine:x64', and link to x64 libraries.

Heighten answered 15/9, 2017 at 19:59 Comment(3)
Assuming a modern llvm installation from any linux package manager, I would expect the remaining steps to work well.Heighten
what the command should be if this works from Ubuntu and I have .scala nor .cpp ?Unseasonable
I've created a CMake Toolchain file allowing to easily cross-compile projects. As a basis I used LLVM's Toolchain and tweaked it, since I am running WSL-Ubuntu and wanted to use the already installed toolchain.Carboloy
S
30

Clang can in principle be used as a cross compiler: unlike most compilers clang/LLVM includes components (such as the codegen, assembler, and linker) for different platforms in the same binary.

However you'll run into a number of problems trying to use it as such in a production capacity:

  • You need platform libraries and headers. To generate an executable that will work on Windows you need Windows headers and Windows libraries you want to link to, either import libs if you're dynamically linking or static libs for static linking. You should be able to get these from an installation of Visual Studio.

  • Many C++ features such as name mangling and RTTI support are not complete on Windows. You'd have these same problems compiling for Windows on Windows with Clang. Windows C++ support is pretty much complete these days.

  • The LLVM project includes the lld linker, which is apparently far enough along that it can self host on x86 Windows and so might work for you as a cross-platform linker, however lld is not yet a standard part of clang distributions. Clang on OS X still uses the OS X platform linker ld by default as does Clang on Windows (link.exe). You'll need to get lld and figure out how to link with it, or find some other cross-platform linker.

  • The clang driver isn't written as a cross-platform compiler driver. You'll likely have to do a lot more hands-on work to run a cross-platform compilation. Take a look at the output of clang -###: the clang driver constructs that command for you, but you may have to do much of the same work as the clang driver by hand. And since clang gets much less testing at cross-platform compilation you're likely to run into more bugs.

  • Xcode is not going to help you with any of this. It can configure clang to build for OS X or iOS, but you'll have to manually configure cross-platform builds to Windows.

I'm relatively confident that one could cobble together an LLVM based environment to build a C "Hello, World" Windows exe on OS X or Linux, but it's not quite ready for Xcode to add a "Windows" item to the list of possible target platforms.


If you're not a compiler developer you're probably best off just copying your source code to a Windows machine and building with Visual Studio. If you are, or want to be, a compiler developer then by all means, help push Clang's cross-compilation abilities forward. I think the Clang universal driver project is exciting and I would really like to see progress continue.


I've successfully done the opposite cross-compilation: compiling a Mac OS X executable on Windows. This turned out to be quite easy to do manually on a small program, i.e. directly compiling a .cpp file.

First, Mac OS X development tools come with "SDKs" which contain all the system libraries and headers for a particular OS. The largest challenge here was figuring out how to transfer the SDK to Windows while preserving all the symbolic links in the SDK. (For some reason creating symbolic links on Windows requires elevated privileges, so after producing a tar.gz on OS X with the symbolic links I had to run 7zip on Windows as an administrator to correctly expand the archive.)

Once the SDK is available on Windows there's a single flag to tell clang where to get all the system dependencies: -isysroot. This combined with the -target flag were all that I needed to tell clang how to produce complete object files for OS X.

For linking I manually used lld, as the compiler driver didn't seem support using cross linking with lld. lld supports similar flags for determining the target system libraries.

The final step was simply copying the produced executable to an OS X machine, enabling the execute permission (Windows doesn't support the same file permissions so the execute bit doesn't get set when building) and running the result.

Silicosis answered 23/4, 2014 at 22:42 Comment(8)
Yeah I found that Bootcamping my Mac to run Windows and installing visual studio 2013 was the way forward. This worked a treat obviously, but I was wondering if there was a cross compilation option so hence my question. ThanksHilton
Some download link so that I can at least try to see If I can build for windowhost and multiple targets?Modred
@DarioOO You'll want to extract windows libraries and headers from installs of Visual Studio. You'll need builds of clang and lld. Since work is ongoing in these areas you should probably build from the latest source instead of using release binaries. clang lld.Silicosis
thanks! but I seems we get confused on terms, Window host means => compiler running on windows for me, so Compiling on windows for Linux & mac. Anyway I'll try, I'm bored to switch on Linux VM each time I have to compile for Linux & MacModred
@DarioOO Oh, the question was about targeting Windows. If you want to compile on Windows and target other platforms you'll probably have much better luck, as clang already fully supports linux and OS X targets. You'll need to extract headers and libraries from an install of whatever platform you want to target, instead of from VS. Otherwise the process will be the same.Silicosis
@Silicosis Could you please provide more details on how you used the lld to link the OS X binary on Windows? I am trying to do cross compilation from Windows to OS X and lld seems to only support Linux (ld.lld.exe) and Windows (ld-link.exe) targets.Hypsometry
@KarelPetranek Try: lld -flavor darwin.Silicosis
@Hilton please consider changing the accepted answer to the step-by-step instructions.Heighten
S
9

Consider using MinGW on Mac OS X to compile Windows binaries. Here are instructions on how to do it on Linux: http://www.blogcompiler.com/2010/07/11/compile-for-windows-on-linux/

You'll have to adapt them for Mac OS X and you may have to compile MinGW yourself.

http://www.mingw.org

Succeed answered 26/3, 2015 at 17:4 Comment(0)
G
2

Thanks to the xwin project, it is now very easy to obtain the Windows headers and libraries on other platforms like Mac or Linux:

  1. Install headers and libraries with xwin:
    export WINSDK_PATH="$HOME/winsdk"
    ./xwin --accept-license splat --preserve-ms-arch-notation --output "$WINSDK_PATH"
    
  2. Install clang, clang-cl, lld and if needed libomp for OpenMP. On Mac, brew install llvm should work, on Debian/Ubuntu sudo apt install clang lld libomp-13-dev clang-tools. It can also be installed with conda: conda install clang llvm-openmp.
  3. Compile your code with clang-cl. Clang-cl can be used like the Microsoft compiler cl.exe. The C runtime libraries can be linked statically (default) with option /MT or dynamically (probably better for most usage) with /MD:
    # Create a program from C++ code
    clang-cl  --target=x86_64-pc-windows-msvc -fuse-ld=lld /winsdkdir "$WINSDK_PATH/sdk" /vctoolsdir "$WINSDK_PATH/crt" /MD hello.cpp -o hello.exe
    
    # Create a DLL from C code and use OpenMP, AVX2 and LTO ("/openmp", "/arch:avx2", "-flto")
    clang-cl --target=x86_64-pc-windows-msvc -fuse-ld=lld /openmp /arch:avx2 -flto /LD /winsdkdir "$WINSDK_PATH/sdk" /vctoolsdir "$WINSDK_PATH/crt" /MD dll_test.c
    
    # The same without clang-cl
    clang -o dll_test.dll \
      -target x86_64-pc-windows-msvc \
      -isystem "$WINSDK_PATH/crt/include" \
      -isystem "$WINSDK_PATH/sdk/Include/ucrt" \
      -isystem "$WINSDK_PATH/sdk/Include/shared" \
      -isystem "$WINSDK_PATH/sdk/Include/um" \
      -Xclang --dependent-lib=msvcrt \
      -fuse-ld=lld "-L$WINSDK_PATH/crt/lib/x64" \
      "-L$WINSDK_PATH/sdk/Lib/ucrt/x64" \
      "-L$WINSDK_PATH/sdk/Lib/um/x64" \
      -flto \
      -shared \
      -march=x86-64-v3 \
      c_test.c
    

When using clang instead clang-cl, adding -Xclang --dependent-lib=msvcrt creates a dynamically linked binary like /MD.

Gowk answered 19/3, 2023 at 19:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.