The TCC Users' Guide

  1. i. The Function of TCC
  2. 1. The Overall Design of TCC
    1. 1.1. Specifying the API
    2. 1.2. The Main Compilation Path
    3. 1.3. Input File Types
    4. 1.4. Intermediate and Output Files
    5. 1.5. Other Compilation Paths
    6. 1.6. Finding out what tcc is doing
  3. 2. TCC Environments
    1. 2.1. The Environment Search Path
    2. 2.2. The Default Environment: Configuring tcc
    3. 2.3. Using Environments to Specify APIs
    4. 2.4. Using Environments to Implement tcc Options
    5. 2.5. User-Defined Environments
  4. 3. Component of the TDF System
    1. 3.1. The C to TDF Producer
    2. 3.2. The TDF Linker
    3. 3.3. The TDF to Target Translator
    4. 3.4. The System Assembler
    5. 3.5. The System Linker
    6. 3.6. The C Preprocessor
    7. 3.7. The TDF Pretty Printer
    8. 3.8. The TDF Archiver
  5. 4. Miscellaneous Topics
    1. 4.1. Intermodular Checks
    2. 4.2. Debugging and Profiling
    3. 4.3. The System Environment
    4. 4.4. The Temporary Directory

First published .

Revision History


Moved out appendix reference material to tccenv, tccmodes and command line options to TCC manpages.

Merged in documentation for the supplied portability tables from the C/C++ Producer Configuration Guide.


Removed compilation scheme diagrams; these were duplicates already provided by TDF and Portability.


Converted to DocBook.


tcc 4.0; TenDRA 4.1.2 release.

Version 4.0 is a complete rewrite from version 3.x.

i. The Function of TCC

Like most compilation systems, the TDF C system consists of a number of components which transform or combine various types of input files into output files. TCC is designed to be a compilation manager, coordinating these various components into a coherent compilation scheme. It is also the normal user's interface to the TDF system on Unix machines: direct use of the various components of the system is not recommended. Therefore it is worth familiarising oneself with TCC before attempting to use the TDF system. To aid this familiarisation TCC has been designed to have the same look and feel as the system C compiler CC, but with added functionality to deal with the additional features of the TDF system. This does not mean that TCC can be necessarily regarded as a direct replacement for CC; the extra portability checks performed by the TDF system require the precise compilation environment to be specified to TCC in a way that it cannot be to CC.

Before discussing TCC itself in detail, it is necessary to understand the compilation strategy that it is designed to implement. This was discussed at length in [1], which readers are urged to consult before moving on to the details of this implementation.

There are two basic components to this paper. The first describes this compilation strategy and how it is implemented by TCC. The second is a Quick Reference section at the end of the paper, which is intended to be a TCC user's manual. For even quicker reference, TCC will print a list of all its command-line options (with a brief description) if invoked with the -query option.

1. The Overall Design of TCC

  1. 1.1. Specifying the API
  2. 1.2. The Main Compilation Path
  3. 1.3. Input File Types
  4. 1.4. Intermediate and Output Files
  5. 1.5. Other Compilation Paths
    1. 1.5.1. Preprocessing
    2. 1.5.2. TDF Archives
    3. 1.5.3. TDF Notation
    4. 1.5.4. Merging TDF Capsules
  6. 1.6. Finding out what tcc is doing

1.1. Specifying the API

As we have seen, the API plays a far more concrete role in the TDF compilation strategy than in the traditional scheme. Therefore the API needs to be explicitly specified to TCC before any compilation takes place. As can be seen from Fig. 3, the API has three components. Firstly, in the target independent (or production) half of the compilation, there are the target independent headers which describe the API. Secondly in the target dependent (or installation) half, there is the API implementation for the particular target machine. This is divided between the TDF libraries, derived from the system headers, and the system libraries. Specifying the API to TCC essentially consists of telling it what target independent headers, TDF libraries and system libraries to use. The precise way in which this is done is discussed below (in section 4.3).

1.2. The Main Compilation Path

Once the API has been specified, the actual compilation can begin. The default action of TCC is to perform production and installation consecutively on the same machine; any other action needs to be explicitly specified. So let us describe the entire compilation path from C source to executable shown in Fig. 3.

  1. The first stage is production. The C → TDF producer transforms each input C source file into a target independent TDF capsule, using the target independent headers to describe the API in abstract terms. These target independent capsules will contain tokens to represent the uses of objects from the API, but these tokens will be left undefined.

  2. The second stage, which is also the first stage of the installation, is TDF linking. Each target independent capsule is combined with the TDF library describing the API implementation to form a target dependent TDF capsule. Recall that the TDF libraries contain the local definitions of the tokens left undefined by the producer, so the resultant target dependent capsule will contain both the uses of these tokens and the corresponding token definitions.

  3. The third stage of the compilation is for the TDF translator to transform each target dependent TDF capsule into an assembly source file for the appropriate target machine. Some TDF translators output not an assembly source file, but a binary object file. In this case the following assembler stage is redundant and the compilation skips to the system linking.

  4. The next stage of the compilation is for each assembly source file to be translated into a binary object file by the system assembler.

  5. The final compilation phase is for the system linker to combine all the binary object files with the system libraries to form a single, final executable. Recall that the system libraries are the final constituent of the API implementation, so this stage completes the combination of the program with the API implementation started in stage 2).

Let us, for convenience, tabulate these stages, giving the name of each compilation tool (plus the corresponding executable name), a code letter which TCC uses to refer to this stage, and the input and output file types for the stage (also see 7.2).

1.C producer (tdfc)cC sourceTarget independant TDF
2.TDF linker (tld)LTarget independant TDFTarget dependant TDF
3.TDF translator (trans)tTarget dependant TDFAssembly source
4.system assembler (as)aAssembly sourceBinary object
5.system linker (ld)lBinary objectExecutable

The executable name of the TDF translator varies, depending on the target machine. It will normally start, or end, however, in trans. These stages are documented in more detail in sections 5.1 to 5.5.

The code letters for the various compilation stages can be used in the -Wtool, opt, ... command-line option to TCC. This passes the option(s) opt directly to the executable in the compilation stage identified by the letter tool. For example, -Wl, -x will cause the system linker to be invoked with the -x option. Similarly the -Etoolfile allows the executable to be invoked at the compilation stage tool to be specified as file. This allows the TCC user access to the compilation tools in a very direct manner.

1.3. Input File Types

This compilation path may be joined at any point, and terminated at any point. The latter possibility is discussed below. For the former, TCC determines, for each input file it is given, to which of the file types it knows (C source, target independent TDF, etc.) this file belongs. This determines where in the compilation path described this file will start. The method used to determine the type of a file is the normal filename suffix convention:

*.cC source
*.jTarget independent TDF capsules
*.tTarget dependent TDF capsules
*.sAssembly source files
*.oBinary object files
*Binary object files

Files whose type cannot otherwise be determined are assumed to be binary object files (for a complete list see 7.1).

