Showing posts with label gtk. Show all posts
Showing posts with label gtk. Show all posts

Sunday, 7 December 2008

Slashdot groupthink

This may be the first time a comment of mine has been modded down to -1 on Slashdot. I'm questioning whether the inefficiency of glib outweighs the speed advantage of C. Very few of the replies get it. Perhaps this proves the people only read the first sentence of any posting ... tl;dr.

Monday, 24 November 2008

Common mistakes cross-compiling MinGW packages

Using the headers from /usr/include

The headers in /usr/include are for the native libraries installed on the system, and it's highly unlikely they will work for cross-compilation. By "won't work" I mean that types and structure fields could be different, resulting in a segfault.

The Fedora MinGW project takes two steps to avoid using native libraries by accident: Firstly GCC is configured so it looks in /usr/i686-pc-mingw32/sys-root/mingw/include and never looks in /usr/include (as long as you don't tell it to). Secondly we supply a replacement %{_mingw32_configure} RPM macro which sets PKG_CONFIG_PATH, so any pkg-config done will pick up the cross-compiled libraries' configuration instead of any native libraries' configuration.

$ PKG_CONFIG_PATH=/usr/i686-pc-mingw32/sys-root/mingw/lib/pkgconfig \
pkg-config --cflags glib-2.0
-mms-bitfields -I/usr/i686-pc-mingw32/sys-root/mingw/include/glib-2.0
-I/usr/i686-pc-mingw32/sys-root/mingw/lib/glib-2.0/include

One thing that can still go wrong is that you don't have the cross-compiled library installed and it then picks up the native library. For example, you missed a BuildRequires line. That mistake usually becomes evident when the program tries to link, because linking a cross-compiled Windows binary to a native Fedora library won't work.

Not setting --prefix

You likely don't want to install Windows binaries and libraries under /usr or /usr/local. For a start it's better to keep Windows things in one place, and the packaging guidelines have specified that place to be /usr/i686-pc-mingw32/sys-root/mingw. But mainly it's not a good idea to mix up native and cross-compiled libraries, which will cause all sorts of problems as in the point above.

If you use %{_mingw32_configure} in RPM specfiles, or the mingw32-configure command, then paths will be set correctly for you.

Not using a portability library

If you're writing the program yourself, or if you're doing the often difficult work of porting an existing application, use a portability library to help you. Which you choose is up to you and depends on many factors, but we would recommend that you look at these ones:

Writing your own build system

While it's fashionable to dislike autoconf and m4 macros, it is still by far the easiest way to both build your program on multiple systems, and to cross-compile. So use autotools or cmake, and definitely don't write your own build system. Discourage other projects from writing their own build systems too.

This really comes down to bitter experience. Every project we have had to port that has used its own build system has been far more of a headache than those that just used autoconf or cmake.

Running programs during the build process

When cross-compiling, it's always a mistake to run programs during essential build steps. The problem is that you can't be sure that binaries can be made to work in the build environment. For Windows binaries, there is some chance of running them under Wine, but Wine itself is incompatible with autobuild environments like mock and Koji. Furthermore Wine only works on x86 platforms, and it's not possible to use it at all when cross-compiling from other architectures like PPC.

Running programs during make test is normal and useful though.

Friday, 10 October 2008

MinGW: Compile software for Windows without leaving your Fedora machine

For the last few weeks I've been focused on the Fedora MinGW project. This project gives Fedora users a compelling new feature: you can build your software for Windows, without ever needing to leave the Fedora / Linux environment. In fact you can do everything, up to and including creating a Windows installer for your customers, without needing once to touch Windows.

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:

  1. virt-viewer uses some header files like <sys/socket.h> which aren't found under Win32.
  2. 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.
  3. virt-viewer makes some Linux-specific system calls which aren't available in the Win32 API. The problematic calls are:

    • usleep (sleep for a specified number of microseconds)
    • fork (create a subprocess)
    • socketpair (create a pipe to communicate with the subprocess)

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

Tuesday, 19 August 2008

Just draw something on the f-ing screen

I don't believe that computers have got better over the past 40 years.

Case in point: I've spent at least 2 hours trying to debug a Gtk program which is supposed to plot some dots on the screen. Like this sort of thing in barely remembered ZX Spectrum BASIC:

10 FOR F = 0 TO 2*PI STEP 0.1
20 PLOT SIN(F)*200+100, COS(F)*200+100
30 NEXT F

The Gtk program is 20 times longer than this. And refuses to draw anything except a black window.

Computers have got worse in many ways since my first computer.

Update

My angry late-night programming rant makes it to reddit.


Ob-awesome Wikipedia page of the week: List of 8 bit computer hardware palettes.