Cross-Compiling Under Linux

From WxWiki
Revision as of 19:59, 23 March 2006 by Viktor (talk | contribs)
Jump to navigation Jump to search

Cross-compiling under Linux

  • Install The Mingw Cross-Compiler.
  • Compile wxWidgets
    • Download wxWidgets source
    • Compile with ./configure --prefix=/usr/local/i386-mingw32 --host=i386-mingw32 --target=i386-mingw32 --with-msw --your_optional_switches
    make
    make install

See also:

Note: The SDL scripts and these directions cannot be mixed. Note: By disabling threads (with --disable-threads), you can avoid a dependency on the ming dll

Example usage

Once installed, save the following file as winhello.c (stolen from Installing and Using the MinGW Cross-Compiler on Mac OS X:

/*
 * Hello, World for Win32
 * gcc winhello.c -o winhello.exe
 */

#include <windows.h>
int main(int argc, char *argv[])
{
	MessageBox(NULL, "Hello, world!", "Hello, world!", MB_OK);
	return 0;
}

To build the example, execute the following command:

 $ i386-mingw32-gcc winhello.c -o winhello.exe

and run it for example with wine wine winhello.exe .

Contrib libraries

Couldn't compile the contrib directory with the wxMSW 2.4.2 sources, use the latest cvs.

Flags

You might need these flags when compiling:

-Wl,--subsystem,windows -mwindows -DWINVER=0x0400 -D__WIN95__ -D__GNUWIN32__ -DSTRICT -DHAVE_W32API_H -D__WXMSW__ -D__WINDOWS__

And these while linking:

-lregex -lpng -ljpeg -lzlib -ltiff -lstdc++ -lgcc -lodbc32 -lwsock32 -lwinspool -lwinmm -lshell32 -lcomctl32 -lctl3d32 -lodbc32 -ladvapi32 -lodbc32 -lwsock32 -lopengl32 -lglu32 -lole32 -loleaut32 -luuid

environment variables

In order to use the cross-compiler tools you need to replace the normal tools in makefiles. This is easier to do just exporting some environment variables before running configure/make:

  export CC=i586-mingw32msvc-gcc
  export CXX=i586-mingw32msvc-c++
  export LD=i586-mingw32msvc-ld
  export AR=i586-mingw32msvc-ar
  export AS=i586-mingw32msvc-as
  export NM=i586-mingw32msvc-nm
  export STRIP=i586-mingw32msvc-strip
  export RANLIB=i586-mingw32msvc-ranlib
  export DLLTOOL=i586-mingw32msvc-dlltool
  export OBJDUMP=i586-mingw32msvc-objdump
  export RESCOMP=i586-mingw32msvc-windres

SDL's Script

See also: BuildCVS.txt in the tar of the SDL scripts

http://www.libsdl.org/extras/win32/cross/ contains scripts that automate the compiler build process described above.

Download build-cross.sh, cross-configure.sh, and cross-make.sh.

Run the script build-cross.sh.

Download the CVS version wxAll and uncompress it.

Copy cross-configure.sh and cross-make.sh to the wxWidgets-2.5.2 directory.

Run cross-configure.sh and cross-make.sh and you should be done. :-)

Autoconf supports cross-compilation natively

If your cross-suite is i586-mingw32msvc-{gcc,g++,ld,...}, just do ../configure --with-msw --target=i586-mingw32msvc --host=i586-mingw32msvc --build=i386-linux and all necessary tools will be prefixed automatically.

ATTENTION: Turn off binfmt support before running configure (Debian: /etc/init.d/binfmt-support stop), which invokes wine for .exe files; otherwise configure will think it does NOT use a cross-compiler.

Autoconf/Automake unit testing suites

(maybe this section should go somewhere else?)

It is possible to autotest your code using wine (you are using unit tests, right?). This makes it very easy to script code under Unix to build multiple platforms, then test, without intervention. This section focusses on testing console-able objects.

First familiarise yourself with building test binaries with autoconf and automake. I recommend cppunit (for C++ systems). There's plentiful documentation on cppunit's website on integrating cppunit with Makefile.am. One show-stopping step is the ability to test msw binaries in the same way (make check) one tests unix binaries.