Thus, for example, we speak of .j files as a shorthand for target independent TDF capsules. Each file type recognised by TCC is assigned an identifying letter. For convenience, this corresponds to the suffix identifying the file type (c for C source files, j for target independent TDF capsules etc.).

There is an alternative method of specifying input files, by means of the -Stypefile, ... command-line option. This specifies that the file file should be treated as an input file of the type corresponding to the letter type, regardless of its actual suffix. Thus, for example, -Sc, file specifies that file should be regarded as a C source (or .c) file.

1.4. Intermediate and Output Files

During the compilation, TCC makes up names for the output files of each of the compilation phases. These names are based on the input file name, but with the input file suffix replaced by the output file suffix (unless the -make_up_names command-line option is given, in which case the intermediate files are given names of the form _tccnnnn.x, where nnnn is a number which is incremented for each intermediate file produced, and x is the suffix corresponding to the output file type). Thus if the input file file.c is given, this will be transformed into file.j by the producer, which in turn will be transformed into file.t by the TDF linker, and so on. The system linker output file name can not be deduced in the same way since it is the result of linking a number of .o files. By default, as with CC, this file is called a.out.

For most purposes these intermediate files are not required to be preserved; if we are compiling a single C source file to an executable, then the only output file we are interested in is the executable, not the intermediate files created during the compilation process. For this reason TCC creates a temporary directory in which to put these intermediate files, and removes this directory when the compilation is complete. All intermediate files are put into this temporary directory except:

  • those which are an end product of the compilation (such as the executable),

  • those which are explicitly ordered to be preserved by means of command-line options,

  • binary object files, when more than one such file is produced (this is for compatibility with CC).

TCC can be made to preserve intermediate files of various types by means of the -Ptype... command-line option, which specifies a list of letters corresponding to the file types to be preserved. Thus for example -Pjt specifies that all TDF capsules produced, whether target independent or target dependent, (i.e. all .j and .t files) should be preserved. The special form -Pa specifies that all intermediate files should be preserved. It is also possible to specify that a certain file type should not be preserved by preceding the corresponding letter by - in the -P option. The only really useful application of this is to use -P-o to cancel the CC convention on preserving binary object files mentioned above.

By default, all preserved files are stored in the current working directory. However the -work dir command-line option specifies that they should be stored in the directory dir.

The compilation can also be halted at any stage. The -Ftype option to TCC tells it to stop the compilation after creating the files of the type corresponding to the letter type. Because any files of this type which are produced will be an end product of the compilation, they will automatically be preserved. For example, -Fo halts the compilation after the creation of the binary object, or .o, files (i.e. just before the system linking), and preserves all such files produced. A number of other TCC options are equivalent to options of the form -Ftype:

-i is equivalent to -Fj (i.e. just apply the producer),
-S is equivalent to -Fs (CC compatibility),
-c is equivalent to -Fo (CC compatibility).

If more than one -F option (including the equivalent options just listed) is given, then TCC issues a warning. The stage coming first in the compilation path takes priority.

If the compilation has precisely one end product output file, then the name of this file can be specified to be file by means of the -o file command-line option. If a -o file option is given when there is more than one end product, then the first such file produced will be called file, and all such files produced subsequently will cause TCC to issue a warning.

Target-independent Target-dependent C source .c tdfc tdfc -E Preprocessed C .i tdfc C++ source .c/.cc/.cpp/.C tcpplus tcpplus -E Preprocessed C++ .i/.ii/.ipp/.I tcpplus Target-independent TDF .j tld arch arch disp tnc tld TDF archive .ta Target-independent TDF notation .p Target-independent TDF .j tld Target-dependent TDF .t disp tnc trans Target-dependent TDF notation .p Assembly source .s as Binary object .o ld Executable a.out
Figure 1. TDF Full Compilation Path

1.5. Other Compilation Paths

So far we have been discussing the main TCC compilation path from C source to executable. This is however only part of the picture. The full complexity (almost) of all the possible compilation paths supported by TCC is shown in Fig. 4. This differs from Fig. 3 in that it only shows the left hand, or program, half of the main compilation diagram. The solid arrows show the default compilation paths; the dashed arrows are only followed if TCC is so instructed by means of command-line options. Let us consider those paths in this diagram which have not so far been mentioned.

1.5.1. Preprocessing

The first paths to be considered involve preprocessed C source files. These form a distinct file type which TCC recognises by means of the .i file suffix. Input .i files are treated in exactly the same way as .c files; that is, they are fed into the producer.

TCC can be made to preprocess the C source files it is given by means of the -P and -E options. If the -P option is given then each .c file is transformed into a corresponding .i file by the TDF C preprocessor, tdfcpp. If the -E option is given then the output of tdfcpp is sent instead to the standard output. In both cases the compilation halts after the preprocessor has been applied. Preprocessing is discussed further in section 5.6.

1.5.2. TDF Archives

The second new file type introduced in Fig. 4 is the TDF archive. This is recognised by TCC by means of the .ta file suffix. Basically a TDF archive is a set of target independent TDF capsules (this is slightly simplified, see section 5.2.3 for more details). Any input TDF archives are automatically split into their constituent target independent capsules. These then join the main compilation path in the normal way.

In order to create a TDF archive, TCC must be given the -prod command-line option. It will combine all the target independent TDF capsules it has into an archive, and the compilation will then halt. By default this archive is called a.ta, but another name may be specified using the -o option.

The routines for splitting and building TDF archives are built into TCC, and are not implemented by a separate compilation tool (in particular, TDF archives are not ar archives). Really TDF archives are a TCC-specific construction; they are not part of TDF proper.

1.5.3. TDF Notation

TDF has the form of an abstract syntax tree which is encoded as a series of bits. In order to examine the contents of a TDF capsule it is necessary to translate it into an equivalent human readable form. Two tools are provided which do this. The TDF pretty printer, disp, translates TDF into text, whereas the TDF notation compiler, TNC, both translates TDF to text and text to TDF. The two textual forms of TDF are incompatible - disp output cannot be used as TNC input. disp is in many ways the more sophisticated decoder - it understands the TDF extensions used to handle diagnostics, for example - but it does not handle the text to TDF translation which TNC does. By default TNC is a text to TDF translator, it needs to be passed the -p flag in order to translate TDF into text. We refer to the textual form of TDF supported by TNC as TDF notation.

By default, TCC uses disp. If it is given the -disp command-line option then all target independent TDF capsules (.j files) are transformed into text using disp. The -disp_t option causes all target dependent TDF capsules (.t files) to be transformed into text. In both cases the output files have a .p suffix, and the compilation halts after they are produced.

In order for TNC to be used, the -Ytnc flag should be passed to TCC. In this case the -disp and the -disp_t option cause, not disp, but tnc -p, to be invoked. But this flag also causes TCC to recognise files with a .p suffix as TDF notation source files. These are translated by TNC into target independent TDF capsules, which join the main compilation path in the normal way.

Similarly if the -Ypl_tdf flag is passed to TCC then it recognises files with a .tpl suffix as PL_TDF source files. These are translated by the PL_TDF compiler, TPL, into target independent TDF capsules.

