Software Engineering with Wine

Contents

Introduction

This document describes two projects suitable for use in an undergraduate Software Engineering course, designed to give students a modicum of real-world experience.

See also the presentation slides given at the beginning of UCLA's CS130.

The Wine Project

The projects are centered around the Wine Project, an ambitious effort to create a clean-room, open source, and free reimplementation of the Win32 API on top of the Unix API. The Wine developers use publically available Microsoft documentation, together with the observed behavior of Windows, to implement each Windows API call and a compliance test for those calls. The compliance test suite is crucial, as without it, adding features to or even fixing bugs in Wine without breaking it would be extremely difficult.

Wine released version 1.0 in the summer of 2008, and is developing rapidly. There is still plenty of room for a motivated student to make his or her mark.

Documentation

www.winehq.org has a fair amount of documentation. You should at least have a look at the following:

Setting Up a Wine Development System

  1. Install a fairly recent mainstream, e.g. Ubuntu 8.10. Students with 64 bit computers should install the 64 bit version of Linux so they have the option of working on the 64 bit port project. (Students with Windows already installed may wish to try the Wubi installer, which installs Ubuntu as if it were a Windows application.)
  2. Install the packages needed to build wine, using the commands
    wget http://winezeug.googlecode.com/svn/trunk/install-wine-deps.sh
    sudo sh install-wine-deps.sh
    
    (see RecommendedPackages).
  3. (64 bit systems only) Build gcc. See wiki.winehq.org/Wine64 for the exact commands.
  4. Get the Wine source tree as described at wiki.winehq.org/GitWine:
    git clone git://source.winehq.org/git/wine.git wine-git
    
    This creates a Wine source tree in a new directory named wine-git.
  5. Build Wine. To build 32 bit wine, simply do "./configure; make" as usual in the Wine source tree.

    To build 64 bit wine, follow the instructions at wiki.winehq.org/Wine64. e.g.

    cd wine-git
    wget -O segv.patch 'http://repo.or.cz/w/wine/wine64.git?a=commitdiff_plain;h=e5146a44451b36062f735b14591479629234c81c'
    patch -p1 < segv.patch
    cd ..
    mkdir wine64
    cd wine64
    ../wine-git/configure --enable-win64 CC=/usr/local/gcc/bin/gcc
    make > make.log 2>&1
    
    (Note: it's easier to build and test inside the source tree, but that gets in the way of testing both 32 and 64 bit builds from the same source tree. People working on the 64 bit port will probably want to build out-of-tree as describe above.)
  6. Try running some of the programs that come with Wine, e.g.
    cd ~/wine-git (or ~/wine64)
    ./wine programs/cmd/cmd.exe.so
    

Running Wine's Test Suite

Once you have built Wine, it's time to run the conformance test suite. See the instructions at www.winehq.org/docs/winedev-guide/testing-wine. For example, if you're building inside the source tree:
cd ~/wine-git
make -k test  > log 2>&1
(The -k makes it continue past failing tests; the "2>&1 log" redirects both stdout and stderr to a file named "log".) This should take about five minutes. If a test hangs, you may need to kill the process or wineserver from another window.)

To see a list of failures, just look for lines with "Test failed" in them, e.g.

grep "Test failed" log | more
You can get a count of failures with wc:
grep "Test failed" log | wc
You shouldn't see more than ten or so errors in 32 bit Wine. 64 bit wine has lots and lots and lots of failures still.

How To Submit Changes To Wine

Once you have made a change to Wine or its test suite that you're happy with, create a patch (see here and here for how), and make sure the patch applies cleanly to a fresh checkout of the Wine sources, and still builds and runs properly. If you used git to retrieve the sources, you should be able to use 'git diff > my.patch' to create a patch.

Once your patch works, add a changelog entry at the top, giving your name and the license (LGPL), and saying very briefly what it does. Then have a friend review the patch for errors, and clean up anything they found confusing or wrong.

If you're a student working in a structured project, send it to your project leader for review, and clean up any issues they find.

Finally, post it to the wine-patches mailing list, and watch for replies on the wine-devel mailing list.

If the patch isn't accepted right away, don't worry, just address any feedback you're given, and resubmit it once a week or so. Ask on wine-devel if you're unsure what's happening. Continue resubmitting until it makes it in. (Sometimes the Wine maintainer's mailbox overflows, so don't expect approval to be quick or easy.)

Mailing list

The mailing list ucla-cs130-wine is set up for students currently enrolled in the class. Please use this to ask questions about the project or run ideas past the coordinator or other students.

Chat room

