Software Engineering with Wine

[ Retrieved from archive.org from its 18 Nov 2005 copy of kegel.com/wine/sweng, postmortem added.]

Contents

Introduction

This document describes a series of projects suitable for use in an undergraduate Software Engineering course, designed to give students a modicum of experience in the following areas:

Mailing list

The mailing list wine-test-devel@yahoogroups.com is set up for discussing these projects. Anyone working on these is welcome to join.

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.

The Wine source code is made available under the terms of the Lesser GNU Public License, or LGPL. Each person who contributes improvements to Wine or its test suite agrees to also license their improvements under the LGPL. This helps ensure that enhancements to Wine are contributed back to the main Wine source tree and remain free for all users.

Wine can be installed on any Pentium-compatible computer that runs Linux, and is able to run Microsoft Office and many other important applications designed for Windows, but as of 2004 is still neither complete nor well polished. In particular, many APIs still lack compliance tests, and even when tests exist, they do not exercize all paths within the code that implement those APIs.

Many companies and governments are currently planning to start using Linux on the desktop, but have many legacy Windows applications that are not yet available for Linux. The Wine project could be an important part of these organizations' transition plans. For instance, Munich is converting about 14000 computers from Windows to Linux by 2008, and will use VMWare, Terminal Servers, or Wine when Linux versions of applications are unavailable.

By contributing improvements to the Wine compliance test suite, students will help reduce software costs for organizations around the world.

Working Environment

This document will assume that students are logged in to a Linux system unless otherwise specified. The Linux system should have the full suite of GNU developer tools (gcc, binutils, etc.) as well as CVS installed. It will also assume that the students have access to a Windows 2000 and/or XP system (either by rebooting, or on a separate computer).

The students will need physical access to computers with both Linux and Microsoft Windows. If the school does not provide a lab set up with such computers, the instructor may have to provide the students with Linux CD-ROMs and have them spend the first project setting up their own computers. This should be coordinated with the school's Linux User Group, which may be able to host an Installfest to assist the students.

The students will also need reasonably fast Internet connections. This document will assume everyone has cable modem, DSL, or T1 access. (Students without fast access can also participate, though the procedures will be a bit different, and will not be covered here.)

Teams

If you want to work in a team, a two-person team might be a good choice. Initially, one person can be the Linux person, and one person can specialize in Windows. The Linux person might do projects 0, 1, and 2 (getting and building Wine, and learning how to run its test suite) at the same time the Windows person is busy doing step 3 (writing a new conformance test for a Windows DLL). Once projects 0, 1, and 2 are done, the Linux person could pitch in and help write the conformance test.

Project 0: Install Linux and Windows

If you don't already have both Linux and Windows installed, install the one you're missing now (not neccessarily on the same box).

Project 1: Get and Build Wine

Visit the web site www.winehq.org and browse through its documentation and mailing list archives to become familiar with the project.

Assuming one has a reasonably fast Internet connection, the best way to get set up to make contributions to Wine is to retrieve the Wine source tree using CVS. Read the documentation at winehq.org about how to do this, then try it. For example:

cd ~
export CVSROOT=:pserver:cvs@cvs.winehq.org:/home/wine
cvs login                (The password is the three letters 'cvs')
cvs checkout wine
Once that's done, you'll want to build the Wine sources. (The file README in the wine directory describes how to do this.) You can do this either in the original directory, or in a separate directory; I like doing it in a separate directory because that keeps the compiler output files from getting mixed in with the sources, and makes it easier to back up copies of the source tree and do recursive diffs when generating patches.

To do an out-of-tree build of the Wine sources:

cd ~
mkdir build
cd build
../wine/configure
make depend
make
This takes about 40 minutes on a 650 MHz system.

If you have a ~/.wine directory left over from an older version of Wine, you should delete or rename it (since Wine is still changing rapidly, it often breaks backwards compatibility with old ~/.wine contents):