disp and TNC are further discussed in section 5.7.

1.5.4. Merging TDF Capsules

The final unexplored path in Fig. 4 is the ability to combine all the target independent TDF capsules into a single capsule. This is specified by means of the -M command-line option to TCC. The combination of these capsules is performed by the TDF linker, TLD. Whereas in the main compilation path TLD is used to combine a single target independent TDF capsule with the TDF libraries to form a target dependent TDF capsule, in this case it is used to combine several target independent capsules into a single target independent capsule. By default the combined capsule is called a.j. The compilation will continue after the combination phase, with the resultant capsule rejoining the main compilation path. This merging operation is further discussed in section 5.2.2.

The only unresolved issue in this case is, if the -M option is given, to what .j files do the -Fj and the -Pj options refer? In fact, TCC takes them to refer to the merged TDF capsule rather than the capsules which are merged to form it. The -Pa option, however, will cause both sets of capsules to be preserved.

To summarise, TCC has an extra three file types, and an extra three compilation tools (not including the TDF archive creating and splitting routines which are built into TCC). These are:

*.iPreprocessed C source
*.taTDF archives
*.pTDF notation source


6.C preprocessor (tdfcpp)cC sourcePreprocessed C source
7a.Pretty printer (disp)dTDF capsuleTDF notation
7b.Reverse notation (tnc -p)dTDF capsuleTDF notation
8.Notation compiler (tnc)dTDF notationTDF capsule

(see 7.1 and 7.2 for complete lists).

1.6. Finding out what tcc is doing

With so many different file types and alternative compilation paths, it is often useful to be able to keep track of what TCC is doing. There are several command-line options which do this. The simplest is -v which specifies that TCC should print each command in the compilation process on the standard output before it is executed. The -vb option is similar, but only causes the name of each input file to be printed as it is processed. Finally the -dry option specifies that the commands should be printed (as with -v) but not actually executed. This can be used to experiment with TCC to find out what it would do in various circumstances.

Occasionally an unclear error message may be printed by one of the compilation tools. In this case the -show_errors option to TCC might be useful. It causes TCC to print the command it was executing when the error occurred. By default, if an error occurs during the construction of an output file, the file is removed by TCC. It can however be preserved for examination using the -keep_errors option. This applies not only to normal errors, but also to exceptional errors such as the user interrupting TCC by pressing ^C, or one of the compilation tools crashing. In the latter case, TCC will also remove any core file produced, unless the -keep_errors option is specified.

For purposes of configuration control, the -version flag will cause TCC to print its version number. This will typically be of the form:

tcc: Version: 4.0, Revision: 1.5, Machine: hp

giving the version and revision number, plus the target machine identifier. The -V flag will also cause each compilation tool to print its version number (if appropriate) as it is invoked.

2. TCC Environments

  1. 2.1. The Environment Search Path
  2. 2.2. The Default Environment: Configuring tcc
  3. 2.3. Using Environments to Specify APIs
  4. 2.4. Using Environments to Implement tcc Options
  5. 2.5. User-Defined Environments

In addition to command-line options, there is a second method of specifying TCC's behaviour, namely TCC environments.

An environment is just a file consisting of lines of the form:


where * stands for one of the environment prefixes, +, < and > (in fact ? is also a valid environment prefix. It is used to query the values represented by environmental identifiers. If TCC is invoked with the -Ystatus command-line option it will print the values of all the environmental identifiers it recognises). Any line in the environment not beginning with one of these characters is ignored. IDENTIFIER will be one of the environmental identifiers recognised by TCC, the environment prefix will tell TCC how to modify the value given by this identifier, and text what to modify it by.

The simplest environmental identifiers are those which are used to pass flags to TCC and the various components of the compilation system. The line:

+FLAG "text"

causes text to be interpreted by TCC as if it was a command-line option. Similarly:

+FLAG_TDFC "text"

causes text to be passed as an option to TDFC. There are similar environmental identifiers for each of the components of the compilation system (see 7.6 for a complete list).

The second class of environmental identifiers are those corresponding to simple string variables. Only the form:


is allowed. This will set the corresponding variable to text. The permitted environmental identifiers and the corresponding variables are:

ENVDIRThe default environments directory (see section 4.1)
PORTABILITYThe producer portability table (see section 5.1.3)
TEMPThe default temporary directory (see section 6.4)

The final class of environmental identifiers are those corresponding to lists of strings. Firstly text is transformed into a list of strings, b say, by splitting at any spaces, then the list corresponding to the identifier, a say, is modified by this value. How this modification is done depends on the environment prefix:

+a = b
>a = a + b
<a = b + a

where + denotes concatenation of lists. The lists represented in this way include those giving the pathnames of the executables of the various compilation components (plus default flags). These are given by the identifiers TDFC, TLD, etc. (see 7.6 for a complete list). The other lists can be divided between those affecting the producer, the TDF linker, and the system linker respectively (see sections 5.1, 5.2 and 5.5 for more details):

INCLlist of default producer include file directories (as -I options)
STARTUPlist of default producer start-up files (as -f options)
STARTUP_DIRlist of default producer start-up directories (as -I options)
LIBlist of default TDF libraries (as -l options)
LINKlist of default TDF library directories (as -L options)
CRT0list of default initial .o files
CRT1second list of default initial .o files
CRTNlist of default final .o files
SYS_LIBlist of default system libraries (as -l options)
SYS_LIBClist of default standard system libraries (as -l options)
SYS_LINKlist of default system library directories (as -L options)

2.1. The Environment Search Path

The command-line option -Yenv tells TCC to read the environment env. If env is not a full pathname then it is searched for along the environment search path. This consists of a colon-separated list of directories, the initial segment of which is given by the system variable TCCENV (we use the term system variable to describe TCCENV rather than the more normal environmental variable to avoid confusion with TCC environments) if this is defined, and the final segment of which consists of the default environments directory, which is built into TCC at compile-time, and the current working directory. The option -vd causes TCC to print this environment search path. If the environment cannot be found, then a warning is issued.

2.2. The Default Environment: Configuring tcc

The most important environment is the default environment, which is built into TCC at compile-time. This does not mean that the default environment is read every time that TCC is invoked, but rather that it is read once (at compile-time) to determine the default configuration of TCC.

The information included in the default environment includes: the pathnames and default flags of the various components of the compilation system; the target machine type; the default temporary directory; the specification of the target independent headers, TDF libraries and system libraries comprising the default API (which is always ANSI); the variables specifying the default compilation mode; the default environments directory (mentioned above).

TCC is designed to work on many different target machines. All the information on where the executables, include files, TDF libraries etc. are located on a particular machine is stored in the standard environments, and in particular, the default environment. The interaction with the system assembler and, more importantly, the system linker is also expressed using environments.

2.3. Using Environments to Specify APIs