I've set up a chat room for this project using IRC; it's at irc://irc.freenode.net/#ucla-cs130-wine

My favorite way to access IRC is with the Chatzilla plugin to Firefox (Tools / Addons / Get Addons, search for IRC). Then you can just click on the above link, and/or add it to your bookmarks.

Sometimes I use IRCII (sudo apt-get install ircii; irc -c '#ucla-cs130-wine' $USER irc.freenode.net) That's handy when I need to use irc without X (e.g., if my ISP is blocking IRC but not ssh, I can use irc at a remote computer via ssh).

Project: 64 bit port

Wine just recently started working in 64 bit mode, but it still has lots of problems. For instance, Notepad starts fine, but crashes when you try to load a file, and about half of the conformance tests fail. The goal of this project is to focus on one or two libraries or programs in Wine, and get them to pass all their tests on 64 bits. This will involve both fixing compiler warnings (e.g. "warning: cast from pointer to int of different size") as well as more subtle problems.

Almost any library would be fine. Four good candidates are gdiplus, msvcrt, oleaut32, and ws2_32. (ntdll, kernel32, and gdi32, and generated.c, would be good except that they're so important that hotshot wine developers will probably get to them before you do.)

See discussions on wine-devel for more info.

Your coordinator will have more information about this project at the first meeting, or feel free to ask questions via email on the project mailing list.

Here's a quick stream-of-consciousness account of looking at a win64 problem in ws2_32.

Looking at "make test" in dlls/ws2_32/tests, the first failure is

sock.c:415: Test failed: simple_server (17): failed to set blocking mode: 10022
To learn more, I figured out which debug channel this file used by doing
grep WINE_DEFAULT_DEBUG_CHANNEL dlls/ws2_32/*.c
This pulled up
WINE_DEFAULT_DEBUG_CHANNEL(winsock);
So I reran the test like this:
rm *.ok
WINEDEBUG=+relay,+winsock make test > log.txt 2>&1
and now I can see the function calls being executed by looking in log.txt. Comparing the log.txt from 32 and 64 bit runs, I see a key difference. On 32 bits:
trace:winsock:WS_ioctlsocket socket 003c, cmd 8004667e, ptr 0x7eb3ba18
but on 64 bits:
trace:winsock:WS_ioctlsocket socket 0030, cmd 8008667e, ptr 0x404e8638
warn:winsock:WS_ioctlsocket     unknown WS_IOCTL cmd (8008667e)
Hmm. cmd has a slightly different value in 64 bits, one of the bits is shifted (8004667e vs. 8008667e). The source line in question, ws2_32/tests/sock.c line 415, says
wsa_ok ( set_blocking ( mem->s, TRUE ), 0 ==, "simple_server (%x): failed to set blocking mode: %d\n");
set_blocking is a function defined higher up in that file, containing the line
return ioctlsocket ( s, FIONBIO, &val );
That constant FIONBIO is defined in include/winsock.h:
#define FIONBIO                    _IOW('f', 126, u_long)
And _IOW is in turn defined as
#define _IOW(x,y,t) (IOC_IN|(((UINT)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))
The change in the value of FIONBIO is because sizeof(u_long) is 8. Now, long is supposed to be 4 bytes on win64; see msdn.microsoft.com/en-us/library/94z15h2c.aspx and blogs.msdn.com/oldnewthing/archive/2005/01/31/363790.aspx. It turns out that, rather than redefine long, gcc has chosen to require win64 apps to use the type LONG instead. So include/winsock.h probably needs to change
#define FIONBIO                    _IOW('f', 126, u_long)
to
#define FIONBIO                    _IOW('f', 126, ULONG)
BTW, it's worth reading through some of the earlier win64 patches to this file 1, 2, or especially 3. (Perhaps one of them should have caught this, but nobody's perfect.)

I'm still not sure why the switch's case for FIONBIO doesn't match; the constant should have been the same in both the test and the implementation, since it came from the same file, winsock.h. That's the next mystery to probe...

Project: Implement dxdiag

dxdiag is a handy little app that comes with Microsoft DirectX; gamers use it to get information about their 3d graphics card and to test to make sure it's working ok. The project here is to both get Microsoft's dxdiag working a little better on Wine, and to create an open source clone of dxdiag to bundle with Wine.

To try the native (Microsoft) version of dxdiag, do

$ wget http://kegel.com/wine/winetricks
$ sh winetricks directx9
$ wine dxdiag
Related links:

Your coordinator will have more information about this project at the first meeting, or feel free to ask questions via email on the project mailing list.