I am trying to cross-compile C applications from Linux (64 bit) to Windows (64 bit) using Clang. I read the page on cross-compilation, which wasn't too helpful.
As a simple test, I have the following code in test.c
:
#include <stdio.h>
int main()
{
puts("hello world");
return 0;
}
My best guess so far is clang -o test -target x86_64-win64-?ABI? test.c
. However, I have no idea what ABI Windows 64 bit uses. When I run clang with the target triple x86_64-win64-abcdefg
, it seems to compile fine--that is, it finishes without error and results in something that is a somewhat-valid binary. That doesn't make any sense, considering abcdefg
is definitely not a valid ABI. The resulting binary is far too big for such a small program, and Windows seems to think it's a 16-bit program (???). Disassembling it reveals references to "linux" and "gnu", so it would seem Clang is not even trying to compile for Windows.
Targeting win32 (x86_64-win32-???ABI???
) results in the following error message:
test.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
^
1 error generated.
This error, if I'm not mistaken, is the result of it not knowing where to look for system files. I assume Clang does store Windows header files somewhere, since it claims to be able to cross-compile; but where? If it doesn't, is there somewhere I can download them?
Is there a list of all the architectures, systems, and ABI's Clang supports somewhere? The list on the cross-compilation page is not comprehensive.
The page also suggests using -mcpu=...
, but a warning suggests that is outdated. Instead, as the warning recommends, I tried -mtune=x86_64
. This seems to have no effect. Is this even necessary, considering the architecture is specified in the target triple?
I have seen some literature that suggests I need lld
, LLVM's experimental linker. Is this the case? I have had some issues compiling lld, and would like to avoid it if possible.
Cross compilation issues On the other hand, Clang/LLVM is natively a cross-compiler, meaning that one set of programs can compile to all targets by setting the -target option.
For best IDE support in Visual Studio, we recommend using the latest Clang compiler tools for Windows. If you don't already have the tools, you can install them by opening the Visual Studio Installer and choosing C++ Clang tools for Windows under Desktop development with C++ optional components.
The Linux kernel has always traditionally been compiled with GNU toolchains such as GCC and binutils. Ongoing work has allowed for Clang and LLVM utilities to be used as viable substitutes. Distributions such as Android, ChromeOS, and OpenMandriva use Clang built kernels.
If you want to use clang instead of GCC, you can add -DCMAKE_C_COMPILER=/path/to/clang -DCMAKE_CXX_COMPILER=/path/to/clang++ . You can also use ccmake , which provides a curses interface to configure CMake variables in an interactive manner.
Your best option to develop Window binaries using clang is Mingw-w64, as you need more than just a compiler to compile for another system. You also need a linker for that system as well as libraries to link against, so basically you need an SDK for the platform you are targeting and Mingw-w64 comes with everything you require.
https://www.mingw-w64.org/downloads/
You can install it on a Linux system or macOS system and cross compile or you can install it directly on a Windows system and compile natively, without the requirement to have anything like the SDK of Visual Studio (VS). Actually the same code should compile with any installation of Mingw-w64 regardless of the system you are using for building it.
Please note that Mingw does not give you a POSIX API on Windows. You will have the standard C/C++ API available that every platform must support and for everything else, you have to use native Windows API just like you'd have to when developing software with VS. As not everyone may understand what I've just said, here's an example:
You can use fopen()
to open a file as that is a standard C API function that every platform supports. But you cannot use open()
to open a file, as that is a POSIX function defined in unistd.h
and this header doesn't natively exist on Windows (not unless you have installed a POSIX subsystem which is not even available for all Windows version).
In Windows you have windows.h
and instead of fopen()
you can use the function CreateFile()
, which despite its name does not always create a file, it can also open existing ones for reading, and then you will get a HANDLE
that you need to pass to CloseHandle()
once you are done with it (which is like close()
on UNIX systems).
If you would like to get a POSIX-like API on Windows with no requirement of users having to install one, so you can share the same code between your Windows and Linux projects, appropriate wrappers do exist for that but that is not related to the compiler or SDK you are using. These are just Windows libraries you are liking against and that implement some fraction of the POSIX API on top of the Windows API; which sometimes comes with caveats. It's the opposite of Wine which implements most of the Windows API on top of POSIX and other native system APIs.
So you see, what makes porting C/C++ code hard is not the language itself but the libraries that act as a layer between your code and the system below it, as they differ from system to system, even between POSIX or POSIX-like systems. There are fundamental differences between Linux, FreeBSD, and macOS, despite the fact that they share a lot of the same API, too. And if you want to test your Windows binaries after the build, you either need a real Windows environment to do so or at least an emulated one like Wine does provide.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With