Another important use of environments concerns their use in specifying APIs. As was mentioned above, an API may be considered to have three components: the target independent headers, giving an abstract description of the API to the producer, and the TDF libraries and system libraries, giving the details of the API implementation to the installer. Environments are an ideal medium for expressing this information. The INCL environmental identifier can be used to specify the location of the target independent headers, LIB and LINK the location of the TDF libraries, and SYS_LIB and SYS_LINK the location of the system libraries. Moreover, all this information can be canned into a single command-line option.

By default, programs are checked against the standard ISO C API as specified in the ISO C standard Chapter 7. Other APIs are specified by passing the -Yapi-name flag to TCC, where api-name is one of the API designators listed below. APIs fall into two categories: base APIs and extension APIs. If more than one base API is specified to TCC, only the last one is used for checking; the others are ignored. Additional extension APIs, however, may be used in addition to any suitable base API.

A number of standard APIs have been described as target independent headers and are provided with the TDF system. A TCC environment is provided for each of these APIs (for example, ansi, posix, xpg3 - see 7.5 for a complete list, also see section 6.3). There is an important distinction to be made between base APIs (for example, POSIX) and extension APIs (for example, X11 Release 5). The command-line option -Yposix sets the API to be precisely POSIX, whereas the option -Yx5_lib sets it to the existing API plus the X11 Release 5 basic X library. This is done by using +INCL etc. in the posix environment to set the various variables corresponding to these environmental identifiers to precisely the values for POSIX, but <INCL etc. in the x5_lib environment to extend these variables by the values for X11 Release 5. Thus, to specify the API POSIX plus X11 Release 5, the command-line options -Yposix -Yx5_lib are required (in that order).

All the standard API environments provided also contain lines which set, or modify, the INFO environmental identifier. This contains textual information on the API, including API names and version numbers. This information can be printed by invoking TCC with the -info command-line option. For example, the command-line options:

% tcc -info -Yposix -Yx5_lib

cause the message:

tcc: API is X11 Release 5 Xlib plus POSIX (1003.1).

to be printed.

As was mentioned above, the default API is C89. Thus invoking TCC without specifying an API environment is equivalent to giving the -Yc89 command-line option. On the basis that, when it comes to portability, explicit decisions are better than implicit ones, the use of -Yc89 is recommended.

2.4. Using Environments to Implement tcc Options

Another use to which environments are put is to implement certain TCC command-line options. In particular, some options require different actions depending on the target machine. It is far easier to implement these by means of an environment, which can be defined differently on each target machine, rather than by trying to build all the alternative definitions into TCC.

An important example is the -g flag, which causes the generation of information for symbolic debugging. Depending on the target machine, different flags may need to be passed to the assembler and system linker when -g is specified, or the default .o files and libraries used by the linker may need to be changed. For this reason TCC uses a standard environment, tcc_diag, to implement the -g option.

For a complete list of those options which are implemented by means of environments, see 7.7. If the given option is not supported on a particular target machine, then the corresponding environment will not exist, and TCC will issue a warning to that effect.

2.5. User-Defined Environments

The TCC user can also set up and use environments. It is anticipated that this facility will be used mainly to group a number of TCC command-line options into an environment using the FLAG environmental identifier and to set up environments corresponding to user-defined APIs.

3. Component of the TDF System

  1. 3.1. The C to TDF Producer
    1. 3.1.1. Include File Directories
    2. 3.1.2. Start-up Files and End-up Files
    3. 3.1.3. Compilation Modes and Portability Tables
    4. 3.1.4. Description of Compilation Modes
  2. 3.2. The TDF Linker
    1. 3.2.1. The Linker and TDF Libraries
    2. 3.2.2. Combining TDF Capsules
    3. 3.2.3. Constructing TDF Libraries
    4. 3.2.4. Useful TLD Options
  3. 3.3. The TDF to Target Translator
    1. 3.3.1. TCC Options Affecting the Translator
    2. 3.3.2. Useful trans Options
    3. 3.3.3. Optimisation in TDF Translators
    4. 3.3.4. The Mips Translator and Assembler
  4. 3.4. The System Assembler
  5. 3.5. The System Linker
    1. 3.5.1. The System Linker and TCC Environments
    2. 3.5.2. The Effect of Command-Line Options on the System Linker
  6. 3.6. The C Preprocessor
  7. 3.7. The TDF Pretty Printer
  8. 3.8. The TDF Archiver

3.1. The C to TDF Producer

We now turn to the individual components of the TDF system. Most of the command-line options to TCC so far discussed have been concerned with controlling the behaviour of TCC itself. Another, even more important, class of options concern the ways in which the behaviour of the components can be specified. The -Wtoolopt, ... command-line option for communicating directly with the components has already been mentioned. This however is not recommended for normal purposes; the other TCC command-line options give a more controlled access to the components.

The first component to be considered is the C → TDF producer, TDFC. This translates an input C source file (a .c file or a .i file) into a output target independent TDF capsule (a .j file).

3.1.1. Include File Directories

The most important producer options are those which tell it where to search for files included using a #include preprocessing directive. As with CC, the user can specify a directory, dir, to search for these files using the -Idir command-line option. However, unlike CC, the producer does not search /usr/include as default. Instead, the default search directories are those containing the target independent headers for the API selected, as given by the INCL identifier in the environment describing the API. In addition, the directories to search for the default start-up files (see below), as given by the STARTUP_DIR environmental identifier, are also passed to the producer.

If the -H option is passed to TCC then it will cause the producer to print the name of each file it opens. This is often helpful if a multiplicity of -I options leads to confusion.

3.1.2. Start-up Files and End-up Files

The producer has a useful feature of start-up and end-up files. The TCC command-line option -ffile is equivalent to inserting the line:

#include "file"

at the start of each input C source file. Similarly -efile is equivalent to inserting this line at the end of each such file. These included files are searched for along the directories specified by the -I options in the normal manner.

TCC generates a producer start-up file, called tcc_startup.h, in order to implement certain command-line options. The CC-compatible options:

-Dname -Dname=value -Uname -Astr

are translated into the lines:

#define name 1 #define name value #undef name #assert str

respectively. TCC does not check that these lines are valid C preprocessing directives since this will be done by the producer. So any producer error message referring to tcc_startup.h is likely actually to refer to the -D, -U and -A command-line options. In case of difficulties, tcc_startup.h can be preserved for closer examination using the -Ph option to TCC.

