3. Building

  1. 3.1. Building APIs
  2. 3.2. Production of TDF
  3. 3.3. Installation of TDF

3.1. Building APIs

The API checking is one of the more interesting areas of TenDRA. An overview of the process of building APIs is given in . This diagram expands on the top-right and bottom-right quadrants of the TDF compilation phases described in TDF and Portability.

API Spec Transcription Tspec Abstract API Description tspec/{base,extension}/ $api/*.tspec Transformation tspec Target-independent API headers (tspec "include output file") $PREFIX_TSPEC/TenDRA/ include/$api/*.h A Target-independent API compilation rig (tspec "source output file") tspec/{base,extension}/ $api/*.tspec System headers /usr/include/*.h Included after hacks (if any) and after startup headers Production tcc -Ymakelib Startup headers osdep/machines/$os/$cpu/ startup/$api.h These set various assertions and define __$os__ etc Hacked includes osdep/machines/$os/$cpu/ include/$api.h These go on to include sys. headers by #include_next #include_next API TDF capsules osdep/obj/machines/$os/ $cpu/api/apis/$api.api/*.j TDF linking tld API TDF libraries $PREFIX_API/$api.tl F
Figure 4. Files Involved for Building APIs

An API consists of abstract specifications of a set of APIs[a] which represent a similar level of abstraction that their respective standards represent. For example, size_t for the C89 API is defined to be an unsigned arithmetic type, but exactly which type is left to the implementation. See for details on specifying APIs.

These abstract specifications are converted by tspec into API Source and API Includes. The API Includes contain #pragma token statements which create tokens that correspond to the various things the API defines. Details of these are documented in the tdfc2 guide. These are used later on, during compilation of users' programs.

The generated API Source from tspec contains implementations of just the symbols present in each header for an API (as opposed to all the extensions your system probably provides), guarded by preprocessor conditions. These guards are of a standard form; for example, ssize_t.c from the posix1 API:

/* AUTOMATICALLY GENERATED BY tspec 2.8 */
#ifndef __WRONG_POSIX1
#ifndef __WRONG_POSIX1_SYS_TYPES_H_SSIZE_T
#if #include ( sys/types.h )
#define __BUILDING_TDF_POSIX1_SYS_TYPES_H_SSIZE_T
#include <sys/types.h>
#endif
#endif

#ifndef __BUILDING_TDF_POSIX1_SYS_TYPES_H_SSIZE_T
#pragma TenDRA no token definition allow
#endif
#pragma implement interface <../shared/posix1.api/ssize_t.h>
#endif

In the API specifications fed to tspec, ssize_t is a subset; the __WRONG_POSIX1_SYS_TYPES_H_SSIZE_T guard above is provided so that it may be excluded if your system does not have a compliant implementation of ssize_t.

Non-compliance for a particular machine is indicated by setting __WRONG_* macros in the start-up files for that machine. Hence for ULTRIX, which (apparently) has a ssize_t incompatible to the posix1 API's, defines __WRONG_POSIX1_SYS_TYPES_H_SSIZE_T and hence ssize_t is omitted when compiling the tspec API Source into the API TDF Tokens. See Porting TenDRA to Different Operating Systems for a worked example of making use of these macros.

The compiled API TDF Tokens are linked together into .tl libraries; each library represents an API. As explained above, the contents of these libraries are the intersection of the sets of the things defined in that particular API and what your system provides.

3.2. Production of TDF

Based on the files installed, the process of compilation is outlined in . These steps may be seen by executing tcc -dry.

Portable program source .c/.cc Producer tdfc/tcpplus A Target-independent API headers (tspec "include output file") $PREFIX_TSPEC/TenDRA/ include/$api/*.h Strictness modes $PREFIX_STARTUP/ modes[.cpp]/X* Configuration for error checking and warning levels Integer bounds $PREFIX_STARTUP/ bounds.*/*.h Integer sizes and ranges, signedness of char Integer literal suffixes $PREFIX_STARTUP/ literal/*.h Specification of suffixes, such as 123ULL Integer promotions $PREFIX_STARTUP/ promotion/*.h Rules for integer promotions during implicit conversion Target-independent TDF $PREFIX_TMP/*.j X
Figure 5. Files involved during production

C is used as an example here, though similar things apply for any other producer. The main difference would be in API checking.

It is important to note that during compilation the system headers are not used at all. Instead, the various prototypes and such which would be bought in by #include statements are prepended from the API Includes. These can be seen by running tcc -E:

clarion% tcc -Yc89 -E hello.c
#line 1 "hello.c"
...
#line 13 "$PREFIX_TSPEC/TenDRA/include/shared/c89.api/size_t.h"
...
#pragma token VARIETY unsigned size_t # size_t
#pragma token VARIETY __size_t # __size_t
#pragma promote size_t : __size_t

#pragma no_def size_t __size_t

...
#line 25 "$PREFIX_TSPEC/TenDRA/include/c89.api/stdio.h"
#pragma token EXP rvalue : FILE * : stdin # c89.stdio.stdin
#pragma token EXP rvalue : FILE * : stdout # c89.stdio.stdout
#pragma token EXP rvalue : FILE * : stderr # c89.stdio.stderr
...
#pragma token FUNC int ( __local_printf_string, ... ) : printf # c89.stdio.printf

#line 3 "hello.c"
int main(void) {
        printf("hello, world\n");
        return 0;
}

Here I've omitted most of the things <stdio.h> defines, just to keep the example small.

Note that the contents of the tspec API Includes are portable; they ought to be the same for any system (this should be the case, since they were generated from the tspec API Specification sources, which did not involve anything system-specific). Therefore since these are included verbatim for a given API at the top of a users' C program, we can infer that the TDF capsule produced (foo.jis itself portable. This is what TenDRA is all about: producing a portable binary. The steps following (namely the call to trans and beyond) may therefore be on a different system than the one on which hello.j was produced, even though that system may have a different implementation of the APIs used. As long as the target system provides the same subset in its $api.tl, the code will link and execute as expected. For details on this, see .

3.3. Installation of TDF

The final step of linking also brings in any system-specific libraries which may be required (such as crt0.o), and of course any user-specified libraries, if given. These are illustrated representatively and their exact details differ per platform.

X Target-independent TDF $PREFIX_TMP/*.j TDF linking tld F API TDF libraries $PREFIX_API/$api.tl Portable TDF interface to OS's implementation. e.g. c89.api to libc symbols LPI TDF libraries $PREFIX_LPI/$lpi.tl Platform-specific implement- ation of language-specific TDF constructs, e.g. ~fl_rep CRT TDF libraries (TODO: crtp_n.tpl -> .j provides __PROM_init_list) TODO/crtp_n.j Target-dependent TDF $PREFIX_TMP/*.t Install trans OR Assembler source $PREFIX_TMP/*.s Assemble as Binasm source MIPS & Alpha only $PREFIX_TMP/*.G Assemble as1 Binary symbol table $PREFIX_TMP/*.T Binary object $PREFIX_TMP/*.o Link ld System libraries /lib/*.so, /lib/*.a libc and friends, providing implementation of symbols referenced by $api.tl above System runtime support /lib/*.o crt.o and friends (e.g. ELF entry for .main) TDF runtime support $PREFIX_SYS/libtsl.a 64-bit emulation (CPU- specific implementation) Executable a.out
Figure 6. Files involved during installation
  1. [a]