To demonstrate how this works, I'm going to show you how to port a simple application to Windows, using Fedora MinGW. The app I've chosen is virt-viewer, a graphical console viewer for virtual machines, written in C.
First we install the cross-compiler environment and any libraries that our program requires. (Until the MinGW packages are accepted into Fedora, you'll have to get them from our temporary yum repository)
yum install mingw32-gcc mingw32-binutils \
mingw32-gtk2 mingw32-gtk-vnc mingw32-libvirt mingw32-libxml2 \
mingw32-nsis mingw32-nsiswrapper
With software such as virt-viewer that is based on the standard autoconf "configure" script, the cross-compiling step is simple. You just have to do:
./configure --host=i686-pc-mingw32
That's all you have to do to configure virt-viewer (and most other software) to cross-compile for Windows.
Now we just do
make
and discover ... ah, that it doesn't compile. This leads us to the hard part of porting software over to Windows. Windows uses the Win32 API instead of the usual POSIX / libc API found on Linux.For virt-viewer there are several problems:
- virt-viewer uses some header files like <sys/socket.h> which aren't found under Win32.
- We need to include <windows.h> on Windows (but not on Linux). For Win32, this header file is analogous to <stdlib.h> or <unistd.h>, and almost every C source file should include it.
- virt-viewer makes some Linux-specific system calls which aren't available in the Win32 API. The problematic calls are:
Problems (1) and (2), the missing header files, are easily solved in a very portable way. For each header file which is missing on Windows or Linux, we will just add a configure-time test and some #ifdef magic. Into configure.ac we put:
AC_CHECK_HEADERS([sys/socket.h sys/un.h windows.h])
and then into the C sources files we put:
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
and so on.
Problem (3) -- missing APIs -- are the hardest problems to solve. In general there are three strategies we could try:
(a) Try to find an equivalent but different API which is present on Linux and Windows. As an example here, Windows has a call which is very similar to pipe, and might be used to replace socketpair.
(b) Write a replacement function for each problematic API.
(c) Comment out the particular feature in the code which uses the missing calls. This is less satisfactory of course: Windows users will now be missing some feature.
We're going to fix problems in (3) with a mixture of strategies (b) and (c).
Windows doesn't have usleep, but looking at MSDN I see that it does have a function Sleep (DWORD milliseconds) which can be used as a replacement for usleep.
You can test and replace functions conditionally by adding this to configure.in:
AC_REPLACE_FUNCS([usleep])
Remember that you don't want to replace this on Linux and any platforms that have usleep, and that is what AC_REPLACE_FUNCS does.
The code to implement usleep is now placed into a single function in a file with the same name,
usleep.c
:
#ifdef WIN32
int
usleep (unsigned int usecs)
{
unsigned int msecs = usecs / 1000;
if (msecs < 1)
Sleep (1);
else
Sleep (msecs);
}
#endif
The magic of autoconf will ensure this file will only be linked into the main program when it is needed.
As for
fork
and socketpair
, it turns out we are quite lucky. These two calls are only used to implement a specific virt-viewer feature, namely tunneling connections over ssh. If you conclude, as I did, that ssh isn't that common on Windows machines, then you can do as I did and just comment out that feature conditionally when building on Windows.With those changes, we have now completed our port of virt-viewer to Windows (full patch). After rerunnning:
autoconf
./configure --host=i686-pc-mingw32
make
we are left with
virt-viewer.exe
, a full Gtk application that runs on Windows.Creating a Windows installer
To package up Windows applications into full-featured installers, that include menu shortcuts, desktop icons and an uninstaller, we wrote a little helper program called nsiswrapper. As its name suggests, it is a wrapper around the NSIS Windows Installer, which we also ported over to run natively under Fedora.
You'll need to wrap up not just
virt-viewer.exe
, but the Gtk-related DLLs and helper modules. With nsiswrapper you would do:
nsiswrapper --run \
--name "Virt-Viewer" \
--outfile "Virt-Viewer-for-Windows.exe" \
--with-gtk \
/usr/i686-pc-mingw32/sys-root/mingw/bin/virt-viewer.exe
9 comments:
Wouldn't it be safer and simpler to always round up in usleep?
int
usleep (unsigned int usecs)
{
Sleep ((usecs + 999) / 1000);
}
Kevin, yes it would be.
I see that Autoconf is used but does anyone know whether this would be possible with cmake or scons too?
cmake can do it, at least according to this page on their wiki.
No idea about scons though. I'd never heard of it until I had to port NSIS over (which uses scons), and I found it pretty baffling. The scons script included with NSIS cross-compiled after I applied a small patch, but I don't know if that was because of scons or hard work by NSIS contributors.
hi, i know this is not the best place for configuration question but
I just tried you packages on F10 compiling poco (www.pocoproject.org)
and it it seems that my include directories are wrong ?
[andrzej@linx poco-1.3.3p1]$ make
make -C /home/andrzej/poco/poco-1.3.3p1/Foundation
make[1]: Entering directory `/home/andrzej/poco/poco-1.3.3p1/Foundation'
** Compiling src/Environment.cpp (debug)
i686-pc-mingw32-g++ -Iinclude -I/home/andrzej/poco/poco-1.3.3p1/CppUnit/include -I/home/andrzej/poco/poco-1.3.3p1/Foundation/include -I/home/andrzej/poco/poco-1.3.3p1/XML/include -I/home/andrzej/poco/poco-1.3.3p1/Util/include -I/home/andrzej/poco/poco-1.3.3p1/Net/include -DPOCO_BUILD_HOST=linx -v -mno-cygwin -D_WIN32 -DMINGW32 -DWINVER=0x500 -DPOCO_NO_FPENVIRONMENT -DPCRE_STATIC -DPOCO_THREAD_STACK_SIZE -DFoundation_Config_INCLUDED -I/usr/local/include -I/usr/include -g -D_DEBUG -c src/Environment.cpp -o /home/andrzej/poco/poco-1.3.3p1/Foundation/obj/MinGW/ia32/debug_static/Environment.o
Using built-in specs.
Target: i686-pc-mingw32
Configured with: ../configure --prefix=/usr --bindir=/usr/bin --includedir=/usr/include --libdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --datadir=/usr/share --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=i686-pc-mingw32 --with-gnu-as --with-gnu-ld --verbose --without-newlib --disable-multilib --with-system-zlib --disable-nls --without-included-gettext --disable-win32-registry --enable-version-specific-runtime-libs --with-sysroot=/usr/i686-pc-mingw32/sys-root --enable-languages=c,c++
Thread model: win32
gcc version 4.3.2 (GCC)
COLLECT_GCC_OPTIONS='-Iinclude' '-I/home/andrzej/poco/poco-1.3.3p1/CppUnit/include' '-I/home/andrzej/poco/poco-1.3.3p1/Foundation/include' '-I/home/andrzej/poco/poco-1.3.3p1/XML/include' '-I/home/andrzej/poco/poco-1.3.3p1/Util/include' '-I/home/andrzej/poco/poco-1.3.3p1/Net/include' '-DPOCO_BUILD_HOST=linx' '-v' '-mno-cygwin' '-D_WIN32' '-DMINGW32' '-DWINVER=0x500' '-DPOCO_NO_FPENVIRONMENT' '-DPCRE_STATIC' '-DPOCO_THREAD_STACK_SIZE' '-DFoundation_Config_INCLUDED' '-I/usr/local/include' '-I/usr/include' '-g' '-D_DEBUG' '-c' '-o' '/home/andrzej/poco/poco-1.3.3p1/Foundation/obj/MinGW/ia32/debug_static/Environment.o' '-mtune=generic'
/usr/libexec/gcc/i686-pc-mingw32/4.3.2/cc1plus -quiet -v -Iinclude -I/home/andrzej/poco/poco-1.3.3p1/CppUnit/include -I/home/andrzej/poco/poco-1.3.3p1/Foundation/include -I/home/andrzej/poco/poco-1.3.3p1/XML/include -I/home/andrzej/poco/poco-1.3.3p1/Util/include -I/home/andrzej/poco/poco-1.3.3p1/Net/include -I/usr/local/include -I/usr/include -DPOCO_BUILD_HOST=linx -D_WIN32 -DMINGW32 -DWINVER=0x500 -DPOCO_NO_FPENVIRONMENT -DPCRE_STATIC -DPOCO_THREAD_STACK_SIZE -DFoundation_Config_INCLUDED -D_DEBUG src/Environment.cpp -quiet -dumpbase Environment.cpp -mno-cygwin -mtune=generic -auxbase-strip /home/andrzej/poco/poco-1.3.3p1/Foundation/obj/MinGW/ia32/debug_static/Environment.o -g -version -o /tmp/cck0eCDn.s
ignoring nonexistent directory "/usr/i686-pc-mingw32/sys-root/usr/local/include"
ignoring nonexistent directory "/usr/lib/gcc/i686-pc-mingw32/4.3.2/../../../../i686-pc-mingw32/include"
ignoring duplicate directory "/home/andrzej/poco/poco-1.3.3p1/Foundation/include"
#include "..." search starts here:
#include <...> search starts here:
include
/home/andrzej/poco/poco-1.3.3p1/CppUnit/include
/home/andrzej/poco/poco-1.3.3p1/XML/include
/home/andrzej/poco/poco-1.3.3p1/Util/include
/home/andrzej/poco/poco-1.3.3p1/Net/include
/usr/local/include
/usr/include
/usr/lib/gcc/i686-pc-mingw32/4.3.2/include/c++
/usr/lib/gcc/i686-pc-mingw32/4.3.2/include/c++/i686-pc-mingw32
/usr/lib/gcc/i686-pc-mingw32/4.3.2/include/c++/backward
/usr/lib/gcc/i686-pc-mingw32/4.3.2/include
/usr/lib/gcc/i686-pc-mingw32/4.3.2/include-fixed
/usr/i686-pc-mingw32/sys-root/mingw/include
End of search list.
GNU C++ (GCC) version 4.3.2 (i686-pc-mingw32)
compiled by GNU C version 4.3.0 20080428 (Red Hat 4.3.0-8), GMP version 4.2.2, MPFR version 2.3.0-p2.
warning: MPFR header version 2.3.0-p2 differs from library version 2.3.2.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: ae26091e2341bb99ed135a76888b4e34
In file included from src/Environment.cpp:48:
src/Environment_WIN32.cpp: In static member function 'static void Poco::EnvironmentImpl::nodeIdImpl(Poco::UInt8 (&)[6])':
src/Environment_WIN32.cpp:176: error: 'memcpy' is not a member of 'std'
make[1]: *** [/home/andrzej/poco/poco-1.3.3p1/Foundation/obj/MinGW/ia32/debug_static/Environment.o] Error 1
make[1]: Leaving directory `/home/andrzej/poco/poco-1.3.3p1/Foundation'
make: *** [Foundation-libexec] Error 2
[andrzej@linx poco-1.3.3p1]$
This isn't really the place for support. Post a message on the fedora-mingw mailing list.
Answered here:
http://lists.fedoraproject.org/pipermail/fedora-mingw/2008-November/000015.html
since afaics virt-viewer uses gtk and thus glib, you should check waht glib provides more carefully, since it has many utilities for cross platform stuff.
In particular for your case, it provides g_usleep() which would save you some code.
Yes thanks pbor, that's a better solution.
Post a Comment