Cross-compiling from Linux to Windows with Clang - c

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.

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.

The question is a bit old, but I hope this answer will help someone else.
Hypothetically, what you need is a cross-compiler that runs on Linux but builds a Windows executable using Visual Studio provided headers and libraries. The link you provided redirects you to this page which tells you how to generate one. Hypothetically, you can build LLVM version 7 like this:
cmake -G Ninja -H. -B../_bin \
-DLLVM_ENABLE_PROJECTS="llvm;clang;lld" \
-DCMAKE_INSTALL_PREFIX=/opt/llvm-win32 \
-DLLVM_TARGETS_TO_BUILD=X86 \
-DCMAKE_BUILD_TYPE=Release \
-DCLANG_TABLEGEN=/mnt/data/projects/llvm-org/dl/clang-tblgen-7 \
-DLLVM_TABLEGEN=/mnt/data/projects/llvm-org/dl/llvm-tblgen-7 \
-DLLVM_DEFAULT_TARGET_TRIPLE=i686-windows-msvc \
-DLLVM_TARGET_ARCH=i686 \
-DLLVM_TARGETS_TO_BUILD=X86 \
You may have to tweak clang/lib/Driver/ToolChains/MSVC.cpp source file so the shell separator is changed from ; to : because on Unix shells, colon is used for separating multiple paths in variable.
One more thing. LLD defaults to Windows 7 in COFF format. You may either statically or creatively modify Configuration::MajorOSVersion and Configuration::MinorOSVersion in lld/COFF/Config.h if you like to compile for an older Windows. Check Windows Versions for the correct version you like to support. Perhaps, an environment variable OS_VER could carry this information.
But even then, that's just the first step. You still would need Visual Studio installed somewhere. This is where LLVM/clang will look for even basic headers like stdio.h or libcmt.lib. Hypothetically, if you have a Visual Studio 6 or later installed somewhere you could use that. Just make sure to rename all the files and directories to small-case (again, because Linux).
After that, triggering the compiler is simple. Something like:
export VCINSTALLDIR=/mnt/data/projects/VC98
__inc="${VCINSTALLDIR}/include"
__inc="${__inc}:${VCINSTALLDIR}/atl/include"
__inc="${__inc}:${VCINSTALLDIR}/mfc/include"
export INCLUDE=${__inc}
__lib="${VCINSTALLDIR}/lib"
__lib="${__lib}:${VCINSTALLDIR}/mfc/lib"
export LIB="${__lib}"
export OS_VER="4.10" # Windows 98
exec /opt/win32/bin/clang \
-fms-compatibility \
-fms-extensions \
-fmsc-version=1200 \
-fuse-ld=lld \
$*
in a shell script will do. The INCLUDE and LIB variables are honored by LLVM. Save it as something like i686-windows-msvc6-cc and you are good to go. Hypothetically, you can now invoke the compiler on your test source like:
i686-windows-msvc6-cc -o test.exe test.c
Then, boot back into Windows or load your VM and execute test.exe.
Note this is all hypothetical because MSVC terms and conditions don't allow you to fool around with their SDK like this. This could likely also be the reason why no one distributes a cross-compiler like this either. You can of course, try this hypothetically for educational purposes. Your best options is to use the one generated with MinGW instead like Mecki suggested.

I've installed mobaxterm on my windows 10 machine. There is a free version. It provides an xserver. It contains an installation of cygwin and you can start a local terminal. you just type: apt-get install clang and clang is ready to compile and finds stdio.h without complaining.
But if you intend to run the resulting executable not on mobaxterm/cygwin but inside windows itself, you need to compile with mingwin instead.

Related

Host tools when cross-compiling (GNU Build System)

I'm either failing hard at Google today, or this is something which is non-trivial.
I have an application that I am working on for a Windows system, cross-compiling from Linux because (a) I need C99 and Microsoft's free tools for the target system does not support it and (b) I've been using UNIX for nearly 30 years anyway, and that's my "home". Changing to an MSVC stack with "native" building is not an option for me, nor is running the GNU build system on Windows (it takes forever).
The problem is that I need to have a single tool built for the system being compiled on and not the target; I need to then run that executable which will generate several .c source files and .h headers which then enable the project to compile. I am using the so-called "GNU Build System" (that is, the autotools, including autoconf/automake/libtool).
Any recipe I write will, regardless if I configure for i686-w64-mingw32 or x86_64-w64-mingw32, compile all DLLs and EXEs for the Win32/Win64 platform.
There is a way that I can force the issue by hand-crafting standard Makefile receipes, but I was trying to find an "autotools native" way of compiling and running build-time executables that are not e.g., unit tests, but source code generators.
Any ideas, short of hand-crafting Makefile recipes?
ETA: Additionally, the project is cross-platform: it does make sense to compile this one natively for Linux as well, so any solution needs to work just as well when not cross-compiling.