cd ~
test -d .wine && mv .wine .wine.old
(If you aren't running X already, e.g. if you're running Wine under VMWare and/or your copy of linux isn't set to use graphics on bootup, start X now with the command startx.)

Once that's done, try running some of the programs that come with Wine, e.g.

cd ~/build
./wine programs/notepad.exe.so
(On the very first run, it will display lots of messages about rebuilding font metrics; that's ok.) Scroll back over the messages it outputs to make sure there aren't any glaring error messages.

If notepad works, try running winefile, e.g.

programs/winefile/winefile
That should give you an idea of how Wine maps drive letters.

Then try installing and running a real Windows program using Wine. One good program to try is WinZip. Download the latest version, save the file in the ~/build directory, then install it with Wine like this:

cd ~/build
./wine winzip90.exe
and then run it, e.g.
./wine 'c:\Program Files\WinZip\WINZIP32.EXE'
to make sure it works as you'd expect.

Troubleshooting

If an out-of-tree build crashes while running widl or some other internal Wine tool, try an in-tree build (or go look on wine-devel for patches for the problem; there have been several in Dec 2004/Jan 2005).

If the first thing Wine displays on the first run is

cp: cannot stat `/home/dank/demo/build/tools/wine.inf': No such file or directory
and/or you get the error
WinZip internal error in file install.c line 930
when installing WinZip, then Wine had trouble finding wine.inf when it was creating ~/.wine, and was probably unable to finish setting up the registry; try the following workaround:
cd ~/build
cp ../wine/tools/wine.inf tools/

You may see, when you quit winzip, that a tiny window is left on the screen, and a unix process keeps running an instance of wine. I suspect wine is showing a winzip window that is supposed to be hidden, and for some reason doesn't get cleaned up. To see it, try

ps augxw | grep wine
To kill it (and all other wine processes), try
killall wine-preloader

Project 2: Run The Conformance Test Suite under Wine

To run the entire conformance test suite under Linux, follow the instructions at www.winehq.org/site/docs/wine-devel/testing-wine. For example:
cd ~/build
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 crashes, you may need to click 'cancel' to make the crash dialog box go away.

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

or a breakdown by test source file with sed, uniq, and sort (I admit, I love the Unix shell!):

grep "Test failed" log | sed 's/:.*//' | uniq -c | sort
On my machine, I got the following breakdown of errors:
      2 typelib.c
      4 capture.c
      4 wave.c
      7 vartype.c
If you see more errors than this, something's probably wrong, and you need to troubleshoot a bit before going on.

Troubleshooting the Wine tests

If you see lots of errors of the form
metafile.c:91: Test failed: pass 0: dx[0] (1079638356) didn't match 6
it probably means you don't have any TrueType fonts installed, and Wine didn't install any for you by default. To fix this, install a TrueType font, e.g. download and run http://prdownloads.sourceforge.net/corefonts/courie32.exe.

If you see errors like this:

typelib.c:39: Test failed: Could not load type library
**************************************************************************
You must copy a 'stdole32.tlb' file to your Windows\System directory!
You can get one from a Windows installation, or look for the DCOM95 package
on the Microsoft Download Pages.
**************************************************************************
fixme:ole:LoadTypeLibEx Wanted to load L"stdole32.tlb" as typelib, but file was not found.
it means you don't have a stdole32.tlb installed, and Wine didn't install one for you by default (hopefully, it will soon). You can either live with those errors, or follow their instructions for how to get a copy of that file.

Project 3: Write a Conformance Test

As of this writing, there are many DLLs that lack a conformance test. Read Chapter 4. Writing Conformance tests in the Wine Developers Guide if you haven't already, then pick a DLL that doesn't have a tests subdirectory yet, and write a simple conformance test that exercizes at least some of its basic functions. (Here's an example.) This can take as little as a day to write, for a simple DLL, or could be a monster project. Try to keep the test very simple; the goal is to not spend more than a couple days on the first version.

Six or seven good DLLs to write tests for might be:

Note: do not include any third-party code (e.g. from Microsoft) in your tests! You have to write everything from scratch yourself (or get the author's permission to contribute his/her code to Wine under the LGPL), otherwise the Wine project won't be able to accept your code!

If the DLL has many functions, that's ok, just test the most important or most commonly used ones. Later, you or others can add tests for more of its functions.

If you need a data file, create it during the run, as the test must be fully self-contained. Make sure the test runs properly on at least Windows XP, and preferably also on Windows 98, before running it under Wine.

I find it easiest to write the test so that it can be compiled standalone, without any of the Wine source tree. This means having an '#ifdef STANDALONE', and providing alternate definitions for the start_test, ok, and todo_wine macros; for an example, see the lzexpand test. You'll want to install the Microsoft C++ toolkit (which can only install on Windows 200x or XP, I think) if you haven't already. Then to compile the test with Microsoft's compiler, give a command like

cl -DSTANDALONE -D_X86_ yourtest.c yourlibs.lib
and replace 'yourlibs.lib' with the name of any Windows library your test needs. That should produce yourtest.exe, which you can run either on Windows or on Wine.

Once it runs properly on both Windows and Wine, copy it into the tests subdirectory of the DLL in question, add the neccessary changes to configure.ac and Makefile.in (see the lzexpand test patch for an example), run autoconf to regenerate configure from configure.ac, and make sure your test builds properly.

Once it builds and runs properly under Wine, 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.

Once your patch works, post it to the wine-patches mailing list, along with a note saying who wrote it and under which terms you're releasing it (suggestion: LGPL).

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.)

If the DLL you're testing is nontrivial, you probably want to plan on submitting an initial version that only tests a subset of the DLL. While you're waiting for that to be accepted, continue adding coverage to your tests. Getting a partial test into the Wine source tree can sometimes make it easier and quicker to get the full test in later.

Postmortem

Since the time scale of the UCLA course was so short (three months), I asked the students to pick a DLL that lacked good conformance tests, and implement or improve the tests. The focus on testing wasn't bad, and some tests were committed: However, since only one student managed to get code into CVS, I clearly was still doing something wrong.

I think Wine's conformance tests were in poor shape at the time, and I made the mistake of telling the students to use the existing conformance tests to see if their Wine installation was good. As a result, students spent too much time looking at failing tests rather than coding new ones.