Using MXE...

I have been cross compiling source code for Windows with MXE for five years now, using a Virtual Machine (VM) specifically setup for this purpose. When the need came to revisit cross compiling, specifically when I wanted to provide 32bit and 64bit binaries of the great AAC encoder fdkaac for Windows 10, I took the opportunity to rebuild my VM and make a clean MXE installation. And, Gentle Reader, this is in the middle of the world wide COVID-19 lockdown so I have decided to document the whole process as well so that others will hopefully profit from my example and will not have to fumble around with the dark magic of cross compiling, as I did in the early days! Let me know, using the email link at the base of this page, if I have been successful in this goal...

Install MXE, create fdkaac binaries...

The heading above makes it all look very easy but, Gentle Reader, there is a little bit of hard work to do before actually outputting the required binaries. The full path to the goal will actually require the following three steps:

  1. Create a suitable Virtual Machine: Since I am rebuilding this VM I will be using a January 2021 snapshot of Slackware -current which is creeping towards a 15.0 release at the moment. My old Ubuntu 18.04 VM will finally go to the bit bucket.
  2. Install a fully featured version of MXE: This involves not only installing the MXE scripts from git but also installing a base compiler set suitable for generating both 32bit and 64bit static Windows binaries.
  3. Cross compile and package the fdkaac binaries: Not only actually doing the cross compile but also creating a decent archive and then comprehensively testing both binaries under my Windows 10 VM. These packages are being released to the public and I do not want to look like an idiot!

And so, courtesy of the global lockdown, the reasonably complex documentation now commences. Remember that that are really only three steps required although I confess that some of these steps are a little complex and time consuming. On my own machine, while writing it all up as I went, the whole process took an entire morning to accomplish although perhaps I am becoming slower as well as older...

Create a suitable Virtual Machine...

When I started seriously cross compiling with MXE I realised from the outset that this would be better done in a Virtual Machine and thus isolated from my day to day computing needs. For some time I used Ubuntu 18.04 as a VM in part because it was easy to setup and run and in part because I still had strong connections with the Ubuntu world. However with this rebuild and write up I have switched to a snapshot of the development version of Slackware taken early in January 2021. It is a solid investment of time and effort to get this set up correctly but a well worthwhile investment. Any Linux distro could be used and at least some of the special steps I have taken with this VM should translate well to your own choice of distro and VM. A few points

I had to restrain myself from doing my usually obsessive compulsive setup of Slackware as this VM is a highly focussed one with a single purpose: to easily cross compile applications for use in the world of Windows. However I did spend some time configuring a few small things as well as installing Geany for text editing. Perhaps 2 hours or so getting the small things right, after all I am retired now so my time is my own now! And I can give you a sneak preview, Gentle Reader, in telling you that in this goal my Slackware VM performed well above expectations when allied with MXE!

Install a fully featured version of MXE...

After the work of setting up a VM dedicated to MXE the setup of MXE itself was pretty light work! The scripts live in a git repository and can be installed to $HOME as follows:

cd $HOME
git clone https://github.com/mxe/mxe.git

I have never bothered with a system installation of MXE, although this can be done, as a single user VM has always been enough. Now a basic set of tools can be installed and we will be installing the basics for two targets:

  1. i686-w64-mingw32.static: This target will allow for the compilation of 32bit, static binaries. By static I mean that no external dlls will be built and the binary itself should be completely self contained.
  2. x86_64-w64-mingw32.static: This target will allow for the compilation of 64bit, static binaries. By static I mean that no external dlls will be built and the binary itself should be completely self contained.

With this hopefully understood a basic set of tools for both targets can be installed. Note that I use MXE_PLUGIN_DIRS=plugins/gcc10 which will allow for the use of gcc 10.x rather than the older, default offering:

cd $HOME/mxe
make cc MXE_TARGETS='i686-w64-mingw32.static x86_64-w64-mingw32.static' MXE_PLUGIN_DIRS=plugins/gcc10

When the long installation process is done (and 2.9 GiB of MXE goodness has been installed!!) the path to your MXE executables will need to be prepended to your $PATH. I add the following to ~/.bashrc (although there are a few other options for the placement of this snippet):

