TADS 3 provides "separate compilation," which means that you can arrange your program's source code into several modules, each of which is compiled separately from the others, then link together the compiled modules into a finished program.
Previous versions of TADS provided a related feature, called "precompiled headers," that allowed you to compile part of your program's source code ahead of time. This wasn't nearly as powerful as TADS 3's true separate compilation, however: precompiled headers only let you pre-compile a single section of the code, which meant that any change to the single pre-compiled section required full recompilation. TADS 3's true separate compilation lets you structure your code into as many separate files as you want, each of which can be independently compiled; you only need to recompile the sections you actually change.
The TADS 3 compiler includes a "make" facility, which automatically recompiles the source modules that you've changed since they were last compiled. The TADS 3 "make" facility is similar to the Unix "make" program, but is not programmable like the Unix version; instead, the TADS 3 version is pre-programmed with the relationships among source, object, and image files.
To build a program using TADS 3, you run the "make" command, t3make, with all of the source modules listed as arguments. You do not need to use #include to combine the source modules from a master source file as you did in previous versions; instead, the linker combines the modules together for you. (You can still use #include to structure your program as a single logical module if you want, but if you do so you will not gain the advantages of separate compilation.)
t3make first compiles each source file that has been modified since it was last compiled. The result of compiling a source module is an "object file"; a source file called "mygame.t" would have a corresponding object file called "mygame.t3o" "t3o" stands for "T3 Object." If a source file or one of its included files has been modified since the corresponding object file was created, t3make compiles the source file; if the object file is up to date with the source, there's no need to recompile the source file, so t3make automatically skips it.
Note that the "object" in "object file" doesn't mean a code object, as in an instance of a class. "Object file" is a term that most compiled languages use to refer to the output of the compiler, which is also the input to the linker. An object file contains a version of the source program that has been translated into machine code, but which usually contains references to external symbols that must be resolved by the linker before the code becomes an executable program.
After compiling all of the modified source files into object files, t3make looks to see if the image file is up to date by checking to see if any object files are newer. If at least one object file is newer than the image file, the image file must be re-linked. (Thus, if any source files are compiled during this run of t3make, the image will obviously have to be re-linked.) If it is necessary to re-link, t3make loads all of the object files, resolves their mutual external references, and creates an image file.
The biggest advantage of separate compilation is that loading an object file into the linker is usually much faster than compiling a source file. If you're working on a large game, you will often make changes in only a few parts at a time, which means that only a small number of your source files might need to be compiled for each build. This can often speed up building quite substantially.
The t3make command line looks like this:
t3make o mygame.t3x Fo obj Fy sym game1.t game2.t game3.t
The -o option tells the linker the name of the image file; this is the T3 executable file that you run using the TADS 3 interpreter. The -Fo option, if you include it, tells the compiler where to put object files; by default, they'll go in the same place as the source file, but if you want to store object files in a separate directory, which you might wish to do to keep your source directory uncluttered, you can use this option. Similarly, the -Fy option tells the compiler where to put "symbol" files, which are another kind of generated file that the compiler creates; as with objects, you might want to keep these files in a separate directory from the source to avoid clutter. (You don't otherwise need to worry about symbol files; they're purely for the compiler's use.) Finally, you must list the source files that make up your game.
Other options that might be useful from time to time:
If you take advantage of the separate compilation capability by dividing your program into several source files, you might find that your t3make command lines become quite lengthy. This will be of no concern if you're using an integrated environment such as TADS Workbench, but could become inconvenient if you're building directly from a command shell.
To make things easier for command-line users, t3make can read build commands from an "option file." An option file is simply a text file that contains the same information you'd normally put on the command line. Each line of an option file can include one or more module names and options, separated by spaces. Use a pound sign ("#") to start a comment; everything after a pound sign is ignored. If you want to use spaces or pound signs within a filename or option, enclose the entire option in double quotes; if you want to use a double quote mark within a quoted option, use two double quote marks.
Here's a sample option file.
#
# option file for calc
#
# source files
"calc sources\calc.t"
"tok sources\tok.t"
# image file
-o "exe\calc.t3o"
To read options from a file, use the f compiler option:
t3make f calc.t3m
The options read from an options file are appended after the options on the command line, so you can mix options from a file and the command line. For example, if you wanted to use the option file above to compile the program for debugging, you could enter a command like this:
t3make f calc.t3m -d
If you run t3make and do not specify any modules (in other words, your command line consists only of options), and you also don't include a f option to specify an option file, the compiler looks for a default option file called "makefile.t3m" in the current directory. If this file is present, the compiler reads the file as though you had specified it with the f option. This makes it very easy to build your program; if you put your build options in the file makefile.t3m, you can build simply by typing "t3make".
The normal rules for option files apply to makefile.t3m, so you can specify additional options on the command line when building with the default option file. For example, to build for debugging using the default option file, you would simply enter this:
t3make d
TADS 3 includes a default source module called _main.t that contains some low-level support code that most programs need. Because most programs will not have any reason to customize this module, the compiler automatically includes the module; this saves you a little work, because you don't have to add the module to your t3make command line explicitly.
However, it is possible that you'll want to use a different version of the code in _main.t, in which case you will need to remove the default version from the build. To do this, use the compiler's nodef option. This option tells the compiler not to include any default modules in the build; only the modules you explicitly list on the command line (or in an option file) are included in the build in this case.
The t3make utility will compile a source file if it finds any of the following conditions:
The dependency tracking mechanism isn't perfect, and it can be fooled under certain circumstances:
You can force a full recompilation with the t3make r option; you can use this option if you encounter any situations where you suspect that t3make is missing some dependency and therefore failing to notice a file that requires recompilation.