An Introduction to wincross

by Nathan Osman  |  posted 8 months, 3 weeks ago  |  permalink

I am pleased to announce some significant progress on a project I have been hard at work on since the beginning of the month. I have not yet posted a status update or even a broad overview of this project at all. Therefore I am writing this article to accomplish both of those goals and perhaps also include a brief tutorial.

What Is wincross Anyway?

After attempting to cross-compile a Gimp plugin for 64-bit Windows, I quickly discovered that the process was difficult, confusing, and nearly impossible to properly complete. I immediately came to the conclusion that some sort of "intermediate tool" was needed in order to ease the pain of cross-compiling libraries and applications. This tool should take care of setting up environment variables, invoking the appropriate build system with the appropriate commands, and perform some helpful utility functions as well.

One of the other conclusions I came to was that forcing a user to cross-compile all of the GTK+ dependencies (and their dependencies, etc.) in order to merely cross-compile a single GTK+ application was ridiculous. Instead, a central repository should exist that contains prebuilt packages for many common libraries. This repository should facilitate easy installation and include information about inter-package dependencies, etc.

From those conclusions, wincross was born.

How Many Packages Are Currently Available?

All of the packages are currently available in the wincross PPA, which can be added to any Ubuntu 12.04 or 12.10 machine using the following command:

sudo apt-add-repository ppa:win-cross-dev/win-cross ; sudo apt-get update

There are currently about 35 libraries packaged, all of them available for both 32 and 64-bit editions of Windows. Basic libraries, such as zlib, libpng, and libogg are included as well as entire frameworks like GTK+, wxWidgets, and Irrlicht. Each source package provides three binary packages:

  • mingw32-[name]
  • mingw64-[name]
  • mingw-[name]

The first includes development headers and static / shared libraries for 32-bit editions of Windows. The second includes equivalent files for 64-bit editions of Windows. The third package provides a convenient method of installing the first two, cutting down on the amount of typing required.

So How Does It Work?

After adding the PPA above, the first thing you will want to do is install the wincross Python module:

sudo apt-get install python-wincross

Note: this package provides both Python 2k and Python 3k files, ensuring compatibility with current and future Ubuntu releases.

Once you have wincross installed, you can begin cross-compiling applications. Let's begin by creating a simple GTK+ demo application - nothing fancy, just a single window onscreen that we can move around:

#include <gtk/gtk.h>

int main(int argc, char * argv[])
{
    /* This will point to the window we create. */
    GtkWidget * window;
    
    /* Initialize GTK+ with our command line arguments. */
    gtk_init(&argc, &argv);
    
    /* Create a toplevel window and make it visible. */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_widget_show(window);
    
    /* Quit the app when the window is closed. */
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    
    /* Run the GTK+ main loop. */
    gtk_main();
    
    return 0;
}

I'll assume the above file is saved with the filename "main.c". We also need a simple Makefile that wincross can use to compile our application:

CFLAGS = $(shell pkg-config gtk+-3.0 --cflags)
LFLAGS = $(shell pkg-config gtk+-3.0 --libs) -mwindows

simple.exe: main.o
	$(CC) main.o -o simple.exe $(LFLAGS)

main.o:
	$(CC) -c main.c $(CFLAGS)

Now that we have the source code and the Makefile, we can begin the compilation procedure. Open a terminal, change to the directory with the above two files, and run the following command:

wincross make

You will probably receive an error stating something like "Package gtk+-3.0 was not found in the pkg-config search path." This is simply telling us that we don't have the GTK+ development headers and libraries installed yet. Let's take care of that now:

sudo apt-get install mingw-gtk

Don't be alarmed if quite a few packages are listed for installation - GTK+ has a number of dependencies which must be installed in order to compile and link the application above. After the installation completes, you can rerun the "make" command and this time it should succeed.

How Do I Package My Application?

If you attempt to copy the newly created "simple.exe" executable to a Windows system and run it, you will quickly run into a problem. All of the required DLLs are missing. Thankfully, you can find nearly all of the DLLs you need in the packages you installed earlier. However, how do you know which DLLs you need? Also, isn't manually copying a bunch of DLLs tedious and error-prone?

wincross comes to the rescue here with a simple utility command:

wincross collect-dlls

Heads-up: you will need to run sudo update-dlocatedb before running the above command until a wincross bug is fixed. Running this command updates the database that wincross uses to look for DLLs.

After running that command, you should end up with a lot of DLLs in the current directory. Shipping a .zip file with your application executable and all of these files to your end-users is absurd. What would be ideal is an installation program. You probably guessed it by now: wincross does that too. Assuming you still have a terminal open to the directory with your .exe and .dll files, run the following commands:
mkdir build     # we'll put the app's files in here
mv *.exe build  # copy the executable there
mv *.dll build  # copy the DLLs there
wincross create-nsis --directory=build --name='Simple Demo' --version=1.0 >installer.nsi
makensis installer.nsi

The last two lines perform the real magic. wincross scans the directory we pointed it to ("build") and creates an NSIS installation script. Then we feed that installation script into the NSIS compiler which will generate an installer we can now distribute to our users. wincross does most of the heavy lifting when generating the installer, including guessing what our primary executable is (we only have one, "simple.exe"). If wincross is guessing wrong, you can set it straight by passing the "--primary-executable" argument.

Here is a screenshot of the DLLs and the application running on Windows 7:

What Else Can wincross Do?

Although this has been mentioned before, the steps above are nearly identical if you want to build a native 64-bit executable instead of a 32-bit one. Simply append "--architecture=64" to all of the "wincross" commands and you'll end up with a 64-bit executable instead. It's that easy.

You can explore some of wincross's other commands by typing:

wincross --help

This will give you a list of all of the supported commands. You can find out more about a specific command by typing:

wincross [command] --help

Can I Help?

Absolutely! With a project of this scale, we are always looking for more people to help with packaging, compiling, installing, and testing. Just drop me an email (using the address on the About page) or request to join the Launchpad team.


Comments

There are currently no comments posted for this item.


Leave a Comment

Please login to comment.