There may be default start-up options specified by the STARTUP environmental identifier. The purpose of these is discussed below. The order the start-up options are passed to the producer is: firstly, the default start-up options; secondly, the start-up option for the TCC built-in start-up file, tcc_startup.h; thirdly, any command-line start-up options. (For technical reasons, a -no_startup_options command-line option is provided which causes no start-up or end-up options to be passed to TDFC. This is not likely to prove useful in normal use.

3.1.3. Compilation Modes and Portability Tables

We have already described how one aspect of the compilation environment, the API, is specified to the producer by means of the default -I options. But another aspect, the control of the syntax and portability checks applied by the producer, can also be specified in a fairly precise manner.

The producer accepts a number of #pragma statements which tell it which portability checks to apply and which syntactic extensions to ISO/ANSI C to allow (see [3] and [2]). These can be inserted into the main C source, but the ideal place for them is in a start-up file. This is the purpose of the STARTUP environmental identifier, to give a list of default start-up files containing #pragma statements which specify the default behaviour of the producer.

In fact not all the information the producer requires is obtained through start-up files. The basic information on the minimum sizes which can be assumed for the basic integer types is passed to the producer by means of another type of file, the portability table. This is specified by means of the PORTABILITY environmental identifier. There are in fact only two portability tables provided, bounds/, which specifies the minimum sizes permitted by the ANSI C89 standard, and bounds/, which specifies the minimum sizes found on most 32-bits machines. The main difference between the two is that in ISO/ANSI it is stated that int is only guaranteed to have 16 bits, whereas on 32-bits machines it has at least 32 bits.

A number of TCC command-line options are concerned with specifying the compilation environment to the producer. The main option for setting the compilation mode is -Xmode. A number of different modes are available:

-XsStrict ISO/ANSI C with extra portability checks
-XpStrict ISO/ANSI C with minimal portability checks
-XcStrict ISO/ANSI C with no extra portability checks
-XaISO/ANSI C with various syntactic extensions
-XtTraditional C

The default is -Xc. For a precise description of each of these modes, see [3]. In addition the command-line options -not_ansi and -nepc can be used to modify the basic compilation modes. -not_ansi specifies that certain non-ANSI syntactic constructions should be allowed. -nepc switches off the producer's extra portability checks (it also suppresses certain constant overflow checks in the TDF translators). All these options are implemented by start-up files.

Two built-in portability tables are provided by TCC. The default reflects the minimal requirements laid down in the ISO C89 standard. The 32-bit portability table (specified by the passing the -Y32bit option to tcc -ch) reflects the implementation on most modern 32 bit machines. These tables are shown below.

ISO/ANSI (default)-Y32bit
Table 1. ISO/ANSI Minimum Requirements Portability Table

The portability table to be used is specified separately by means of an environment. The default is the ISO/ANSI portability table, but -Y32bit or -Ycommon can be used to specify 32-bit checking. -Y16bit will restore the portability table to the default. Note that all checks involving the portability table are switched off by the -nepc command-line option, so in this case no portability table is specified to the producer.

3.1.4. Description of Compilation Modes

Let us briefly describe the compilation modes introduced in the previous section. The following tables describe some of the main features of each mode. The list of pre-defined macros is complete (other than the built-in macros, __FILE__, __LINE__, __DATE__ and __TIME__; because the producer is designed to be target independent it does not define any of the machine name macros which are built into CC. The CC-compatible option, -A-, which is meant to cause all pre-defined macros (other than those beginning with __) to be undefined, and all pre-assertions to be unasserted, is ignored by TCC. In the standard compilation modes there are no such macros and no such assertions. The integer promotion rules are either the arithmetic rules specified by ISO/ANSI or the "traditional" signed promotion rules. The precise set of syntactic relaxations to the ISO/ANSI standard allowed by each mode varies. For a complete list see [3]. The -not_ansi command-line option can be used to allow further relaxations. The extra prototype checks cause the producer to construct a prototype for procedures which are actually traditionally defined. This is very useful for getting prototype-like checking without having to use prototypes in function definitions. This, and other portability checks, are switched off by the -nepc option. Finally, the additional checks are lint-like checks which are useful in detecting possible portability problems.

ModePre-defined MacrosInteger PromotionsRelaxationsExtra Checks
-Xs__STDC__ = 1ISO/ANSInoneyes *
-Xp__STDC__ = 1ISO/ANSInonesome *
-Xc__STDC__ = 1ISO/ANSInonenone
-Xa__STDC__ = 1ISO/ANSIsyntacticnone
-Xt__STDC__ = 0signedsyntacticnone

* Includes extra prototype checks.

All the above -X* modes provide the pre-defined macros __ANDF__ = 1 and __TenDRA__ = 1.

The choice of compilation mode very much depends on the level of checking required. -Xa is suitable for general compilation, and -Xc. -Xp and -Xs for serious program checking (although some may find the latter excessive). -Xt is provided for CC compatibility only; its use is discouraged.

The recommended method of proceeding is to define your own compilation mode. In this way any choices about syntax and portability checking are made into conscious decisions. One still needs to select a basic mode to form the basis for this user-defined mode. -Xc is probably best; it is a well-defined mode (the definition being the ISO/ANSI standard) and so forms a suitable baseline. Suppose that, on examining the program to be compiled, we decide that we need to do the following:

  • allow the #ident directive,

  • allow through unknown escape sequences with a warning,

  • warn of uses of undeclared procedures,

  • warn of incorrect uses of simple return statements.

The first two of these are syntactic in nature. The third is more interesting. ISO/ANSI says that any undeclared procedures are assumed to return int. However for strict API checking we really need to know about these undeclared procedures, because they may be library routines which are not part of the declared API. The fourth condition is a simple lint-like check that no procedure which is declared to return a value contains a simple return statement (without a return value).

To tell the producer about these options, it is necessary to have them included in every source file. The easiest way of doing this is by using a start-up file, check.h say, containing the lines:

#pragma TenDRA begin
#pragma TenDRA directive ident allow
#pragma TenDRA unknown escape warning
#pragma TenDRA implicit function declaration warning
#pragma TenDRA incompatible void return warning

The second, third, fourth and fifth lines correspond to the statements above (see [3]). The first line indicates that this file is defining a new checking scope.

Once the compilation mode has been described in this way, it needs to be specified to TCC in the form of the command-line options -Xc -fcheck.h.

3.2. The TDF Linker

The next component of the system to be considered is the TDF linker, TLD. This is used to combine several TDF capsules or TDF libraries into a single TDF capsule. It is put to two distinct purposes in the TCC compilation scheme. Firstly, in the main compilation path, it is used in the installer half to combine a target independent TDF capsule (a .j file) with the TDF libraries representing the API implementation on the target machine, to form a target dependent TDF capsule (a .t file). Secondly, if the -M option is given to TCC, it is used in the producer half to combine all the target independent TDF capsules (.j files) into a single target independent capsule. Let us consider these two cases separately.

3.2.1. The Linker and TDF Libraries

In the main TDF linking phase, combining target independent capsules with TDF libraries to form target dependent capsules, two pieces of information need to be specified to TLD. Firstly, the TDF libraries to be linked with, and, secondly, the directories to search for these libraries. For standard APIs, the location of the TDF libraries describing the API implementation is given in the environment corresponding to the API. The LIB identifier gives the names of the TDF libraries, and the LINK identifier the directories to be searched for these libraries. The user can also specify libraries and library directories by means of command-line options to TCC. The option -jstr indicates that the TDF library should be used for linking (.tl is the standard suffix for TDF libraries). The option -Jdir indicates that the directory dir should be added to the TDF library search path. Libraries and directories specified by command-line options are searched before those given in the API environment.

There is a potential source of confusion in that the TLD options specifying the TDF library and the library directory dir are respectively -lstr and -Ldir. TCC automatically translates command-line -j options into TLD -l options, and command-line -J options into TLD -L options. However the LIB and LINK identifiers are actually lists of TLD options, so they should use the -l and -L forms.

3.2.2. Combining TDF Capsules

The second use of TLD is to combine all the .j files in the producer half of the compilation into a single capsule. This is specified by means of the -M ("merge") command-line option to TCC described in section 3.5.4. By default, the resultant capsule is called a.j. If the -M option is used to merge all the .j files from a very large program, the resultant TDF capsule can in turn be very large. It may in fact become too large for the installer to handle. Interestingly it is often the system assembler rather than TDF translator which has problems.

The -MA ("merge all") option is similar to -M, but will in addition "hide" all the external tag and token names in the resultant capsule, except for the token names required for linking with the TDF libraries and the tag names required for linking with the system libraries (plus main). In effect, all the names which are internal to the program are removed. This means that the -MA option should only be used to merge complete programs. For details on how to use TLD for more selective name hiding, see below.

3.2.3. Constructing TDF Libraries

There is a final use of the TDF linker supported by TCC which has not so far been mentioned, namely the construction of TDF libraries. As has been mentioned, TDF libraries are an indexed set of TDF capsules. TLD, in addition to its linking mode, also has routines for constructing and manipulating TDF libraries. The library construction mode is supported by TCC by means of the makelib environment. This tells TCC to merge all the .j files and then to stop. But it also passes an option to TLD which causes the merged file to be, not a TDF capsule, but a TDF library. Thus the command-line options:

% tcc -Ymakelib -o a.j b.j c.j

cause the TDF capsules a.j, b.j and c.j to be combined into a TDF library,

3.2.4. Useful TLD Options

TLD has a number of options which may be useful to the general user. The -w option, which causes warnings to be printed about undefined tags and tokens, can often provide interesting information; other options are concerned with the hiding of tag and token names. These options can be passed directly to TLD by means of the -WL, opt, ... command-line option to TCC. The TLD options are fully documented on the appropriate manual page.

3.3. The TDF to Target Translator

The next compilation tool to be considered is the TDF translator. This translates an input target dependent TDF capsule (.t file) into an assembly source file (.s) file for the appropriate target machine. This is the main code generation phase of the compilation process; most of the optimisation of code which occurs happens in the translator (some machines also have optimising assemblers).

Although referred to by the generic name of trans, the TDF translators for different target machines in fact have different names. The main division between translators is in the supported processor. However, operating system dependent features such as the precise form of the assembler input, and the symbolic debugger to be supported, may also cause different versions of the basic translator to be required for different machines of the same processor group. The current generation of translators includes the following:

  • The TDF → i386/i486 translator is called trans386. This exists in two versions, one running on SVR4.2 and one on SCO. The two versions differ primarily in the symbolic debugger they support. trans386 has also been ported to several other i386-based machines, including MS-DOS.

  • The TDF → Sparc (Version 7) translator is called sparctrans. This again exists in two versions, one running on SVR4.2 and one on SunOS and Solaris 1. These versions again differ primarily in the symbolic debugger supported.

  • The TDF → Mips (R2000/R3000, little-endian) translator is called mipstrans. This differs from the other translators in that instead of outputting a single .s file, it outputs two files, a binasm file (with a .G suffix) and a symbol table file (with a .T suffix). This is discussed in more detail below. mipstrans runs on Ultrix, but again has two versions. One runs on Ultrix 4.1 and earlier, the other on 4.2 and later. This necessary because of a change in the format of the binasm file between these two releases.

  • The TDF → 68030/68040 translator also exists in two versions. One runs on HP-UX and is called hptrans; the other runs on NeXTStep and is called nexttrans (however the NeXT is not a supported platform because of its lack of standard API coverage). These differ, not only in the symbolic debugger supported, but also in the format of the assembly source output.

This list is not intended to be definitive. Development work is proceeding on new translators all the time. Existing translators are also updated to support new operating systems releases when this is necessary.

3.3.1. TCC Options Affecting the Translator

A number of TCC command-line options are aimed at controlling the behaviour of the TDF translator. The CC-compatible option -Kitem, ... specifies the behaviour indicated by the argument item. Possible values for item, together with the behaviour they specify, include:

PICCauses position independent code to be produced
ieeeCauses strict conformance to the IEEE floating point standard
noieeeAllows non-strict conformance to the IEEE standard
frameSpecifies that a frame pointer should always be used
no_frameSpecifies that frame pointers need not always be used
i386Causes code generation to be tuned for the i386 processor
i486Causes code generation to be tuned for the i486 processor
P5Causes code generation to be tuned for the P5 processor

Obviously not all of these options are appropriate for all versions of trans. Therefore all -K options are implemented by means of environments which translate item into the appropriate trans options. If a certain item is not applicable on a particular target machine then the corresponding environment will not exist, and TCC will print a warning to this effect.

The CC-compatible -Zstr option is similarly implemented by means of environments. On those machines which support this option it can be used to specify the packing of structures. If str is p1 then they are tightly packed, with no padding. Values of p2 and p4 specify padding to 2 or 4 byte boundaries when appropriate.

Finally, the TCC command-line option -wsl causes the translator to make all string literals writable. Again, this is implemented by an environment. For many machines this behaviour is default; for others it requires an option to be passed to the translator.

3.3.2. Useful trans Options

For further specifying the behaviour of trans it may be necessary to pass options to it directly. The command-line options implemented by trans vary from machine to machine. The following options are however common to all translators and may prove useful:

-ESwitches off certain constant overflow checks
-XSwitches off most optimisations
-ZPrints the version number(s) of the input capsule

These options may be passed directly to trans by means of the -Wt, opt, ... command-line option to TCC. The -E option is also automatically invoked when the -nepc command-line option to TCC is used. The manual page for the appropriate version of trans should be consulted for more details on these and other, machine dependent, options.

3.3.3. Optimisation in TDF Translators

As has been mentioned, the TDF translator is the main optimising phase of the TDF compilation scheme. All optimisations are believed to be correct and are switched on by default. Thus the standard CC -O option, which is intended to switch optimisations on, has no effect in TCC except to cancel any previous -g option. If, due to a translator bug, a certain piece of code is being optimised incorrectly, then the optimisations can be switched off by means of the -Wt, -X option mentioned above. However this should not normally be necessary.

3.3.4. The Mips Translator and Assembler

As has been mentioned, the TDF → Mips translator, mipstrans is genuinely exceptional in that it outputs a pair of files for each input TDF capsule, rather than a single assembly source file. The general scheme is shown in Fig. 5.

Target-dependent TDF .t mipstrans Binary symbol table .T as1 Binasm source .G Assembly source .s as Binary object .o
Figure 2. Mips Compilation Path

mipstrans translates each input target dependent TDF capsule, a.t, into a binasm source file, a.G, and an assembler symbol table file, a.T. It may optionally output an assembly source file, a.s, which combines all the information from a.G with part of the information from a.T (it is the remainder of the information in a.T which is the reason why this scheme has to be adopted). The .s file is only produced if TCC is explicit told to preserve .s files by means of one of the command-line options, -Ps, -Pa, -Fs or -S. The two main mipstrans output files, a.G and a.T, are then transformed by the auxiliary Mips assembler, as1, into a binary object file, a.o.

Although they can be preserved for examination, the .G and .T files output by mipstrans cannot subsequently be processed using TCC. If a break in compilation is required at this stage, a .s file should be produced, and then entered as a TCC input file in the normal way. The information lost from the symbol table in this process is only important when symbolic debugging information is required. Input .s files are translated into binary object files by the main Mips assembler, .s, in the normal way.

So, in addition to the main assembler, which is given by the AS environmental identifier, the location of the auxiliary assembler also needs to be specified to TCC. This is done using the AS1 environmental identifier, which is normally defined in the default environment.

3.4. The System Assembler

The system assembler is the stage in the TCC compilation path which is likely to be of least interest to normal users. The assembler translates an assembly source (or .s) file into a binary object (or .o) file. (The exception to this is the Mips auxiliary assembler discussed above.) Most assemblers are straight translation phases, although some also offer peephole optimisation and scheduling facilities. No TCC command-line options are directly concerned with the assembler, however options can be passed to it directly by means of the -Wa, opt, ... command-line option.

3.5. The System Linker

The final stage in the main TCC compilation path is the system linking. The system linker, ld, combines all the binary object files with the system libraries to form a final executable image. By default this executable is called a.out, although this can be changed using the -o command-line option to TCC. In terms of the differences between target machines, the system linker is the most complex of the tools which are controlled by TCC. Our discussion can be divided between those aspects of the linker's behaviour which are controlled by TCC environments, and those which are controlled by command-line options.

3.5.1. The System Linker and TCC Environments

The general form of TCC's calls to ld are as follows:

ld (linker options) -o (output file)     (initial .o files) (binary object files) (final .o files)     (default system library directories) (default system libraries) (default standard libraries)

The linker may require certain default binary object files to be linked into every executable created. These are divided between the initial .o files, which come before the main list of binary object files, and the final .o files, which come after. For technical reasons, the list of initial .o files is split into two; the first list is given by the CRT0 environmental identifier, and the second by CRT1. The list of final .o files is given by the CRTN environmental identifier.

The information on the default system libraries the linker requires is given by three environmental identifiers. SYS_LINK gives a list of directories to be searched for system libraries. This will exclude /lib and /usr/lib which are usually built into ld. These directories will be given as a list of options of the form -Ldir. The default system libraries are divided into two lists. The environmental identifier SYS_LIBC gives the "standard" library options (usually just -lc), and SYS_LIB gives any other default library options. Both of these are given by lists of options of the form -lstr. This option specifies that the linker should search for the library libstr.a if linking statically, or if linking dynamically.

So the main target dependencies affecting the system linker are described in these six environmental variables: CRT0, CRT1, CRTN, SYS_LINK, SYS_LIB and SYS_LIBC. For a given machine these will be given once and for all in the default environment. Standard API environments may modify SYS_LINK and SYS_LIB to specify the location of the system libraries containing the API implementation, although at present this has not been done.

3.5.2. The Effect of Command-Line Options on the System Linker

The most important TCC command-line options affecting the system linker are those which specify the use of certain system libraries. The option -lstr indicates that the system libraries libstr.a (or libstr .so) should be searched for. The option -Ldir indicates that the directory dir should be added to the list of directories searched for system libraries. Both these options are position dependent. They are passed to the system linker in exactly the same position relative to the input files as they were given on the command-line. Thus normally -l (and to a lesser extent -L) options should be the final command-line options given.

The following TCC command-line options are passed directly to ld. A brief description is given of the purpose of each option, however whether or not ld supports this option depends on the target machine. The local ld manual page should be consulted for details.

-Bstrsets library type: str can be dynamic or static
-Gcauses a shared object rather than an executable to be produced
-dncauses dynamic linking to be switched off
-dycauses dynamic linking to be switched on
-hstrcauses str to be marked as dynamic in a shared object
-scauses the resultant executable to be stripped
-ustrcauses str to be marked as undefined
-zstrspecifies error behaviour, depending on str

The position of any -Bstr options on the command-line is significant. These positions are therefore preserved. The position of the other options is not significant. In addition to these options, the -b command-line option causes the default standard system libraries (i.e. those given by the SYS_LIBC environmental identifier) not to be passed to ld.

Other command-line options may affect the system linker indirectly. For example, the -g option may require different default .o files and system libraries, the precise details of which are target dependent. Such options will be implemented by means of environments which will change the values of the environmental identifiers controlling the linker.

3.6. The C Preprocessor

The TDF C preprocessor, TDFCPP, is invoked only when TCC is passed the -E or -P command-line option, as described in section 3.5.1. These both cause all input .c files to be preprocessed, but in the former case the output is send to the standard output, whereas in the latter it is send to the corresponding .i files.

The TDF system differs from most C compilation systems in that preprocessing is an integral part of the producer, TDFC, rather than a preliminary textual substitution phase. This is because of difficulties involved with trying to perform the preprocessing in a target independent manner. Therefore TDFCPP is merely a modified version of TDFC which halts after the preprocessing phase and prints what it has read. This means that the TDFCPP output, while being equivalent to its input, will not correspond at the textual level to the degree which is normal in C preprocessors.

3.7. The TDF Pretty Printer

The TDF pretty printer, disp, and the TDF notation compiler, TNC, have already been discussed in some detail in section 3.5.3. The TDF decoding command-line options, -disp and -disp_t, cause respectively all .j files and all .t files to be decoded into .p files. This decoding is done using disp by default, and with TNC -p if the -Ytnc command-line option is specified. The -Ytnc option also causes any input .p files to be encoded into .j files by TNC.

The pretty printer, disp, can be used as a useful check that a given .j or .t file is a legal TDF capsule. The TDF decoding routines in the TDF linker and the TDF translator assume that their input is a legal capsule. The pretty printer performs more checks and has better diagnostics for illegal capsules. By default disp only decodes capsule units which belong to "core" TDF. Options to decode other unit types can be passed directly to disp by means of the -Wd, opt, ... command-line option to TCC. The potentially useful disp options include:

-ACauses all known unit types to be decoded
-gCauses diagnostic information units to be decoded
-DCauses a binary dump of the capsule to be printed
-UCauses link information units to be decoded
-VCauses the input not to be rationalised
-WCauses a warning to be printed if a token is used before it is declared

The manual page for disp should be consulted for more details.

The TDF notation compiler, TNC, is fully documented in [4].

3.8. The TDF Archiver

A TDF archive is a TCC-specific form intended for software distribution. It consists of a set of target independent TDF capsules (.j files) and a set of TCC command-line options. It is intended that a TDF archive can be produced on one machine, and distributed to, and installed on, a number of target machines.

If a TDF archive is given as an input file to TCC (it will be recognised by its .ta suffix), then it is split into its constituent capsules and options. The options are interpreted as if they had been given on the command-line (unless the -WJ, -no_options flag is specified), and the capsules are treated as input files in the normal way. The archive splitting and archive building routines are both built into TCC; there is no separate TDF archiver tool. Options passed to the archiver using -WJ, opt are interpreted by TCC.

In order to specify that a TDF archive should be created, the -prod flag should be used. This specifies that all target independent capsules (.j files) and all options opt given by a TCC option of the form -WI, opt, ... should be combined into a TDF archive. The compilation process halts after producing this archive. By default the TDF archive created is called a.ta, but this can be changed using the -o option. Normally the names of the capsules comprising the archive are inserted into the archive, but this may be suppressed by the use of the -WJ, -no_names option.

As an example of the kind of option that might be included in an archive, suppose that the production has been done using the POSIX API. Then the installation should also be done using this same API. Alternatively expressed, if a TDF archive has been constructed using the posix environment, then the -Yposix flag should be included in the archive to ensure that the installation also takes place in this same environment. In fact the environments describing the standard APIs have been set up so that this happens automatically. For example, the posix environment contains the line:

+FLAG "-WI,-Yposix"

Another kind of option that it might be useful to include in an archive is a -lstr option. In this way all the information on the install-time options can be specified at produce-time.

A final example of an option which might be included in an archive is the -message option. The command-line option -message str causes TCC to print the message str with any @ characters in str replaced by spaces (there are problems with escaping spaces). So, by using the command-line option:


one can produce an archive which prints a message as it is installed. This option is also useful in environments. By inserting the line:

+FLAG "-message Reading@tcc@environment@..."

one can produce an environment which prints a message whenever it is read.

4. Miscellaneous Topics

  1. 4.1. Intermodular Checks
  2. 4.2. Debugging and Profiling
  3. 4.3. The System Environment
  4. 4.4. The Temporary Directory

In this section we draw together a number of miscellaneous topics not so far covered.

4.1. Intermodular Checks

All of the extra compiler checks described in section 5.1.3 refer to a single C source file, however TCC also has support for a number of intermodular checks. These checks are enabled by means of the -im command-line option. This causes the producer to create for each C source file, in addition to its TDF capsule output file, a second output file, called a C spec file, containing a description of the C objects declared in that file. This C spec file is kept associated with the target independent TDF as it is transformed to a target dependent capsule, an assembly source file, and a binary object file. When these binary object files are linked then the associated C spec files are also linked using the C spec linker, spec_linker, into a single C spec file. This file is named a.k by default. It is this linking process which constitutes the intermodular checking (in fact spec_linker may also be invoked at the TDF merging level when the -M option is used).

When intermodular checks are specified, TCC will also recognise input files with a .k suffix as C spec files and pass them to the C spec linker.

The nature of the association between a C spec file and its binary object file needs discussion. While these files are internal to a single call of TCC it can keep track of the association, however if the compilation is halted before linking it needs to preserve this association. For example in:

% tcc -im -c a.c

the binary object file a.o and the C spec file a.k need to be kept together. This is done by forming them into a single archive file named a.o. When a.o is subsequently linked, TCC recognises that it is an archive and splits it into its two components, one of which it passes to the system linker, and one to the C spec linker.

Intermodular checking is described in more detail in [3]. In tcc -ch intermodular checking is on by default, but may be switched off using -im0.

4.2. Debugging and Profiling

TCC supports options for both symbolic debugging using the target machine's default debugger, and profiling using prof on those machines which have it.

The -g command-line option causes the producer to output extra debugging information in its output TDF capsule, and the TDF translator to translate this information into the appropriate assembler directives for its supported debugger (for details of which debuggers are supported by which translators, consult the appropriate manual pages).

For the translator to have all the diagnostic information it requires, not only the TDF capsules output by the producer, but also those linked in by the TDF linker from the TDF libraries, need to contain this debugging information. This is ensured for the standard TDF libraries by having two versions of each library, one containing diagnostics and one not.

By default the environmental identifier LINK, which gives the directories which the TDF linker should search, is set so that the non-diagnostic versions are found. However the -g option modifies LINK so that the diagnostic versions are found first.

Depending on the target machine, the -g option may also need to modify the behaviour of the system assembler and the system linker. Like all potentially target dependent options, -g is implemented by means of a standard environment, in this case tcc_diag.

The -p option is likewise implemented by means of a standard environment, tcc_prof. It causes the producer to output extra information on the names of statically declared objects, and the TDF translator to output assembler directives which enable prof to profile the number of calls to each procedure (including static procedures). The behaviour of the system assembler and system linker may also be modified by -p, depending on the target machine.

4.3. The System Environment

In section 4.3 we discussed how TCC environments can be used to specify APIs. There is one API environment however which is so exceptional that it needs to be treated separately. This is the system environment, which specifies that TCC should emulate CC on the machine on which it is being run.

The system environment specifies that TCC should use the system headers directory, /usr/include, as its default include file directory, and should define all the machine dependent macros which are built into CC. It will also specify the 32-bit portability table on 32-bit machines.

Despite the differences from the normal API environments, the system environment is indeed specifying an API, namely the system headers and libraries on the host machine. This means that the .j files produced when using this environment are only target independent in the sense that they can be ported successfully to machines which have the exactly the same system headers and predefined macros.

Using the system headers is fraught with difficulties. In particular, they tend to be very CC-specific. It is often necessary to use the -not_ansi and -nepc options together with -Ysystem merely to negotiate the system headers. Even then, TCC may still reject some constructs. Of course, the number of problems encountered will vary considerably between different machines.

To conclude, the system environment is at best only suitable for experimental compilation. There are also potential problems involved with its use. It should therefore be used with care.

4.4. The Temporary Directory

As we have said, TCC creates a temporary directory in which to put all the intermediate files which are created, but are not to be preserved. By default, these intermediate files are left in the temporary directory until the end of the compilation, when the temporary directory is removed. However, if disk space is short, or a particularly large compilation is taking place, the -tidy command-line option may be appropriate. This causes TCC to remove each unwanted intermediate file immediately when it is no longer required.

The name of the temporary directory created by TCC to store the intermediate files is generated by the system library routine tempnam. It takes the form TEMP/tcc????, where TEMP is the main TCC temporary directory, and ???? is an automatically generated unique suffix. There are three methods of specifying TEMP, listed in order of increasing precedence:

  1. by the TEMP environmental identifier (usually in the default environment),

  2. by the -temp dir command-line option,

  3. by the TMPDIR system variable.

Normally TEMP will be a normal temporary directory, /tmp or /usr/tmp for example, but any directory to which the user has write permission may be used. In general, the more spare disk space which is available in TEMP, the better.

[1] TDF and Portability, DRA, 1994. [2] The C to TDF Producer, DRA, 1993. [3] The TenDRA Static Checker, DRA, 1994. [4] The TDF Notation Compiler, DRA, 1994.