About a year ago, I started looking into ways to cross-compile Windows applications from within Linux. This brought me to a cool project called MXE (short for M Cross Environment). With MXE, you can use your Linux machine to generate Windows binaries without having to install any virtual machines or compatibility layers. In this post, I’ll walk you through the process of setting up MXE and turning your source code into a Windows program.
What is MXE, and Why is it Useful?
MXE—or the M Cross Environment—is a tool for compiling cross-platform software in Linux. It works for normal applications and also supports a number of free libraries including GTK, Qt, and SDL. It can also target 32-bit or 64-bit platforms. It uses MinGW, an open source development environment for creating Windows applications. And of course, MXE and all of its components are fully open source.
With MXE, software created in Linux can be effortlessly cross-compiled for Windows systems. This makes it significantly easier for developers to port their software to different platforms. Best of all, the software (for the most part) behaves exactly the same on Windows as it does on Linux.
My experience with MXE came when porting a Qt-based desktop application to Windows. Qt is a framework for building graphical applications written in C++ and other languages. Qt runs on Linux and Windows, and the framework handles most idiosyncrasies between the two platforms.
Compiling a Qt application is very straightforward, especially when using Qt Creator, the official IDE for developing Qt-based software. Qt Creator auto-detects any Qt installations on your local system, letting you quickly build and run executables for your current platform. To get an executable for a different platform like Windows, you either need to compile your application in a Windows environment, or use a tool like MXE.
Using MXE is a very straightforward process consisting of downloading MXE, building the required tools, then using those tools to cross-compile your application.
Step 1: Install MXE
The first step is to download MXE. You can either build MXE from source, or download pre-compiled binaries. For the purposes of this post, let’s build it form source.
First, open a terminal and clone the MXE Git repository to your computer. You’ll want to install Git if you don’t already have it installed.
git clone https://github.com/mxe/mxe.git
Next, change into the directory:
cd mxe/
From here, we’ll need to build the tools necessary to cross-compile our projects. Depending on what your project uses, you might need to build one or more of the packages listed on the MXE homepage. Since we’re cross-compiling a Qt project, we’ll focus on the Qt libraries.
Qt is modular by nature, and splits different functionality into different packages. The core functionality is provided by the qtbase package, although you can build other packages if your application requires it. Alternatively, you can build all of Qt using the qt5 package, but this will take much longer to complete than if you had chosen specific packages.
To build the minimum tools required, run:
make qtbase
Or, to build all of Qt, run:
make qt5
This starts the process of downloading and building the cross-compiler along with all of its dependencies. By default, this builds a cross-compiler for 32-bit applications, but you can specify the target (32 or 64-bit) using the MXE_TARGETS environment variable:
make MXE_TARGETS=x86_64-w64-mingw32.static qtbase
This will take some time, so grab a cup of coffee or catch up on the latest news. Once the build is done, you’ll have a new tool for generating Makefiles called qmake, which you’ll use to build your Windows executable.
Step 2: Compile Using MXE
The last step installed the qmake tool under the MXE directory as <MXE directory>/usr/i686-w64-mingw32.static/qt5/bin/qmake. Open your terminal and change your working directory to that of your Qt project. Then, run the following commands:
$ <MXE directory>/usr/i686-w64-mingw32.static/qt5/bin/qmake $ make
And that’s it! When the build is finished, you can find the Windows executable in the release/ folder. Although you compiled it for 32-bit targets, it will run just as well in 64-bit environments. And since it’s a static executable, you can run it on a system that doesn’t already have Qt installed.
If you choose, you can test your executable by using Wine, a compatibility layer for running Windows programs in Linux:
$ wine release/my-program.exe
(Optional) Step 3: Configure Qt Creator
Qt Creator is a fully-featured IDE for developing Qt applications. If you choose, you can build a Windows executable from within Qt Creator simply by calling your cross-compiled qmake tool instead of the default qmake tool.
Open the Build Settings panel for your project and add a new Release configuration. Under Build Steps, remove the qmake step and replace it with a Custom Process Step. Add the following parameters:
- Command: Path to the qmake tool generated by MXE (<MXE directory>/usr/i686-w64-mingw32.static/qt5/bin/qmake)
- Arguments: Path to your project’s main file (%{CurrentProject:FilePath})
- Working directory: Where to place the executable (I use %{buildDir})
Make sure to change the Build directory and rename the configuration to something meaningful. Now, press Ctrl-B to try building your project. Congratulations, you can now build Windows applications in Linux!
Nice tutorial. However, the Qt Creator integration can be set up better 🙂
First, you add a new Kit:
1. Go to Tools > Options > Kits
2. Go to tab Compilers
3. Add two new MinGW compilers (one for C, one for C++)
(/usr/bin/i686-w64-mingw32.static.g++ resp. gcc)
Click Apply
3. Go to tab Qt Vesions
4. Add the mxe Qt version by adding the path to qmake
(/usr/i686-w64-mingw32.static/qt5/bin/qmake)
Click Apply
5. Go to tab Kits
6. Add a new Kit, assign the new created compiler and Qt version, set Debugger to none
7. Change the Environment of the Kit by adding the path to the compilers
(/usr/bin:${PATH})
8. Close the dialog Options by clicking Ok
9. Select the new created Kit for your project, select Release (important!)
10. Cross build for Windows and enjoy
Oops, forgot to add one important thing to step 3:
– Choose ABI: x86-windows-msys-pe-32bit (or 64bit if you want to use that)
After doing all your steps, when I tried to compile a simple code, I got the following messge:
:-1: error: i686-pc-mingw32-uic: Command not found
what is the reason for that?
I’m not sure. Did you have any problems building MXE? You could try running
make cc
to rebuild the base packages, in case something is missing.