To take advantage of wine (running your tests automatically with wine), first make sure that wine may run headless. If you have access to a graphical terminal then this isn't important (if you're Ok with having wine spout gobbledygock to a window with every run). Make sure your test-directory Makefile.am's have all TESTS tokens suffixed with $(EXEEXT):

TESTS = TestFoo$(EXEEXT)

check_PROGRAMS = TestFoo

...and so on.

Next add a configure.ac (you have upgraded to using .ac instead of .in, right?) line manipulating the macro TESTS_ENVIRONMENT:

AC_SUBST([TESTS_ENVIRONMENT], [$WINE])

In this I assume that WINE has been set with AC_CHECK_PROGS or something (even `WINE = wine'). This will have all tests run in the following format:

$(TESTS_ENVIRONMENT) $${dir}$$tst

Where dir is the path and tst is the test name (remember that EXEEXT). That's it: wine will return the exit code of your running binary. You can also put a special shell or other token in there, but that exceeds the focus of this documentation. This assumed automake-1.9 and autoconf-2.57 but I'm fairly certain it works in earlier versions of both (uncertain about autoconf-2.13 style).


Some more details for Debian folks

After apt-getting the three packages mingw32, mingw32-binutils and mingw32-runtime from "unstable" as well as downloading the wxWidgets source (I took the "2.6.2 all ports combined", but MSW should be enough), use the --host option of the configure script (see "Autoconf supports cross-compilation natively" above) for auto-magic!

If that doesn't work: I found out that I had to set the environment variables mentioned above ("Flags"), however I needed "export CFLAGS=" as well:

export CC=i586-mingw32msvc-gcc
export CXX=i586-mingw32msvc-g++
export LD=i586-mingw32msvc-ld 
export AR=i586-mingw32msvc-ar
export AS=i586-mingw32msvc-as
export NM=i586-mingw32msvc-nm
export STRIP=i586-mingw32msvc-strip
export RANLIB=i586-mingw32msvc-ranlib
export DLLTOOL=i586-mingw32msvc-dlltool
export OBJDUMP=i586-mingw32msvc-objdump
export RESCOMP=i586-mingw32msvc-windres
export CFLAGS=

If you save that in a file, say, don't forget that you shouldn't execute, but source it! Then

./configure --prefix=/usr/local/i586-mingw32 --host=i586-mingw32msvc --target=i586-mingw32msvc \
       --with-msw [--your_optional_switches]
make
make install

(or sudo make install, depending what rights you have on /usr/local/i586-mingw32).

Your wxMSW libraries will be created in the directory you specified with --prefix, here it's /usr/local/i586-mingw32

To test your mingw32 installation with a sample not using wxWidgets, look above ("Example usage").

To test your mingw32 installation with a real wxWidgets example, take minimal.cpp from the official examples. Fortunately, I didn't have to fiddle around with the flags myself, I use wx-config for that - not the system-wide one, but the one compiled with the cross-Windows libraries below /usr/local/i586-mingw32!

i586-mingw32msvc-g++ -c -o minimal.o minimal.cpp \ 
  `/usr/local/i586-mingw32/bin/wx-config --cxxflags`
i586-mingw32msvc-g++ -o minimal.exe minimal.o \
  `/usr/local/i586-mingw32/bin/wx-config --libs`

Attention, there are are two caveats here that could cost you lots of time (it did cost me lots of time, hope I'll save yours ;-)

  • When compiling, be sure to include the -c option. -o with an .o object file isn't enough, mingw32 will try to link!
  • When linking, be sure to include first your object files and then the libraries (given by wx-config). When compiling, the order isn't too important, but if you exchange libraries and object files at the linking stage, you'll get lots of undefined references. In fact, mingw32 shows exactly the same behaviour as if you hadn't specified any libraries at all! I don't know if this is a bug, but according to the Debian Bug Report #254185 it seems to be OK.

Finally, when executing your program with wine, qemu (works great!) or even on a real Windows box, don't forget that even if you linked everything statically, you'll also need mingwm10.dll in addition to your executable. Put in in the same directory and execute the binary from there, and everything works. I found mingwm10.dll gzipped in /usr/share/doc/mingw32-runtime/