Notes on porting TADS
=====================
Following are notes on changes made to the OS layer in recent
versions, starting with the most recent changes. If you're updating
a TADS port, you should refer to the changes made since the last
working version on your system.
At the end of the file, you'll find more general information on how
the portability layer is designed and how to get TADS working on a
new operating system. If you're porting TADS to a new system for the
first time, you should look at the general notes at the end of this
file.
Quick Start Guide
-----------------
To port TADS to a new platform, you should start by looking at
osifc.h, which specifies the entire TADS Operating System Interface.
You must provide an implementation of this interface for your
platform.
If you're porting TADS to a machine that resembles another platform
where TADS already runs, you can probably use the OS Interface
implementation for that existing platform as a starting point; if
not, you should read the documentation in osifc.h to learn what each
function must do.
You'll also need to construct a makefile or equivalent for your
platform, to compile the C files that make up TADS and link the
results into executables for the TADS Interpreter, and optionally the
TADS Compiler and other tools. You should refer to an existing
makefile (such as the DOS or Unix makefile) as a starting point.
Version 2.5.2 changes
---------------------
In preparation for TADS 3, I've been tightening up the interfaces
between the OS layer and the portable code. My goal is to ensure
that the a common OS layer can be shared by TADS 2 and TADS 3, which
will dramatically simplify the porting of TADS 3 by eliminating the
need to write a new set of OS routines. Porting TADS 3 will simply
be a matter of compiling and linking the TADS 3 portable code with
the existing TADS 2 OS code for your platform; the only coding you
should have to do is to create the makefile.
I've been working on this OS interface improvement for some time.
This process started with the creation of osifc.h, which provides us
with a comprehensive definition of the entire interface that the
portable code uses to call the OS code. I've also been expanding and
improving the OS interfaces slightly over the past few releases, but
I've been trying to minimize these changes to minimize the resulting
porting work created.
With this release, I've addressed a new area, which is references
from the OS code to the portable code. In general, the OS code
should never call the portable code or use any global variables
defined in the portable code; doing so ties the OS code to a
particular portable system, which makes it difficult to re-use the OS
code in a new system (such as TADS 3).
The OS code should NOT henceforth refer to ANY function or global
variable defined in the portable code. If your OS code refers to
anything in the portable code, your OS code will not work with TADS
3, because those portable symbols will probably not be defined at all
in TADS 3.
I've tried to remove all of the references I could find from the OS
code into the portable code. However, until TADS 3 is ported to the
existing platforms, where the linker can root out the missing
symbols, it is difficult to know for sure that all of the references
are gone.
* OS code should no longer call runstat(). Most os_gets()
implementations started by calling runstat() to update the status
line prior to reading input. The OS code is no longer responsible
for this. You should simply remove any runstat() calls from your
OS code. If you have runstat() calls that are needed in places
other than at the start of os_gets(), contact me (mjr_@hotmail.com)
if you would like advice on how to remove the dependency and I'll
try to help figure out what to do.
* The global variables "pagelength" and "linewidth" have been renamed
to G_os_pagelength and G_os_linewidth. This formally moves these
variables into the OS layer rather than leaving them in the portable
formatter.
* The global variable "moremode" has been renamed to G_os_moremode,
moving it into the OS layer.
* OS routines should no longer call tio_is_html_mode() (or any other
tio routines).
* OS routines should no longer call qasclose(). Most of the
os_term() implementations in the OS code were calling this routine;
this should instead be handled in the portable code, so the OS code
should not use this method at all.
* OS code should no longer call outformat() or getstring(). The
text-only implementations of os_askfile() and os_input_dialog()
called these routines, because they implemented their dialogs using
formatted text. To address this, I've moved these text
implementations to the portable layer; there is no longer a text-only
version of os_askfile() or os_input_dialog(). Refer to askf_tx.c,
askf_os.c, indlg_tx.c, and indlg_os.c for details on the new
portable-layer implementations.
MAKEFILE CHANGES: You must include one of askf_tx.c or askf_os.c in
each executable you build. You must include one of indlg_tx.c or
indlg_os.c in each executable. Refer to these files to determine
which one to choose. In general, the _tx versions are text-only
implementations -- these do not invoke os_xxx routines; the _os
versions simply pass through the operation to the corresponding
os_xxx routines. You should choose the _os version if you have a
corresponding os_xxx implementation that you want to use; you should
choose the _tx version if you want to use the plain text version.
If your os_xxx routine was calling outformat() or getstring(), you
should simply delete your os_xxx routine entirely and use the _tx
version; otherwise, keep your os_xxx routine and use the _os version.
OTHER CHANGES:
* added os_is_special_file()
* added os_uninit()
* added OS_CHARMAP_FILECONTENTS identifier
Version 2.5.1 changes
---------------------
* I added a new command code for os_getc(): CMD_EOF. This new code
indicates that "end of file" has been reached on the console input;
this usually means that the player has terminated the application
through some means such as closing its main window, or disconnected
the terminal, or something like that. os_getc() should return this
new code when it detects this type of condition so that code that
calls os_getc() can finish up whatever it's doing and terminate the
application gracefully.
* There's a new function called os_getc_raw(). This is conceptually
a lower-level version of os_getc(). The difference is that os_getc()
returns "translated" keystroke CMD_xxx codes, whereas os_getc_raw()
returns "raw" CMD_xxx codes. The translated codes are higher-level
functional codes; for example, on Unix, when the user types Ctrl-E,
os_getc() would return CMD_END, because Ctrl-E is bound to the
end-of-line command. In contrast, os_getc_raw() would simply return
ASCII 5. Similarly, on DOS, if the user presses the Escape key,
os_getc() would return CMD_KILL, but os_getc_raw() returns ASCII 27.
Note that some keys return different CMD_xxx codes for os_getc() and
os_getc_raw(); for example, on DOS, if the user presses F1, os_getc()
returns CMD_SCR (to toggle scrollback mode), but os_getc_raw() returns
CMD_F1.
The purpose of os_getc_raw() is to allow lower-level access to keystroke
information, particularly for the inputkey() TADS function, while still
preserving the port-specific functional mapping that os_getc() affords.
Refer to osifc.h for documentation of the new function. Note that the
CMD_xxx codes defined in osifc.h are now commented to indicate which
command codes are "translated" and which are "raw"; when a particular
key maps to one of each type, os_getc() should return the translated
CMD_xxx code and os_getc_raw() should return the raw code.
* The osfoprwb() function has traditionally been implemented
incorrectly. On most platforms, this has been implemented as a call
to fopen() with the mode "r+b" (or simply "r+" on platforms with no
text/binary mode distinction), following the example of the DOS code.
In fact, the intended function, which was not adequately documented
in the osifc.h comments, was to open an existing file or create a new
file if it didn't already exist. The C fopen() "r+" mode fails if the
file doesn't exist. The intended behavior has now been correctly
documented in osifc.h, and the DOS, Windows, Unix, and Mac versions
have been changed to use the correct behavior.
Version 2.4.1 changes
---------------------
* New OS function: os_input_dialog(). A default character-mode
implementation in osgen.c should suffice for most ports, but GUI
ports should show a dialog box if possible. The character-mode
implementation in osgen.c is selected at compile time with #define
symbol USE_STDIO_INPDLG, which osgen.c defines implicitly if
USE_STDIO is defined.
* New OS function: os_get_str_rsc(). Most platforms should be able
to use the default implementation in ostadrsc.c (in the generic
code directory). Where possible, though, this function should be
implemented using native OS string resources; this will make it
easier for translators to localize the TADS executables.
* TADSVER.TXT has been changed to TADSVER.HTM, and DOSVER.TXT is
now DOSVER.HTM.
* The interface to the os_askfile() function has changed very
slightly, in that the result code values are now more precisely
specified. In the past, this function simply returns zero for
success and non-zero to indicate failure of some kind. The result
codes can now indicate the type of failure; in particular, the
function can distinguish actual errors from the case where the user
simply chooses to cancel the dialog. Refer to osifc.h for details.
I've attempted to change all of the OS sources that I have in my
source tree; experts on the code for the individual platforms are
encouraged to double-check my changes.
Version 2.4.0 changes
---------------------
* os.h has been reorganized to make it cleaner and more consistent.
All of the DOS code has been removed from os.h and moved to new
DOS-specific headers; this leaves os.h as a very simple "switchboard"
file whose only function is to select the appropriate set of headers
to #include based on the system macro settings. All of the non-DOS
headers already worked this way, so this change should be transparent
to other ports.
* osifc.h now has (as far as I can tell) complete documentation of
the entire TADS Operating System Interface. In particular, all of
the file-related functions (osfoprb, osfrb, etc) are now specified
and documented in osifc.h, as are the former "library" functions
(osmalloc, osfree). This change should not affect any existing code;
the additions are mostly comments.
* The os_find_first_file() and os_find_next_file() interfaces have
changed. Two new parameters, outpathbuf and outpathbufsiz, have been
added; the new buffer is to receive the full path of the current
file, so that the caller doesn't have to attempt to construct the
path name from its components using possibly non-portable
assumptions. This should have minimal impact, since the only ports
that appear to implement these functions currently are DOS, Windows,
OS/2, and Macintosh. Refer to osifc.h for documentation.
* The os_progress() interface has changed slightly. This function no
longer takes a (struct linfdef *) argument, which tied the function
to the particulars of an internal structure in the TADS 2 compiler;
instead, the function now takes a filename string and a line number.
This change should have minimal impact, since only the Macintosh port
currently provides a non-trivial implementation of this function.
Version 2.3.0 changes
---------------------
* ATTENTION UNIX USERS - If you run into weird display problems in
the interpreter, especially with spurious extra spaces at the
beginning of each line, try these definitions in your makefile:
LIBS= -lncurses
CFLAGS= -DHAVE_TPARM (plus whatever other CFLAGS you were already using)
* The existing os_term() function is now used more rigorously. In
the past, the generic code called exit() directly in a few places,
which prevented the OS layer from doing any clean-up at termination.
The generic code should now use os_term() exclusively to terminate
execution. This shouldn't require any new porting work, since
nothing about os_term() has changed -- the only change is that the
generic code is calling it more predictably now. However, a few
ports may accidentally have omitted an os_term() implementation from
some executables, since it wasn't always needed before; if you get a
link error for this symbol during building, adjust your makefile to
include an os_term() implementation.
* A new file, oem.c, defines some global strings for use in identifying
the version of TADS. You must fill in that file with a couple of
customized settings for your version. Please refer to oem.h and
oem.c for details on how to do this.
* A few new OS interface functions have been added. These functions
are described in comments in osifc.h. The new functions are:
os_get_sys_clock_ms()
os_sleep_ms()
os_get_event()
os_set_title()
osfdel_temp()
These functions should be reasonably simple to implement on most
systems. os_get_event() in particular can simply degrade to
os_getc() with some additional argument checks and changes in the
return value if it's hard to implement fully on your system; the
USE_STDIO version in osgen.c can be used as a default implementation.
Note also that a completely portable implementation of os_sleep_ms()
is in msdos/oswin.c. You can use this implementation if you wish,
but the function is included in the OS interface so that you can
replace it with something more suitable for your platform. The
implementation in msdos/oswin.c discards keystrokes and other events
that occur during the delay, which may be undesirable on your system.
This implementation has the desirable effect of processing UI events,
such as window sizing, during the delay.
Most platforms can provide an empty implementation of os_set_title();
this function merely notifies the OS layer that the game has set a
title string via the HTML
tag. If it's convenient, the OS
layer can use the title string as a window caption, or whatever else
makes sense. Most character-mode display code will simply ignore
this; osgen.c has a default implementation that does nothing.
osfdel_temp() is a new function to complement os_create_tempfile().
This function deletes a temporary file previously created with
os_create_tempfile(), after the temporary file has been closed;
callers previously used osfdel(), the generic file deletion function,
to delete these temporary files. The purpose of this new function is
to support systems that can be instructed to delete temporary files
automatically when closed; on such systems, a call to osfdel() is
redundant (and problematic), since the system will already have
automatically deleted the temporary file by the time the caller gets
around to invoking osfdel().
osnoui.c provides a simple implementation of osfdel_temp() that simply
calls osfdel(); this works with the implementation of os_create_tempfile()
in osnoui.c, so you won't need to make any changes if you're already
using this file. If you're using a customized os_create_tempfile(),
you may want to provide a correspondingly customized osfdel_temp().
In particular, if your os_create_tempfile() opens the file in such a
way that the underlying OS will automatically delete the file when
closed, your osfdel_temp() should simply do nothing.
* The os_askfile() interface (defined in osifc.h) has been changed to
provide more information about what kind of prompt to use. The extra
parameters indicate whether we're opening an existing file or saving
a new file, and what type of file we're interested in. Many GUI
systems use different dialogs for opening and saving files, and
filter files displayed in a file selector dialog according to the
type of file to be chosen. Systems that don't need the extra
information can ignore the new parameters; they're purely to make it
easier for the system code to determine what type of dialog to show.
I've updated my copies of the MSDOS, Win32, Mac, and Unix sources for
the new os_askfile interface, but I don't have a copy of every
port-specific version, so you may need to propagate this change into
your version.
* The #define's for the OSFTxxx codes (the file type codes) are now
in osifc.h. In the past, these were scattered among the different
system-specific headers for no good reason -- these are used by
portable code, so they are necessarily part of the OS interface, and
hence belong in osifc.h. If you encounter any errors with redundant
#define's for these symbols, you should simply remove the #define's
from your system-specific headers and use the ones in osifc.h.
* The #define's for the CMD_xxx codes (the os_getc() extended keystroke
codes) are now in osifc.h. In the past, as with the OSFTxxx codes,
these were scattered among the system-specific headers. It's desirable
to be able to use these key codes in the portable code, so these are
now part of the general OS interface. As with the OSFTxxx codes, if
you run into any compilation errors with redundant #define's for CMD_xxx
symbols, you should be able to remove the #define's from your system-
specific headers and use the new osifc.h definitions.
Version 2.2.6 changes
---------------------
In past versions, the release notes for generic changes and platform-
specific changes were combined into a single file, which had to be
maintained separately on each platform. For example, the DOS release
notes were in TADSVER.DOS. To create a comprehensive set of release
notes for another platform, someone porting TADS had to sift through
TADSVER.DOS to pick out the generic changes, then add any changes
specific to the ported version.
In order to remove this extra work, I've broken up the release notes
into two separate files. The new file TADSVER.TXT contains only the
generic changes. Since these changes will automatically be included
in any port (because such changes are always in the portable portion
of the code), the distribution for a port should always be able to
include TADSVER.TXT unchanged. The separate new file TADSVER.DOS
contains changes that apply only to the DOS version. Since such
changes are only in the DOS osxxx code, they should not affect any
other platforms, so only DOS users should need to look at this file.
When creating a ported version, you can now simply create your own
platform-specific release notes file where you can describe any changes
that you made that apply only to your platform.
Please let me know (mjr_@hotmail.com) the name of your port-specific
release notes file, and I'll add it to the table at the top of
TADSVER.TXT, which refers users to the appropriate file for each
platform. (You may want to add an entry to the table yourself for
your initial version, if you plan to include TADSVER.TXT with your
distribution.)
Version 2.2.4 changes
---------------------
I've changed the source distribution zip file's layout slightly to
make the TADS source tree more self-contained. In the previous
version, several files were in a separate LIB directory, which was at
the same level in the hierarchy as the TADS2 directory. This was an
undesirable layout for some people, since it meant that TADS had two
high-level directories. Since keeping the files in a separate
directory doesn't serve any real purpose currently (the separation is
historical), I've merged these files into the base TADS directory
(except that a few of the files are now in TADS/MSDOS, because
they're DOS-specific). Of course, you can still lay out your source
files however you want them, of course, but if you follow the layout
in the zip file, you'll need to adjust your makefile for the changed
location of these files.
If you change the default memory sizes in your osXXX.h file, you should
also define message strings that correspond to your new defaults for the
usage messages. To do this, look at errmsg.c, and notice the big list
of TxD_xxxSIZ_MSG definitions. For each value that you override in your
OS header, you should provide a corresponding TxD_xxxSIZ_MSG definition
that looks like the one in errmsg.c but uses your changed default value.
Version 2.2.3 changes
---------------------
The operating system interfaces have changed somewhat between version
2.2.2 and 2.2.3 (the HTML TADS release). The OS interfaces have been
stable for a long time, so most systems where TADS has been ported
should have OS-dependent implementations that conform to the 2.2.2
interfaces. Unfortunately, all of these ports will have to be reworked
slightly to accomodate the changes in 2.2.3.
The changes in 2.2.3 should be fairly minor, though, so it shouldn't
require a huge effort to upgrade port-specific code that worked with
the previous version. The main changes are that the OS interfaces
have been rearranged slightly in the header files (note in particular
the creation of osifc.h), and some of the functions that were in
osgen.c have been moved to the new file osnoui.c. A few functions
have had minor changes to their interfaces as well. It will probably
be necessary to make some small changes to your makefiles because of
the rearrangements.
One of the biggest changes may be the use of ANSI-style function
prototypes throughout the code. Depending on your compiler, you may
or may not have to change your OS function implementations to use ANSI
prototypes.
==============================================================================
General notes on porting TADS
-----------------------------
Code Organization
-----------------
The TADS code is divided into portable and system-specific sections.
In porting TADS to a new platform, only the system-specific portions
should need to be changed. If any changes are needed to the portable
code, we consider the portable code in error and will try to correct
it so that it is the same on all platforms. We want the portable
portion to have a single set of sources, without port-dependent
ifdefs, across all platforms.
For the most part, the system-specific sections are isolated in
files with the prefix "os", and system-specific functions and macros
all begin with "os" or "OS".
Historical note: At one point we started to group some code that High
Energy was internally sharing between multiple products into a code
library, all of whose files start with "L". The file los.h formerly
many system-specific macros and definitions; these have been moved
into the OS files along with everything else.
oem.h
-----
This file defines information about the person who built a particular
version ("OEM" for "Original Equipment Manufacturer"). Refer to oem.h
for details about how to set up the definitions there.
osxxx.h, os.h, and osifc.h
--------------------------
The first thing to do when starting a new port is to create a new
system-specific header file for your platform. You should choose a
name for the header based on your platform name; for example, on DOS,
the file is osdos.h, and on Unix it's osunix.h.
Next, you must define a C preprocessor macro that will identify your
platform. This macro will be used to select the appropriate code to
include in your version of TADS, using #ifdef preprocessor directives
in the TADS code. Many compilers automatically pre-define a symbol
for this purpose, in which case you should use this symbol;
otherwise, make up a symbol of your own and define it on the C
compiler command line or equivalent when you compile the TADS C files.
Edit the file os.h. This is a "switchboard" file that selects an
appropriate system-specific header to include. The TADS portable C
files #include os.h, and os.h must in turn #include your header file.
You should add a few lines to os.h to #include your header; follow
the example of DOS, Unix, and the other platforms:
#ifdef FROBNIX_OS
/* Frobnix operating system definitions are in osfrob.h */
#include "osfrob.h"
#endif
You shouldn't add anything else to os.h - the rest of your code should
go in your own "osfrob.h" file.
Now you must write the code in your OS-specific header ("osfrob.h" in
the example above). To do this, refer to osifc.h, which defines the
TADS Operating System Interface, which is what you must implement for
your machine.
The purpose of your osxxx.h is to isolate certain platform-specific
definitions to a well-defined location in the code. The rest of the
TADS C code is written so that it uses the definitions in osxxx.h;
this way, the other code doesn't have to be changed when moving TADS
to a new platform.
The file osifc.h contains the specification and documentation of the
TADS Operating System Interface, which contains the portable
interface definitions for functions, types, and macros that must be
tailored to each platform. osifc.h contains a portable interface to
code that varies by platform; because the interface is portable, the
rest of the TADS code doesn't have to know anything about different
platforms, since it can expect the exact same functions to be
available on every machine. osifc.h contains only portable code, so
you shouldn't make any changes in this file.
You can probably take one of the existing osxxx.h implementations as
a starting point, depending on your hardware and operating system.
For example, for a 68000 or 68000-like processor, you might want to
start with the Macintosh header (osmac.h), since the alignment and
byte ordering macros will be appropriate. For an 8086-like
processor, start with the DOS headers (os.h and los.h). Other
platforms may need additional work.
IMPORTANT NOTE: Do not make changes in osifc.h - this file should never
contain any #ifdef's for different platforms, because it defines a
portable interface that is the same everywhere, even though the
implementation of the interface varies by platform. In particular,
the #define constants (OS_EVT_xxx, SYSINFO_xxx, and so on) MUST be the
same on all platforms, because some of these values can be used
programmatically by TADS games; a game can be compiled on one platform
and run on any other machine, so these constant values must be the same
everywhere for games to work properly.
Datatype configuration
----------------------
TADS makes relatively few assumptions about datatype sizes. TADS
expects that shorts are at least 16 bits, ints are at least 16 bits,
and longs are at least 32 bits.
System-specific function implementation
---------------------------------------
Depending on your platform, you may be able to re-use some code that
was originally written for the DOS platform, but works with some
minor changes on other types of machines as well.
The files osdos.c, osgen.c, and osnoui.c provide an implementation of
the system routines for DOS. osgen.c and osnoui.c should be usable
on any system with DOS-like display characteristics. Note osgen.c
and osdos.c check to see if several USE_xxx preprocessor symbols are
defined; these macros are NOT defined anywhere in the source, but are
to be defined by the makefile. On DOS, these os files are compiled
multiple times with different combinations of the USE_xxx symbols to
produce different object files for linking the compiler and run-time.
A stdio (C run-time library "standard input/output") implementation
of many of the routines can also be selected by defining the
preprocessor symbol USE_STDIO.
The file osnoui.c is similar in purpose to osgen.c. The functions
implemented in osnoui.c are semi-portable implementations of functions
that have no user interface component ("no UI").
Building the system
-------------------
TADS consists of three main pieces: the compiler, the run-time, and
the debugger. Refer to the DOS makefile to see which object files
are included in each. Note that it may not be possible to let a
librarian/archiver resolve the links for all symbols, because a few
of the object files provide overlapping sets of symbols -- it is
necessary to manually include such object files in the links. (The
overlapping symbol sets are generally used to provide empty
definitions for certain functions that are referenced but not
actually used by one executable, but must be fully implemented in
another.)
Debugger
--------
The debugger diverges somewhat from the convention of keeping the
os-dependent functions in a file prefixed by "os" or "los". The
debugger's user interface is implemented in the file dbgu.c on DOS,
and dbgumac.c on Macintosh. The DOS version also has a file, osdbg.c,
which provides lower-level functions; it should be possible to port
the debugger to a new platform by using the DOS user interface and
replacing only osdbg.c with an appropriate set of functions for the
new system. However, for any system without DOS-like display and
input device characteristics, the entire user interface will usually
need to be replaced; for example, on the Mac, dbgu.c is not used at all,
but is replaced by dbgumac.c. This separation of the user interface
provides maximum flexibility for the debugger's user interface while
minimizing the amount of work to port it to a new platform.
Testing
-------
The first test is to build a run-time and see if it can run games
compiled on another system. The second is to build the compiler, use
it to compile game on your system, and see if that runs.
You can further test using the regression tests. Compile DEEP.T,
then run tr like this:
tr -i dsdwalk.in -l dsdwalk.new deep
Then compare dsdwalk.new (the new log generated by your version of
DEEP) with dsdwalk.log (the reference version) -- if they're
identical, your system is probably in pretty good shape. You can
test similary with DITCH.T and DDDWALK.IN, and BUGS.T and BUGS.IN.
MS-DOS and Windows Compilation
------------------------------
Two makefiles are provided for compilation on MS-DOS and Windows
machines; both makefiles are in the msdos directory. To avoid
confusion, these makefiles build object files into separate
directories, and name their executables differently from one
another.
makefile.bc is for compilation with the 16-bit Borland C compiler,
version 4.5. With this makefile, you can build the real-mode and
protected-mode 16-bit DOS executables. (You'll need the Borland
Power Pack for DOS in order to build the protected-mode versions
of the executables.)
Note that you should run makefile.bc with Borland make.
makefile.bc compiles into objs (for real-mode object files) and xobjs
(for protected-mode object files), and generates the following
executables:
tc.exe - real-mode TADS compiler
tr.exe - real-mode TADS run-time
tdb.exe - real-mode TADS debugger
tcx.exe - 16-bit protected-mode TADS compiler
trx.exe - 16-bit protected-mode TADS run-time
tdbx.exe - 16-bit protected-mode TADS debugger
maketrx.exe - single-file executable binder
tadsrsc.exe - TADS resource manager
trcolor.exe - run-time color picker
makefile.vc5 is for Microsoft Visual C++ version 5.0. VC++ 5.0
can only perform 32-bit compilations, so this makefile builds only
32-bit versions of the executables. Note that this makefile builds
the two TADS libraries that are required for building HTML TADS:
tr32h.lib (the TADS run-time 32-bit Windows library for HTML) and
tdb32h.lib (the TADS debugger 32-bit Windows library for HTML).
You should run makefile.vc5 with Microsoft nmake.
makefile.vc5 compiles into winobjs32 (for 32-bit Windows object files),
and generates the following executables:
tc32.exe - TADS compiler 32-bit Windows console application
tr32.exe - TADS run-time 32-bit Windows console application
tdb32.exe - TADS debugger 32-bit Windows console application
maketrx32.exe - executable binder 32-bit Windows console application
tadsrsc32.exe - TADS resource manager 32-bit Windows console application
trcolor32.exe - run-time color picker 32-bit Windows console application