# Prepend MXE to the system $PATH:
export PATH="$HOME/mxe/usr/bin:$PATH"

Now either source this file or perhaps just reboot, but before doing this you should add the non-default gcc 10 choice to MXE's settings.mk file. This gcc 10 option can be painlessly added as follows:

echo 'override MXE_PLUGIN_DIRS += plugins/gcc10' >> $HOME/mxe/settings.mk

There are several options in this file worth experimenting with but, Gentle Reader, I will leave that to you because now with setup complete we can prepare to actually start cross compiling.

Cross compile and package the fdkaac binaries...

So finally to the actual process of cross compiling the amazing AAC encoder fdkaac for use on Windows 10! fdkaac requires both libiconv and fdk-aac for a successful compile so another trip to MXE itself to prepare these libraries. Note that if you have not added the gcc 10 option to your MXE configuration file you will also need to append MXE_PLUGIN_DIRS=plugins/gcc10 to the this command:

cd $HOME/mxe
make fdk-aac libiconv MXE_TARGETS='i686-w64-mingw32.static x86_64-w64-mingw32.static'

Again there are two targets being used here: one for 32bit Windows (i686) and one for 64bit Windows (x86_64). When this is done the following commands will download, compile and finally package the 32bit fdkaac. Note that every line with the '#' mark at the begining of the line is a hopefully helpful note:

#--------------------------#	
# Create the 32bit fdkaac  #
#--------------------------#	
cd $HOME/Desktop
wget --content-disposition https://github.com/nu774/fdkaac/archive/refs/tags/v1.0.2.tar.gz
tar xvf fdkaac-1.0.2.tar.gz && cd fdkaac-1.0.2 
autoreconf -fiv
./configure CFLAGS="-O3 -march=i686 -mtune=i686" \
            --host=i686-w64-mingw32.static \
            --with-libiconv-prefix=$HOME/mxe/usr/i686-w64-mingw32.static
make -j 8
strip --strip-unneeded fdkaac.exe

#--------------------------#	
# Package the 32bit fdkaac  #
#--------------------------#

cd $HOME/Desktop
zip -j fdkaac-1.0.2-win32-ads.zip fdkaac-1.0.2/{fdkaac.exe,README,COPYING}
rm -rfv $HOME/Desktop/{fdkaac-1.0.2.tar.gz,fdkaac-1.0.2}

Now how cool is that! The resulting file will be on your desktop as fdkaac-1.0.0-win32-ads.zip ready for installation to either a 32bit or a 64bit Windows 10 installation. But perhaps you are after a 64bit copy of fdkaac, which will be suitable for a 64bit Windows 10 installation only? Note the small differences in the syntax below where the 64bit fdkaac is now built:

#--------------------------#	
# Create the 64bit fdkaac  #
#--------------------------#	
cd $HOME/Desktop
wget --content-disposition https://github.com/nu774/fdkaac/archive/refs/tags/v1.0.2.tar.gz
tar xvf fdkaac-1.0.2.tar.gz && cd fdkaac-1.0.2 
autoreconf -fiv
./configure CFLAGS="-O3 -fPIC" \
            --host=x86_64-w64-mingw32.static \
            --with-libiconv-prefix=$HOME/mxe/usr/x86_64-w64-mingw32.static
make -j 8
strip --strip-unneeded fdkaac.exe

#--------------------------#	
# Package the 64bit fdkaac  #
#--------------------------#	

cd $HOME/Desktop
zip -j fdkaac-1.0.2-win64-ads.zip fdkaac-1.0.2/{fdkaac.exe,README,COPYING}
rm -rfv $HOME/Desktop/{fdkaac-1.0.2.tar.gz,fdkaac-1.0.2}

And thus it is all done! I have tested the resulting binaries on my 64bit Windows VM and they both work perfectly. For those readers of this page who are perhaps simply after binaries to use with Foobar2000 and friends and could not be bothered building their own I have placed the two files here... It is my hope however that at least some readers of this page have seen that the dark magic of cross compiling does not have to really be so dark nor indeed so difficult to accomplish. Perhaps some will even be guided a little by the steps I have taken and carefully documented above as they move onto even bigger cross compiling projects? Let me know...