Using the MS Visual C++ Compiler with GNU/Wine

By J. Grant 2003-02-18


Abstract

This article documents my investigation into how to use the MS Visual C++ compiler with Wine (Free Software MS-Windows compatible API implementation) on the GNU System.  The results are very positive: with some configuration the same source code can be compiled and the resulting binary can run on any MS-Windows computer.  Reducing the development time wasted was the main goal of this investigation.  In a consolidated game development environment, where one computer can compile everything this provides flexibility and lets the programmers get back to programming.  However, nothing is perfect and, in this case, there was a slowdown of between 40-57% when compiling under GNU/Wine.  This is not a major problem because MS-Windows specific builds are not as frequent as GCC builds in my specific case.  Development time and effort was saved because of no necessity to move source code to MS-Windows to compile.  The time previously used maintaining other computers and builds can now be put to better use in the development process.

Motivation

I am tired of the inefficiencies of moving source code back and forth between GNU and MS-Windows to compile.   Each time the source code files are copied back from MS-Windows the mode attributes are lost, some filenames are now uppercase, others are mixed case.  Correcting issues like this each time I want to do some work on a project in MS-Windows is a monotonous chore; I want to eliminate things like this that waste my time (when I could be programming and earning money!).

Recently I started a small project to port a multi-platform game to PS2Linux (Spheres of Chaos).  The current code base was on MS-Windows and there was an SDL version that had been available compiled for GNU/Linux/SDL.  The SDL source code was languishing and was now slightly broken by the changes in the MS-Windows areas of the source code. 

I decided I wanted to consolidate my game development environment around the GNU OS.  Although MS sell GCC for MS-Windows they do not sell Visual C++ for the GNU OS, which is what I required to eliminate the problem issues relating to maintaining the MS-Windows version of the game.

I was looking for a solution to build native win32 software from my GNU computer.  There are a few cross-compilers that could support this, MinGW being one of the most popular.  However, all the Visual C++ project files were already created, and another developer was using Visual C++ as well.  Therefore I decided I wanted to make use of the current MS-Windows Visual C++ compiler with my consolidated GNU OS development environment.  This is exactly what I did :)

Implementing the idea of using the Visual C++ compiler with GNU/Wine

Using the entire Visual Studio interface to access the compiler underneath would have been overkill for my requirements.  I only wanted to use Visual C++ to compile, as I already use KDevelop, bash, vi, make and grep etc to develop on my GNU system. 

The first job was to check the current game source code compiled on MS-Windows: this required installing SDL and fixing the broken SDL code to compile on MS-Windows (preprocessor code fixes mostly).  After I knew the code was working, I wanted to move over to the GNU OS for development.  There is a common problem with filenames on MS-Windows because they do not support case sensitivity, many were in CAPITALS others were mixed case as IainLib.h.  I zipped the source code on MS-Windows and then copied the zip archive over samba and used a simple trick to fix most of my filename issues.  The command unzip -aL chaos-src.zip unzips the archive, converts text files to GNU format and names all files in lower case.  However, I still had to go through all source code manually and change all #include's also to lower case.

I zipped the "Microsoft Visual Studio" directory after a standard install on MS-Windows as a zip file, and then used unzip -aL to convert to GNU format line endings and to make all filenames lower case.  I moved the directory to $(HOME)/vs which is visible as d:\vs in Wine.   The commands needed to build the game library and the actual game were cl, rc and link, with nmake to manage the build process.  It would be simplest if the Visual C++ compiler could also be executed from a bash prompt.  I tested using GNU paths to execute nmake (cd iainlib; wine -- /home/now3d/vs/vc98/bin/nmake.exe /fiainlib.mak) which, contrary to expectations, did not execute in the current working directory.  This meant that iainlib.mak could not be found, frustratingly (even though it was in the current directory).  Wine supports the use of DOS style file paths:  wine -- d:\\vs\\vc98\\bin\\nmake.exe /fiainlib.mak executed successfully and nmake could read the makefile.  nmake could not, however, complete the build, because three environment variables are required to configure the programs used to compile:  INCLUDE, LIB and PATH.  These three environment variables are required to be "visible" to nmake.  PATH is reasonably simple to setup in GNU bash:

PATH=$PATH:$HOME/vs/vc98/bin/:$HOME/vs/common/msdev98/bin

However, because of the way the separators work, defining INCLUDE and LIB with DOS style ";" would not work, but placing quotes around it forces bash not to evaluate it as separate commands.  If these two environment variables are not defined, Visual C++ cannot access common functions and headers.  Entering this in a bash shell will make these available to nmake.

