Tuesday, March 29, 2011

Compiling Windows Executables on Linux

For me Windows is like that girl that you want to forget about but you can't because she seems to be everywhere and too many people like her. As a software engineer you can't just leave windows behind because too many people still rely on it. If only there were a way that I could continue to use Linux but easily provide the same software for Windows.

What I'm talking about is cross compiling. It simply refers to compiling software to run on a target system that is different from the system running the compiler. This has been common in the Linux community and the embedded development communities for years. I'm going to describe the steps to installing cross compilers for Windows 32-bit and 64-bit on Fedora 14. I'm also going to show how to set-up Eclipse projects and create build configurations that will use the cross compilers to generate binary files that will run on Windows.

Thanks to Eric van Pienbroek and some other volunteers, Fedora 15 will be shipped with the MinGW64 (Minimum GNU tools for Windows x64) cross compiling toolchain. Until then you can install the compilers using the repository file from the Cross Compiler Framework wiki page. Alternatively this can be done from the command line with the following:

cd /etc/yum.repos.d
sudo wget http://build1.openftd.org/fedora-cross/fedora-cross.repo

Now that the repository is set-up you can install the toolchain using the following command:

sudo yum install mingw32-gcc mingw32-gcc-c++ mingw64-gcc mingw64-gcc-c++

Congratulations you can now compile Windows executables from your Fedora machine! All of your favorite GCC tools are provided for working with Windows executables such as strip, nm, ar, and even GDB! All tools are prefixed with i686-w64-mingw32- or x86_64-w64-mingw32-. You can even build code using autoconf tools using the mingw32-configure and mingw64-configure tools. Continue reading if you want to learn how to set-up Eclipse projects to cross compile using your newly installed cross toolchain.

Open Eclipse and select new C++ project. For the project type select 'Empty Project' and 'Linux GCC' for the toolchain. While Eclipse does provide options 'Cross-Compile Project' and 'Cross GCC' I have found both lacking full support. For example, if you select a Cross GCC toolchain Eclipse will ask you for the prefix of the tool chain which in our case would be i686-w64-mingw32-. In the project options under 'C/C++ Build'-> 'Tool Chain Editor' you can select the tools you want to use to build the project and there are a few listed such as 'Cross G++ Compiler' and 'Cross GCC Compiler' but there is no cross archiver or cross assembler, even though these tools are supplied by the MinGW toolchain.

For this reason I suggest selecting the 'Linux GCC' toolchain. Then open the project options and under 'C/C++ Build' -> 'Settings' add the prefix i686-w64-mingw32- (or x86_64-w64-mingw32- for 64-bit executables) to each tools command.

Because these binaries are built with the MinGW32/64 they require libgcc_s_sjlj-1.dll to be distributed with the binary. The DLL can be found in the /usr/i686-w64-mingw32/sys-root/mingw/bin (or /usr/x86_64-w64-mingw32/sys-root/mingw/bin) directory. The extra DLL is required to for setjmp/longjmp C exception handling and is approximately 500K in size.

If you're not too worried about the size of your binaries you can have the linker statically link in this code, that way you won't have to distribute the shared DLL with your binary. To do this you need to tell the linker to statically link the binary. Open the project properties in Eclipse and select 'C/C++ Build' -> 'Settings' then select the 'Miscellaneous' option of the linker. Add the -static option to the 'Linker flags' text box.

When building binaries with C++ you will also be required to distribute libstdc++-6.dll with your binary. This is the standard C++ library and is quite large (~6MB). Like libgcc_s_sjlj-1.dll it can be statically compiled into your binary with the -static option to the linker. The resulting size of your binary will depend on how much of the standard library you happen to utilize.

Now that you can build Windows executables and DLL without leaving Linux, get out there and try it out! If you find that this is helpful don't forget to thank Erik van Pienbroek and the rest of the Fedora MinGW64 special interest group for all their hard work that has made this possible. If I have enough time and there is enough interest I will post about how to use GDB to debug the Windows binaries built with the MinGW64 toolchain.

No comments: