
Using OOC under Win32
=====================

This document describes options for using OOC on Windows systems.

Currently, OOC requires the GNU C compiler (gcc). There are a couple of
implementations of gcc under Windows:

1) Mingw32  (www.mingw.org)
2) Cygwin   (www.cygwin.com)

Mingw32 is a "minimalist" implementation of gcc for Win32 systems. Mingw32
applications link to Microsoft's own C run-time library (MSVCRTL.DLL),
which is installed as part of every Windows system. Some features of
Mingw32:
- Mingw32 environment is compact.
- Mingw32 applications are compact.
- Run-time library functions have "Windows" semantics.
- Some "Unix" functionality is not available.

Cygwin is an implementation of the Unix API for Windows. Cygwin
applications use GCC's run-time library as well as additional "emulation"
functions in a separate library (CYGWIN.DLL). Some features of Cygwin:
- Cygwin environment is very large.
- Cygwin applications require an additional large DLL.
- Run-time library functions have "Unix" semantics.
- Cygwin is only free for GPL code. Use with non-GPL code requires a
  special contract with the vendors.

In many cases, Unix source code can run unmodified under Cygwin. Cygwin is
typically distributed with a large collection of Unix utilities, including:
- C compiler
- Bash shell
- ssh and cvs
- XWindows client libraries
- XWindows server
- inetd and friends (supporting ftp and telnet into Windows systems).

In addition, Cygwin supports the generation of Mingw applications via the
"-mno-cygwin" option. 

OOC supports the following options:

- Cygwin
- Mingw stand-alone  (with MSYS)
- Mingw under Cygwin

Note: Some of these configurations have not been extensively tested. Please
report any problems.

Path virtualisation
===================

The C compiler and associated utilities are Unix applications that have
been ported to run under Windows. Unix applications cannot be allowed to
see DOS file names, or they would fail to handle files properly. Each
application has its own file management procedures that assume Unix syntax.
To port such applications to Windows, the run-time environment MUST map all
DOS file paths to Unix syntax.

Applications compiled with Cygwin will see Unix-style paths. Applications
compiled with Mingw (or -mno-cygwin under Cygwin) will see Windows paths.

OOC will see different styles of paths according to which environment is
has been compiled under. However, the C compiler always sees virtual Unix
paths. For OOC and gcc to play nicely together:

  It is ESSENTIAL that OOC and gcc SEE THE SAME PATHS TO SOURCE FILES.

Keep this in mind when installing the system.

Note that OOC does not quote file names that are passed as arguments to the
C compiler, so:

  PATHS TO SOURCE FILES MAY NOT INCLUDE WHITESPACE.

This may be an issue on Windows systems, in which the user's default working
directory is called something like "Documents and Settings/myname". To use OOC
under Windows, you will need a working directory that does not have spaces in
its name (eg. C:/users/myname").

Note that OOC uses an absolute path to name the "install" program. This means
that the path detected by "configure" may not be usable by the generated
compiler under mingw. To remedy this problem, specify the absolute path using
the INSTALL environment variable.

Installing the GC
=================

To do any serious work with OOC, you will need to install a garbage collector.
This is a separate library used by the compiler and OOC applications for
memory management. OOC uses Hans Boehm's GC, available here:
  http://www.hpl.hp.com/personal/Hans_Boehm/gc/

Follow the installation instructions for the GC. The following discussion 
applies for modern releases. It is recommended to use at least version
6.3alpha2.

1) Build the GC library.

  ./configure
  make

2) Ensure that the GC is working correctly.

  Under Cygwin:
    make gctest
    ./gctest

  Under MingW32, the test application is a Win32 application and writes its
  output to a file "gc.log" rather than standard output.
    make gctest.exe
    ./gctest
    cat gc.log

3) Install the GC library

  make install

4) Review possible configuration settings for OOC

Path issues:

  Unless you specify another location to "configure" via the --prefix option,
  the libraries will be installed in /usr/local/{lib,include}. Depending on
  your local settings, this may not be the C compiler's search path. To ensure
  that OOC finds the GC, you may need to use these settings:
    CPPFLAGS=-I/usr/local/include
    LDFLAGS=-L/usr/local/lib
  It appears that these are necessary for MingW32/MSYS.

Threading issues:

  Versions of the GC differ in how threads are handled under Win32.

  For modern releases of the GC, "configure" builds a threaded GC under
  MingW32. This requires locks to be statically allocated by the GC. Under
  Win32, this only works correctly if client code defines the symbol:
    GC_WIN32_THREADS

In summary, for MingW32/MSYS the following options are likely to be required
by the GC in order to build OOC:
	"CPPFLAGS=-I/usr/local/include -DGC_WIN32_THREADS" \
	LDFLAGS=-L/usr/local/lib 

Installation 
============

1) Make a directory `c:\usr\local\src', and extract the oo2c files here.

2) Under MSYS or Cygwin, ensure that `c:\usr\local' is mapped to the
   logical path `/usr/local'. Normally, one would do:

     mount c:/usr/local /usr/local

   If you encounter problems with the "mount" tool, see additional comments
   below.

3) `cd' to the directory containing the compiler source code.

4) Configure the package.

    For Cygwin:

      env CFLAGS=-O2 ./configure --disable-libs

      
    For stand-alone Mingw32 (adjust path to "install.exe"):

	  env \
	    "INSTALL=c:/msys/1.0/bin/install.exe" \
	    LDFLAGS=-L/usr/local/lib \
	    CFLAGS=-O2 \
		"CPPFLAGS=-I/usr/local/include -DGC_WIN32_THREADS" \
        ./configure --disable-libs

    For Mingw32 under Cygwin:

	  env CPPFLAGS=-mno-cygwin CFLAGS=-O2 LDFLAGS=-mno-cygwin \
	    ./configure --disable-libs

      (depending on path settings, INSTALL path may be required as above)

5) Type `make' to compile the package.

6) Type `make install' to install the programs and any data files and
   documentation.  `make install-strip' will additionally remove any 
   debug information from the installed executables.

7) You can remove the program binaries and object files from the
   source code directory by typing `make clean'.  To also remove the
   files that `configure' created (so you can compile the package for
   a different kind of computer), type `make distclean'.  

Problems?
=========

1) In at least one version of MSYS it looks like the "mount" tool is
   broken.  If you keep getting "Function not implemented", you may need to
   manually edit the MSYS fstab file (eg. C:\MSYS\1.0\etc\fstab). It should
   look something like this:

     c:/MinGW /mingw
     c:/usr/local /usr/local

   Note that MSYS must be restarted for any changes to take effect.

2) OOC couldn't find "install" during "make install"? Depending on path 
   settings, the detected path to "install" may not be valid for mingw
   executables. See the explanation in "Path Virtualisation" and try setting
   the INSTALL path before running "configure". For a quick fix, manually
   adjust the "install" entries in the generated "rsrc/OOC/oo2crc.xml" and
   re-run "make install".

3) While building OOC under MingW32, stage0/oo2c crashes abruptly? Most likely
   you have a threaded GC, and have not defined "-DGC_WIN32_THREADS" during
   configure. The crash is due to an uninitialised mutex in the GC. See
   the section "Installing the GC".

4) You installed the GC under MingW32, but OOC did not find it? By default
   mingw32/MSYS does not search in /usr/local/{lib,include} where the GC is
   normally installed. You will need to explicitly specify these locations
   to the compiler via the LDPATH and CPPFLAGS environment variables. See
   the section "Installing the GC".

5) You have installed both cygwin and mingw32 toolchains, and the C compiler
   is behaving strangely? Take care that you have the correct search paths
   configured. As a general rule, you should not allow the MSYS shell to see
   the cygwin compiler, and vice versa. The object files generated by the two
   compilers are similar, but depend on different run-time libraries. If the
   compiler sees the wrong object files at link-time you can expect to see
   many undefined symbols.

Platform-specific issues
========================

This section discusses features of OOC relevant to the Win32 platform.

- Alignment. Many Win32 structure specify particular alignments. OOC
  provides the following record flags to control the alignment of fields
  within a record: ALIGN1 ALIGN2 ALIGN4 ALIGN8

  Example:

    tagMCI_WAVE_OPEN_PARMSA_struct* = RECORD [ALIGN1]
      dwCallback* : DWORD;
      wDeviceID* : MCIDEVICEID;
      lpstrDeviceType* : LPCSTR;
      lpstrElementName* : LPCSTR;
      lpstrAlias* : LPCSTR;
      dwBufferSeconds* : DWORD
    END;

- Calling Conventions. Most functions in the Win32 API are declared to use
  "Pascal" (or "stdcall") calling convention. For Pascal calls, the callee
  removes any parameters from the stack before returning from the
  procedure.  In "C" calling convention (or "cdecl"), the caller removes
  the parameters which permits the use of variable argument lists.

  The "fastcall" calling convention is implemented by Microsoft's C compiler as
  well as recent versions of GCC. Specifying "Fastcall" causes arguments to
  functions to be passed in registers "where possible". For the x86, the first
  two LONGINT or smaller arguments are passed (left to right) in the ECX and
  EDX registers; all other arguments are passed right to left on the stack. The
  callee removes arguments from the stack. On modern machines, the speed
  benefits of fastcall are probably negligible, but it is occasionally used in
  third-party application binary interfaces (ABIs) so it is included here for
  compatibility with these libraries.

  OOC allows calling convention to be specified in both Module declarations
  and procedure declarations. For example, an interface module for a Win32
  library is usually declared "Pascal":

    MODULE WinApi [ INTERFACE "Pascal";
      LINK LIB "kernel32"; LIB "user32"; LIB "gdi32" END];

  Procedures or procedure types declared within the interface module will
  inherit the specified calling convention. 

    WNDPROC* = PROCEDURE (p0 : HWND; 
	   p1 : UINT; p2 : WPARAM; p3 : LPARAM) : LRESULT;

  In the above example, WinApi.WNDPROC inherits the "Pascal" convention
  declared in the module header.  Exceptions from the module convention may
  be declared per procedure. For example:

    PROCEDURE wsprintfA* [ "C" ] (p0 : LPSTR; p1 : LPCSTR; ...) : LONGINT;
 
  Regular Oberon-2 modules use the default calling convention, which is
  compatible with "C". Oberon-2 functions to be used as Win32 call-backs
  must therefore be explicitly declared "Pascal". For example:

    IMPORT W := WinApi;

    PROCEDURE MessageHandler ["Pascal"] (wnd : W.HWND; 
      msg : W.UINT; wParam : W.WPARAM; lParam : W.LPARAM) : W.LRESULT;

- C string assignment. Libraries written for the "C" language generally
  represent text strings using the "char *" data type. The Oberon-2
  equivalent is "POINTER TO ARRAY OF CHAR", which is not normally
  compatible with Oberon strings types. The CSTRING pointer flag specifies
  that "C"-style string assignments should be permitted. The following are
  fragments from the Win32 API.

    PCHAR* = POINTER [ CSTRING ] TO ARRAY OF CHAR;
	...
    LPCSTR* = PCHAR;
	...
    PROCEDURE MessageBoxA* (hWnd : HWND; 
	  lpText : LPCSTR; lpCaption : LPCSTR; uType : UINT) : LONGINT;

  The declaration of WinApi.MessageBoxA allows strings or character arrays
  to be passed as the second and third parameters. For example:

    IMPORT W := WinApi;

    PROCEDURE TestMessage;
    VAR result : LONGINT;
    BEGIN
      result := W.MessageBoxA(0, "Hello!", "This is a test Message", 0);
    END TestMessage;

    PROCEDURE MessageBox(title, message : ARRAY OF CHAR);
	VAR result : LONGINT;
	BEGIN
	  result := W.MessageBoxA(0, title, message, 0);
	END;  

Implementation Issues
=====================

1) File rename. 

Windows file semantics do not allow open files to be renamed, or files to
be renamed over existing files. Cygwin emulates Unix behaviour, but not on
Win9X platforms. 

- Files.File.Register uses unlink/rename/re-open

- IO:FileChannel uses the Win32 kernel function MoveFileEx to guarantee an
  atomic rename operation. It is not clear which versions of Windows
  support MoveFileEx. 

2) ftruncate()

The ftruncate function is unavailable under Windows. This means that
PosixFileDescr.Truncate will always return an error.

3) Windows networking.

Windows networking functions are in a separate library, WSOCK32.DLL, which
is included if the relevant IO modules are used.  The networking library is
configured as part of the initialisation for module IO:Socket. Note that
Windows sockets are not file descriptors and require a separate set of
functions to operate. For portable code, IO:SocketChannel should always be
used for sockets.

4) system()

There are many issues associated with the system() run-time function.
Under Unix, system() calls the Unix shell as its command interpreter.
Under windows, system() calls the Windows command interpreter. These
interpreters differ in their syntax and semantics. In addition, the
Microsoft C start-up code has its own rules for interpreting the command
line. 

There appear to be some limitations in the Windows command interpreter that
prevent OOC passing long command lines to the C compiler (eg. as are
required for static linking). Therefore, OS:ProcessManagement.system does
not use the run-time library system() command. Instead, the command-line is
passed directly to the command using the Win32 kernel CreateProcess
function. This means that it is not possible to:
- use piping redirection with a system command
- specify substitutions using environment variables

An option exists to use an external shell `/bin/sh' for the system command.
This can be enabled by defining USE_SHELL in lib/src/OS/ProcessManagement.c. 
With an external shell, such as `bash' installed in `C:\bin', system()
behaves the same as the Unix system() call. This configuration is necessary
to use the test framework from the OOC CVS repository. 

-- Stewart Greenhill <sgreenhill@users.sf.net>