How to tell whether an executable was compiled for the present machine?

I have some c code that I compile and run, in a directory that is accessible from many different unix computers (various linux and mac, occasionally others), with different OS's obviously needing different executables.
I have a simple shell script that invokes the appropriate executable, prog.$OSTYPE.$MACHTYPE, compiling it first if necessary. This is very simple (although it requires using csh in order to have $OSTYPE and $MACHTYPE be reliably defined) and it almost works.
However, it turns out that even $OSTYPE and $MACHTYPE are not enough: for example, compiling on OSX 10.5 yields an executable prog.darwin.i386 which, when invoked on OSX 10.4, crashes instantly.
Yes, recompiling every time I want to run the program is one way to solve this, but it seems excessive. I know having a bin directory on every machine is a standard solution, but a non-root user may not have much write access outside their home directory (which is common to all the machines).
So my question is, is there a better approach? The compiler (often gcc) obviously knows what kind of system it is compiling for -- is there a good portable way to find out what "kind of system" my script is running on, so it can invoke the correct executable, instead of one with undefined behavior?
You could use gcc -v to figure out what the installed/runnable gcc thinks is the target arch for hosted compiling (something like $(gcc -v 2>&1 | grep Target: | sed 's/.*: *//') in bash)
edit
If you really want to be able to do this without having anything in particular installed, you could extract the config.guess script from gcc (its in the top level directory of any gcc source package) and run that. Unfortunately this won't work for all systems and might not exactly match what the system gcc package uses for some distributions, but this is the script used to configure gcc for building unless you explicitly override it...
try to use file command from shell prompt
Download some open source packages written in C and have a look at the file ./configure which is basically a large shell script that collects info from many sources, often by compiling and running short C programs. This will tell you everything that you need to know.
Since you are dealing with recent Mac OS X make sure you choose a package that is currently being maintained and supports OS X versions.

How to build executable from c written source files?