INCLUDE="d:\vs\vc98\include;d:\vs\vc98\mfc\include;d:\chaos-src\iainlib\h;d:\chaos-src\chaossrc\h;d:\chaos-src\gpdumb"
LIB="d:\vs\vc98\lib;d:\vs\vc98\mfc\lib;c:\chaos-src\iainlib"


Then it is possible to directly compile from a standard terminal with wine -- nmake.exe /fiainlib.mak.

As I was familiar with the DOS shell, I tested the Wine implementation of the DOS shell wcmd.   It looks like a DOS shell in MS-Windows and has the same feel to it.  I created a batch file using DOS paths to define the environment variables as follows (some are specific to the game).

set INCLUDE=d:\vs\vc98\include;d:\vs\vc98\mfc\include;d:\chaos-src\iainlib\h;d:\chaos-src\chaossrc\h;d:\chaos-src\gpdumb
set LIB=d:\vs\vc98\lib;d:\vs\vc98\mfc\lib;c:\chaos-src\iainlib


I decided against placing the game specific #include's and libs in the makefile permanently because it would have required further editing each time a project modification was made by the other team member.

Also, it was necessary to add the executable search path to ~/.wine/config to allow wcmd to execute the commands.

"Path" = "d:\\vs\\common\\msdev98\\bin;d:\\vs\\vc98\\bin;C:\\windows;C:\\windows\\system;D:\\;E:\\"

Now I could run nmake from any directory, the environment variables PATH, INCLUDE and LIB could be read from the program and also accessed by the other commands executed in the makefile.  I also tested cmd and ReactOS CLI from my Win2k computer.  However, both crashed when reading my batch file (DOS format text!).

wcmd screenshot

Build comparison

Win2k laptop, 850MHz Pentium 3, 128MB RAM.  GNU/Wine computer is an Athlon 1GHz, 384MB RAM.  Take this into consideration when reading the following.  Both computers only had one HD, so temporary files would not have had an advantage on either computer.  Both projects were compiled with nmake.  The commands were respectively nmake /fiainlib.mak and nmake /fchaos2.mak.  The times below were taken as a mean average (rounded off) over three complete builds from a clean state.

Project iainlib (platform independent games lib) chaossrc (full game source linked with iainlib)
Win2k Visual Studio [mins:secs] 00:06 00:25
GNU/Wine wcmd [mins:secs] 00:14 00:42
GNU/Wine MS cmd.exe [mins:secs] 00:13 00:42
GNU/Wine ReactOS CLI [mins:secs] 00:14
00:43
GNU bash [mins:secs] 00:14
00:43

Using wcmd filled my terminal with debug printf's.  Using cmd only had one debug printf at startup and one debug printf for each program called.  Using the ReactOS CLI also produced many debug printf's.  The total compile time for iainlib using the three different shells on GNU/Wine were all very similar, 57% longer than on Win2k.  The compile time of chaossrc was also very similar using the four shells tested with GNU/Wine, 40% longer than on Win2k.

It was demonstrated that using a different shell with GNU/Wine did not reduce the overall compilation time.  The extra time required is thus directly linked to the Wine implementation of the win32 API.  This extra time used was not such a major issue in the case of the game and library, because it was not a large project.  The transfer of source to an MS-Windows machine and the correction of filenames and text format issues have been avoided.  Therefore, I can build the game from one machine, then I only have to copy the final chaos.exe to my MS-Windows machine to test.

Issues

wcmd is limited in functionality, it appears to look like any other MS-Windows application running under GNU/Wine (a little sluggish).  It is implemented as running in its own window, and does not support the standard X-Windows copy/paste approach.  GNU style LF text files are displayed as "abcd[][]" and the wcmd crashes and has to be terminated.  Scrolling up wcmd often leaves the text area corrupted.   Changing the number of lines in wcmd causes the font to be reset to small size again, and then minimise itself.  wcmd does not save preferences, so I always have to start with a small font! (fixed in current CVS version)

There are two fonts to choose from: a Courier lookalike (which looks poor with no anti-aliasing on X), and one that looks like it came from Atari - Asteroids.  cmd ran in a terminal, but did not work well.  The option of running wcmd in my current terminal of choice would make things much better.

After copying from the "marked" buffer in the wcmd window, the text is repeated many times and is somewhat corrupt.

Both ReactOS CLI and cmd crashed when running batch files.

Consideration of the Visual C++ compiler implementation

