I am giving a talk and demonstration in London (UK) this Saturday afternoon, 31st January on the subject of the Fedora MinGW (Windows cross-compiler) project. Free entry, everyone is invited!
Previous MinGW postings on this blog ...
Showing posts with label computing. Show all posts
Showing posts with label computing. Show all posts
Thursday, 29 January 2009
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.
Sunday, 2 November 2008
malloc failures
I can't put a comment on Debarshi's post, so I'll answer here. Debarshi complains about this comment by the "inimitable" Jeff Johnson:
Another problem is that only about 1 in 10 memory allocations in a typical C program are mallocs. The rest are stack-allocated variables, and those aren't usually checked at all. If any of your 9 out of 10 stack allocations fail, your whole program fails hard.
This is the correct way to deal with those 1 in 10 memory allocations that you can check — provide a custom abort function that the main program can override in the very rare case that they can do anything useful other than exit:
Really the answer is to use a sensible programming language though. Programming languages invented before C had safer, faster memory allocation, dealt with 10 out of 10 memory allocation errors, and provided a mechanism to recover correctly. Those languages are now 30 years more advanced. In 2008 we're having these silly arguments about how to deal with malloc failures. That's a failure of ourselves as programmers.
You have to look at the usage case, malloc returning NULL is a "can't happen" condition where an exit call is arguably justified.
Returning an error from library to application when malloc returns NULL assumes:
1) error return paths exist [...]
2) applications are prepared to do something meaningful with the error
Another problem is that only about 1 in 10 memory allocations in a typical C program are mallocs. The rest are stack-allocated variables, and those aren't usually checked at all. If any of your 9 out of 10 stack allocations fail, your whole program fails hard.
This is the correct way to deal with those 1 in 10 memory allocations that you can check — provide a custom abort function that the main program can override in the very rare case that they can do anything useful other than exit:
Note that the main program can use longjmp (or exceptions in some cases) to "return" back to a safe point in the program, such as a transaction checkpoint. If the main program uses pool allocators — about the only safe and sensible way to deal with C's programming model — then the program has a chance of recovering.
void (*custom_abort) () = abort;
void
lib_set_custom_abort (void (*new_abort) ())
{
custom_abort = new_abort;
}
void *
lib_malloc (int n)
{
void *data = malloc (n);
if (data == NULL) custom_abort ();
return data;
}
Really the answer is to use a sensible programming language though. Programming languages invented before C had safer, faster memory allocation, dealt with 10 out of 10 memory allocation errors, and provided a mechanism to recover correctly. Those languages are now 30 years more advanced. In 2008 we're having these silly arguments about how to deal with malloc failures. That's a failure of ourselves as programmers.
Sunday, 12 October 2008
IDN use and abuse
JWZ blogged about the Unicode snowman. If you're running a proper browser, take a close look at the domain name:
☃.net
A brief, two sentence overview: For any domain name which begins with
I was quite excited for a while since many of these Unicode dingbats and symbols are unregistered in combinations of two or more, but then I found that the killjoys at the IETF had put a stop to that with RFC 4690. So while the snowman registration can be continued, no new dingbats can be registered.
Nevertheless, we can still have fun abusing the simpler Chinese characters. For a laugh I registered 丄.com and 丿乀.com. These might not be active when you read this, and to be honest I'm not quite sure where I'll point them at the moment. The first looks like
Someone should do the world a favour and register 丅丨丅.com (
☃.net
A brief, two sentence overview: For any domain name which begins with
xn-- followed by some gobbledygook, certain clients like web browsers can interpret the gobbledygook as a Punycode representation of some Unicode string. So the snowman's real domain name is xn--n3h.net.I was quite excited for a while since many of these Unicode dingbats and symbols are unregistered in combinations of two or more, but then I found that the killjoys at the IETF had put a stop to that with RFC 4690. So while the snowman registration can be continued, no new dingbats can be registered.
Nevertheless, we can still have fun abusing the simpler Chinese characters. For a laugh I registered 丄.com and 丿乀.com. These might not be active when you read this, and to be honest I'm not quite sure where I'll point them at the moment. The first looks like
bottom, the symbol for non-terminating programs. Hmmm maybe that'd be good for some insightful blog about functional programming? The second is a total abuse of two characters together, but looks like the number 8 in Japanese (IETF rules forbid registering actual numbers, even non-Arabic ones).
Someone should do the world a favour and register 丅丨丅.com (
xn--9gqa8h.com).Update
Subdomains are of course not regulated by the IETF jobsworths. Here's another, prettier unicode snowman: http://☃.earthlingsoft.net/, and I can have http://☆☆☆.annexia.org/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)
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:
That's all you have to do to configure virt-viewer (and most other software) to cross-compile for Windows.
Now we just do
For virt-viewer there are several problems:
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:
and then into the C sources files we put:
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:
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,
The magic of autoconf will ensure this file will only be linked into the main program when it is needed.
As for
With those changes, we have now completed our port of virt-viewer to Windows (full patch). After rerunnning:
we are left with
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
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
Tuesday, 16 September 2008
Tip: Read all lines from a file (the most common OCaml newbie question?)
Is this the most common OCaml beginners question? It comes up every few weeks on the OCaml beginners list, and I have tried to answer it before.
It seems that everyone who learns OCaml comes away with the impression that functional programming is the New Cool Thing, and imperative programming is Bad and Must Be Avoided.
I'm going to say it now: programming fashions are stupid and counterproductive. The only things that matter are that your program is short, easy to write, easy to maintain and works correctly. How you achieve this has nothing to do with programming fads.
Reading all lines from a file is an imperative problem, and the shortest solution (easy to write, easy to maintain and correct1) uses a while loop, in OCaml or any other language:
1This is only strictly speaking correct if you handle clean-up if
It seems that everyone who learns OCaml comes away with the impression that functional programming is the New Cool Thing, and imperative programming is Bad and Must Be Avoided.
I'm going to say it now: programming fashions are stupid and counterproductive. The only things that matter are that your program is short, easy to write, easy to maintain and works correctly. How you achieve this has nothing to do with programming fads.
Reading all lines from a file is an imperative problem, and the shortest solution (easy to write, easy to maintain and correct1) uses a while loop, in OCaml or any other language:
let lines = ref [] inActually, no, I'm lying. The best solution is this:
let chan = open_in filename in
try
while true; do
lines := input_line chan :: !lines
done; []
with End_of_file ->
close_in chan;
List.rev !lines
Std.input_list chanwhich is supplied by extlib. Don't bother to duplicate functions which are already provided in commonly available libraries.
1This is only strictly speaking correct if you handle clean-up if
input_line throws some read error (exception). In the common case where you just exit the program, leaving the channel open is perfectly acceptable.
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:
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.
Ob-awesome Wikipedia page of the week: List of 8 bit computer hardware palettes.
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.
Subscribe to:
Posts (Atom)