There is few files with .c anf .h extensions (cmdline.c cmdline.h core.c core.h and so on) in src directory, also there is one file "MakeFile" without extension. Is there any possibility to build these source files into some executable file on Windows 7 (64bits) ? I think i need to download compilers for C or some sdks right?
Yes.
You need to:
download and install a C/C++ compiler (I recommend TDragon's distribution of MinGW ),
add the compiler to your PATH (the installer can do it for you most of the cases); verify it's done by opening cmd.exe and typing gcc -v and mingw32-make -v, both should give you half a screenful of version information if your path is set correctly,
via cmd.exe, navigate to the folder in which the Makefile resides and call mingw32-make.
From now on everything should compile automatically. If it doesn't, post the errors.
Update:
First of all, it'd be useful for you to get the MSys package. Install it and you'll have a more recent version of make (use it instead of mingw32-make from now on).
About the CreateProcess bug, it has to do with the system PATH variable being too long. You'd need to do something like this:
open cmd
execute set PATH=c:/mingw32/bin;c:/msys/1.0/bin (change the paths here to reflect your own installation if it's different)
then as before: navigate to your project's directory, run make. Everything should be smooth now if you're not missing any external libraries.
BTW- remember not to install MinGW or MSys in directories with spaces.
I am not a Windows Developer..
But still as per my knowledge. Visual Studio (i.e 2008, I guess) has the ability to read the Makefile.
Please have a look at it..and if needed change this makefile to their format..
There are many opensource product which are platform independent..and they get compiled on both OS with the just Makefile they provided.
Or else use 'cygwin'
Developer C++ works in windows but it is actually GCC code bought into Windows, Is anyone familiar about the procedure they used to convert the linux ( .sh) to executables ??
I think i need to download compilers for C or some sdks right?
A compiler certainly, but what additional libraries you may need will depend entirely on the code itself. A successful build may also depend on the intended target of the original code and makefile. The makefile may be a GNU makefile, but there are other similar but incompatible make utilities such as Borland Make and MS NMake. If it is a simple build, you may be able to avoid the makefile issue altogether and use the project management provided by an IDE such as Visual C++ 2010 Express.
If you do not know what this code is or what it does and what it needs to build, you are taking a risk building it at all. Maybe you should post a link to the original source so that you can get more specific advice on how to build it.
[EDIT]
Ok, now looking at the code you are attempting to build, it is a very simple build, so if you wanted to avoid using GNU make, then you could just add all the *.c files in the src folder to a project in your IDE and build it.
However there is one serious gotcha, it uses the BSD sockets API and Linux system headers. You will need to first port the code to Windows APIs such as WinSock (very similar to BSD Sockets), or build it under Cygwin (a sledgehammer for a nut somewhat). There may be other Linux dependencies that need sorting, I have not looked in detail, but it looks fairly simple. That said, if you did not have the first clue regarding compiling this stuff, then perhaps this is not a task you could do?
Of course compiling the code may only be half teh problem, if it was designed to run on Linux, there may be run-time dependencies that prevent it running on Windows. Again I have not looked in detail.
Also looking at the code, I would suggest some caution, this may not be the best quality code. That may be unfair, but one obvious flaw and an indication if inexperience is the lack of include guards in the headers.

make---linux and windows formats

I am in a big problem ..i have compiled my c files using linux make file in Linux OS.
I want to compile the same files in Windows using the same make file by command prompt. For that i have nmake utility and Cygwin utility too.
I have done that successfully with simple programs with simple make file ..
But it is not possible to compile when i was using the complex C files with complex make file.
I have changed the '/' in linux make file to '\' in windows? Anyother changes?
I want to know 'Is there any special make file formats in windows?'
also the difference between them..
I am really in need of that...
Unfortunately, nmake was only loosly inspired by make, and they didn't get many important things right. By far the easiest thing to do is to start by having the same flavor of make on both platforms.
On linux, Gnu make is the default and best option.
On Windows, there are several sources for Gnu make, with some quirks to choose among. Personally, I mostly use the native win32 build of Gnu make from the GnuWin32 project. You might want to poke around at the rest of the project's packages because some of the others will be useful to have as well.
Alternative sources are Cygwin and MinGW32/MSYS.
Cygwin is a credible attempt at providing a *nix compatibility environment on top of the Windows kernel. It consists of a DLL that exports a huge percentage of *nix (especially POSIX) system calls implemented via the Windows API. That DLL also has its own idea about disk mounts and prefers *nix-style path names. The DLL itself is licensed GPL (although a commercial-use license is available for a fee), and programs built in the Cygwin environment require it by default, so that can be a factor to consider. Another factor is that Cygwin is not friendly to normal Windows users, so development projects based on it usually end up difficult for non-unix users to deal with. For a cross-platform developer, however, Cygwin can be really useful as it gets you all of the usual suspect utility programs required by your Makefile, and it includes the MinGW32 native Windows targeted GCC as well as a GCC targeting the Cygwin environment.
MinGW32 is a porting project that did a really good job of porting the GCC compilers to run as native Windows executables. If used along with the header files they supply, it is possible to use nearly all of the Windows API via a C runtime DLL that ships with modern Windows installations.
MSYS is a lightweight fork of Cygwin that contains a minimal set of utilities (starting with a *nix shell) that are usually assumed to exist by a typical *nix Makefile. Unlike Cygwin, MSYS is configured such that the default target is the native Windows API.
What I'm trying to hint at here, and probably should just state flat out, is that your compatibility issues don't end with the dialect of make you use.
The Makefile language itself is highly dependent on the command shell available, and most serious project Makefiles end up using many of the *nix the core utilities such as cp and rm.
I would strongly recommend starting with the GnuWin32 build of make, and also installing MinGW32 and MSYS. It is then relatively easy to write a Makefile that works under both MSYS and linux, and needs only a small amount of platform-specific logic.
You should consider CMake for cross-platform make but your real problem is you shouldn't have to change the '/' to '\'. If you run under cygwin or msys (recommended) this should be handled for you.
NMake is a windows tool and will parse only windows-style paths, i.e. paths with drive letters and backslashes. Therefore you should use GNU Make installed with cygwin.
nmake should read your makefiles okay, the differences are generally between versions of make rather than OSs.
The big question is what your target platform actually is, are you trying to make this code operate in Windows natively or are you looking to run it under Cygwin?
Use gnumake on both platforms. I do. I haven't touched Visual C in years.
nmake got it's own format rather than windows itself, so makefile format is related to make tool rather than os. For simple things format is similar for g(nu)make and nmake, as people suggested before consider using gmake only.

How do I cross-compile C code on Windows for a binary to also be run on Unix (Solaris/HPUX/Linux)?

I been looking into Cygwin/Mingw/lcc and I liked to be able to compile perl native C extensions on my windows(preferably under cygwin) and then run them on Solaris and HP unix without any further fuss, is this possible?
This all stems from my original perl cross-platform question here.
(This is a very old question, but missing some useful info --
I've personally done this for Solaris (SPARC & x86), AIX, HP-UX and Linux (x86, x64).)
Getting C++ cross-compiled is much harder than straight C.
HP-UX 32-bit PA-RISC is not supported because it uses SOM format instead of ELF and binutils doesn't (and likely won't ever) support SOM. In other words, you can only cross-compile 64-bit PA-RISC. (Requires PA-RISC 2.0 chip.)
I would go with mingw instead of cygwin, if you can. Cygwin introduces a lot of file permission headaches and cygwin1.dll dependencies that can be troublesome. If possible, however, build on linux. Everything will be much faster because all the tools and scripts you're running are designed for an environment where exec and stat are fast operations. Windows + NTFS is not that environment.
Start with the crosstools script, but be prepared to spend a lot of time on this.
Try with the very latest gcc/binutuils first, but if you can't overcome problems try dropping back to older packages. E.g. for Power3 (AIX) gcc 4.x series cross compiler generates bad code, 3.x is fine.
When copying native libs and headers make sure you are copying from the oldest machine you're likely to run on. Copying a new libc means your code won't run on any machine with an older libc.
When copying native libs and headers you probably want 'tar -h' to turn symlinks into actual files, also watch that on Solaris some requisite crt object files are buried in a cc directory, not under /usr/lib
Cross-compiler are very hard to setup and get working correctly.
Consider that (the people at) NetBSD have to put in a huge amount of work to get cross-compiling to work, and they're running the same OS, just different architectures.
You'd have to, at least, copy all the headers from the other OSs to Windows, and get a cross-compiler, linker etc for the target OS/architecture.
Also that may well not be possible - perl and shared libraries may be compiled with a native/non-gcc compiler which won't be available on Windows at all.
I agree with Douglas, that getting a cross compiler up and working is very hard to do. This is generally, your choice of last resort. If you are boot strapping, or making a binary for an embedded device, then often cross-compiling is your only option. You should be comfortable compiling your own gcc under Cygwin before considering cross compiling. To cross compile, you need to build a gcc to run under windows, but which will create binaries for your execution platform. Sample instructions for doing this can be found here.
Perhaps you are wanting to cross compile because you don't have root and/or can't compile on your target platform. For example, I had a hosting provider which ran Redhat Linux. I could run Perl CGI scripts, and associated modules, but I could not compile on the target machine, and an libraries I built had to exist in my own directory.
To solve this, I could have attempted to cross compile for my target platform, but instead, I decided to setup a similar host inside a VM on Windows. From within Cygwin, you can create a script which ssh's into your VM, copies your source, and does a full configure/build. The last step was to deploy the binary artifact onto my hosted system.
I've successfully had both Solaris 10 and Open Solaris running within a VM on Windows. Unfortunately, you might have a harder time running HPUX under a VM.
Why don't you have a read up on "Grand Unified Builder" (http://lilypond.org/gub/ and http://valentin.villenave.info/The-LilyPond-Report-11 (section #4))
I don't know how it works, but GUB allows the Lilypond developers to compile for about 11 platforms on a linux box.
Compile on Windows then use Wine to run them on any *nix. It works well most of the time.
No, this isn't possible at the binary level. There are so many differences at binary level between the various OSes and CPUs.
But what you can do is make the your C extensions source compatible so that it can compile to different platforms. C was designed as a "portable assembly language". As long as you stick with routines that are cross-platform, then they will usually work the same. You'll still need to test because there could be bugs that exists on particular platform.
This can't be done ... but is it that much of a hassle to recompile the code under Solaris or HP?

Resources