There was quite a bit of hocus-pocus surrounding the command line arguments and other functionality.  This is also a problem with GCC to a certain extent.  However, how could anyone be expected to understand the difference between _DEBUG  and NDEBUG?  (The former is with debugging symbols and the latter without.)  The Visual C++ compiler does not follow the GNU compiler standard, the parameters and commands are quite different.  rc requires lower case /i for command line include paths, the inverse of cl, which is poor design in my opinion.  The makefile syntax is a little different from GNU make, also quotes are used extensively, for example, in declarations.  Compared to GNU make, nmake is limited in functionality: often previously compiled code was recompiled each time nmake was executed.  Furthermore, the pre-generated iainlib.mak was not as structured as Makefiles output from GNU automake.  Often there was more than one definition of each program that was executed by the makefile.

RSC_PROJ was defined containing the flags for rc, but were they never used, the same arguments were passed on the command line each time!  Also everything was defined twice, for release and debug.  Perhaps it would have been more sensible just to add /ZI to the CPP_PROJ flags MS? (This is all that is different between the two, essentially.)

Inexplicably, it was impossible for Visual Studio to add files to the project with lower case filenames .  So, I had to edit the dsp file and replace all upper case filenames and directory names with lower case.

Conclusions

wcmd was the only DOS shell that could use the batch file to configure the compiler.  wcmd printed many debug printf's, cmd had one debug printf, as did ReactOS CLIwcmd and ReactOS CLI run in a separate window by default.  Unfortunately, there is no way to run in a normal text mode GNU terminal.  cmd does run in a terminal, but as it does not work with batch files or facilitate the access of environment variables, it is not useful.

Wine has really come a long way to facilitate running major applications such as Visual C++.  Features that "just work" often do not get mentioned because there is nothing to say.  Wine has many excellent features like this.  However, I have expressed the problems with Wine currently and I expect that in a potential follow up article many of these will be resolved.  Wine has been in development for over a decade now. As it is finally nearing a 1.0 release, I see how much better it was than the 1.0 release of MS Windows.

Using Visual C++ on GNU/Wine gives me all the benefits of being able to develop a 100% compatible MS-Windows version of the game, while saving me the time of maintaining another Win2k machine version of the source and moving to that machine to compile.  It has been a great time saver for me and I strongly expect this information will be very useful to myself and others in the future.

Future aspirations for Wine

wcmd is only ver 0.17; I would like to see it mature to a 1.0 release soon.  In the same way that X-Windows runs on top of a GNU style environment, I would like to see Wine also supporting environment variables better.  An option in the Wine config file to enable the autoexec.bat file to be called on startup of the Wine environment would be very useful.  An alternative to this would be an [Environment Variables] block in the config file; MS-Windows NT replaced the autoexec.bat functionality in a similar way to this (stored in registry I believe).  Many of the problems visible when working with command line MS-Windows tools perhaps have not been noticed before.  However, command line programs are still in use, even on the GUI oriented MS-Windows.  I would hope that text mode "fixme" warnings will be corrected, and there is better support of a builtin msvcrt.dll in the future.  Please take these comments in the constructive criticism format they were considered.

Technical details

I chose to use all stable release software so that this article would be immediately useful.  I tested using the Mandrake 9.0 branded GNU/Linux distribution, Wine version 2002-08-04, MS Visual C++ compiler Version 6.  I also checked the latest Wine CVS version 2003-01-15 at the end of writing this article to see if any issues had been resolved and would be available in the next stable release.  wcmd ran slightly better, copy and paste was partially working still, cmd and ReactOS CLI still crashed with batch files.  However there was a regression regarding dll loading, available for viewing in the online bugs database (it is present in all builds since 2002-09-24).   Normally it would be fine to place the msvcrt.dll in the bin dir, but in this case it will not be loaded.  The workaround is to move your msvcrt.dll(win98se version works well) from vc98/bin to the windows/system dir.  If you do not have your copy of MS-Windows installed currently you can download the dll's you already own again from here or here.  This bug is characterised by "fixme:msvcrt:_XcptFilter" being displayed when nmake crashes.

Be careful to avoid configuration errors in your paths.  MS-Windows does not follow the GNU bash style environment variable format and uses ";" to separate different dir's in each environment variable.  As PATH is defined in the Wine "config" file this is converted, but INCLUDE and LIB will only work if declared correctly by a batch file running in the selected DOS shell or in the bash shell using quotes.

Acknowledgements

I would like to thank the people on #winehq (irc.freenode.net)  and the Wine developers list for their comments and feedback during the final stages of this investigation. You all are a credit to the Free Software world.


Author bio

J. Grant has been developing video games since circa 1998.  Most recently he ported Spheres of Chaos)
to PS2Linux.  There is a free demo for GNU/Linux, PS2Linux and MS-Windows if you would like to try it.

You can contact J. Grant at:  jg-web-articles--AT--jguk-org and on ICQ 11122941.
Homepage: http://jguk.org/