.HTML "How to Use the Plan 9 C Compiler.TLHow to Use the Plan 9 C Compiler.AURob Pikerob@plan9.bell-labs.com.SHIntroduction.PPThe C compiler on Plan 9 is a wholly new program; in factit was the first piece of software written for what wouldeventually become Plan 9 from Bell Labs.Programmers familiar with existing C compilers will finda number of differences in both the language the Plan 9 compileraccepts and in how the compiler is used..PPThe compiler is really a set of compilers, one for eacharchitecture \(em MIPS, SPARC, Intel 386, Power PC, ARM, etc. \(emthat accept a dialect of ANSI C and efficiently producefairly good code for the target machine.There is a packaging of the compiler that accepts strict ANSI C fora POSIX environment, but this document focuses on thenative Plan 9 environment, that in which all the system source andalmost all the utilities are written..SHSource.PPThe language accepted by the compilers is the core 1989 ANSI C languagewith some modest extensions,a greatly simplified preprocessor,a smaller library that includes system calls and related facilities,and a completely different structure for include files..PPOfficial ANSI C accepts the old (K&R) style of declarations forfunctions; the Plan 9 compilersare more demanding.Without an explicit run-time flag.CW -B ) (whose use is discouraged, the compilers insiston new-style function declarations, that is, prototypes forfunction arguments.The function declarations in the libraries' include files areall in the new style so the interfaces are checked at compile time.For C programmers who have not yet switched to function prototypesthe clumsy syntax may seem repellent but the payoff in stronger typingis substantial.Those who wish to import existing software to Plan 9 are urgedto use the opportunity to update their code..PPThe compilers include an integrated preprocessor that accepts the familiar.CW #include ,.CW #definefor macros both with and without arguments,.CW #undef ,.CW #line ,.CW #ifdef ,.CW #ifndef ,and.CW #endif .Itsupports neither.CW #ifnor.CW ## ,although it doeshonor a few.CW #pragmas .The.CW #ifdirective was omitted because it greatly complicates thepreprocessor, is never necessary, and is usually abused.Conditional compilation in general makes code hard to understand;the Plan 9 source uses it sparingly.Also, because the compilers remove dead code, regular.CW ifstatements with constant conditions are more readable equivalents to many.CW #ifs .To compile imported code ineluctably fouled by.CW #ifthere is a separate command,.CW /bin/cpp ,that implements the complete ANSI C preprocessor specification..PPInclude files fall into two groups: machine-dependent and machine-independent.The machine-independent files occupy the directory.CW /sys/include ;the others are placed in a directory appropriate to the machine, such as.CW /mips/include .The compiler searches for include filesfirst in the machine-dependent directory and thenin the machine-independent directory.At the time of writing there are thirty-one machine-independent includefiles and two (per machine) machine-dependent ones:.CW <ureg.h>and.CW <u.h> .The first describes the layout of registers on the system stack,for use by the debugger.The second defines somearchitecture-dependent types such as.CW jmp_buffor.CW setjmpand the.CW va_argand.CW va_listmacros for handling arguments to variadic functions,as well as a set of.CW typedefabbreviations for.CW unsigned.CW shortand so on..PPHere is an excerpt from.CW /386/include/u.h :.P1#define nil ((void*)0)typedef unsigned short ushort;typedef unsigned char uchar;typedef unsigned long ulong;typedef unsigned int uint;typedef signed char schar;typedef long long vlong; typedef long jmp_buf[2];#define JMPBUFSP 0#define JMPBUFPC 1#define JMPBUFDPC 0.P2Plan 9 programs use.CW nilfor the name of the zero-valued pointer.The type.CW vlongis the largest integer type available; on most architectures itis a 64-bit value.A couple of other types in.CW <u.h>are.CW u32int ,which is guaranteed to have exactly 32 bits (a possibility on all the supported architectures) and.CW mpdigit ,which is used by the multiprecision math package.CW <mp.h> .The.CW #defineconstants permit an architecture-independent (but compiler-dependent)implementation of stack-switching using.CW setjmpand.CW longjmp ..PPEvery Plan 9 C program begins.P1#include <u.h>.P2because all the other installed header files use the.CW typedefsdeclared in.CW <u.h> ..PPIn strict ANSI C, include files are grouped to collect related functionsin a single file: one for string functions, one for memory functions,one for I/O, and none for system calls.Each include file is protected by an.CW #ifdefto guarantee its contents are seen by the compiler only once.Plan 9 takes a different approach. Other than a few includefiles that define external formats such as archives, the files in.CW /sys/includecorrespond to.I libraries.If a program is using a library, it includes the corresponding header.The default C library comprises string functions, memory functions, andso on, largely as in ANSI C, some formatted I/O routines,plus all the system calls and related functions.To use these functions, one must.CW #includethe file.CW <libc.h> ,which in turn must follow.CW <u.h> ,to define their prototypes for the compiler.Here is the complete source to the traditional first C program:.P1#include <u.h>#include <libc.h> voidmain(void){ print("hello world\en"); exits(0);}.P2The.CW printroutine and its relatives.CW fprintand.CW sprintresemble the similarly-named functions in Standard I/O but are notattached to a specific I/O library.In Plan 9.CW mainis not integer-valued; it should call.CW exits ,which takes a string argument (or null; here ANSI C promotes the 0 to a.CW char* ).All these functions are, of course, documented in the Programmer's Manual..PPTo use.CW printf ,.CW <stdio.h>must be included to define the function prototype for.CW printf :.P1#include <u.h>#include <libc.h>#include <stdio.h> voidmain(int argc, char *argv[]){ printf("%s: hello world; argc = %d\en", argv[0], argc); exits(0);}.P2In practice, Standard I/O is not used much in Plan 9. I/O libraries arediscussed in a later section of this document..PPThere are libraries for handling regular expressions, raster graphics,windows, and so on, and each has an associated include file.The manual for each library states which include files are needed.The files are not protected against multiple inclusion and themselvescontain no nested.CW #includes .Instead theprogrammer is expected to sort out the requirementsand to.CW #includethe necessary files once at the top of each source file. In practice this istrivial: this way of handling include files is so straightforwardthat it is rare for a source file to contain more than half a dozen.CW #includes ..PPThe compilers do their own register allocation so the.CW registerkeyword is ignored.For different reasons,.CW volatileand.CW constare also ignored..PPTo make it easier to share code with other systems, Plan 9 has a versionof the compiler,.CW pcc ,that provides the standard ANSI C preprocessor, headers, and librarieswith POSIX extensions..CW Pccis recommended onlywhen broad external portability is mandated. It compiles slower,produces slower code (it takes extra work to simulate POSIX on Plan 9),eliminates those parts of the Plan 9 interfacenot related to POSIX, and illustrates the clumsiness of an environmentdesigned by committee..CW Pccis described in more detail in.IAPE\(emThe ANSI/POSIX Environment,.Rby Howard Trickey..SHProcess.PPEach CPU architecture supported by Plan 9 is identified by a single,arbitrary, alphanumeric character:.CW kfor SPARC,.CW qfor 32-bit Power PC,.CW vfor MIPS,.CW 0for little-endian MIPS,.CW 1for Motorola 68000,.CW 2for Motorola 68020 and 68040,.CW 5for ARM v5 and later 32-bit architectures,.CW 6for AMD64,.CW 7for DEC Alpha,.CW 8for Intel 386, and.CW 9for 64-bit Power PC.The character labels the support tools and files for that architecture.For instance, for the 386 the compiler is.CW 8c ,the assembler is.CW 8a ,the link editor/loader is.CW 8l ,the object files are suffixed.CW \&.8 ,and the default name for an executable file is.CW 8.out .Before we can use the compiler we therefore need to know whichmachine we are compiling for.The next section explains how this decision is made; for the momentassume we are building 386 binaries and make the mental substitution for.CW 8appropriate to the machine you are actually using..PPTo convert source to an executable binary is a two-step process.First run the compiler,.CW 8c ,on the source, say.CW file.c ,to generate an object file.CW file.8 .Then run the loader,.CW 8l ,to generate an executable.CW 8.outthat may be run (on a 386 machine):.P18c file.c8l file.88.out.P2The loader automatically links with whatever libraries the programneeds, usually including the standard C library as defined by.CW <libc.h> .Of course the compiler and loader have lots of options, both familiar and new;see the manual for details.The compiler does not generate an executable automatically;the output of the compiler must be given to the loader.Since most compilation is done under the control of.CW mk(see below), this is rarely an inconvenience..PPThe distribution of work between the compiler and loader is unusual.The compiler integrates preprocessing, parsing, register allocation,code generation and some assembly.Combining these tasks in a single program is part of the reason forthe compiler's efficiency.The loader does instruction selection, branch folding,instruction scheduling,and writes the final executable.There is no separate C preprocessor and no assembler in the usual pipeline.Instead the intermediate object file(here a.CW \&.8file) is a type of binary assembly language.The instructions in the intermediate format are not exactly those inthe machine. For example, on the 68020 the object file may specifya MOVE instruction but the loader will decide just which variant ofthe MOVE instruction \(em MOVE immediate, MOVE quick, MOVE address,etc. \(em is most efficient..PPThe assembler,.CW 8a ,is just a translator between the textual and binaryrepresentations of the object file format.It is not an assembler in the traditional sense. It has limitedmacro capabilities (the same as the integral C preprocessor in the compiler),clumsy syntax, and minimal error checking. For instance, the assemblerwill accept an instruction (such as memory-to-memory MOVE on the MIPS) that themachine does not actually support; only when the output of the assembleris passed to the loader will the error be discovered.The assembler is intended only for writing things that need access to instructionsinvisible from C,such as the machine-dependentpart of an operating system;very little code in Plan 9 is in assembly language..PPThe compilers take an option.CW -Sthat causes them to print on their standard output the generated codein a format acceptable as input to the assemblers.This is of course merely a formatting of thedata in the object file; therefore the assembler is justanASCII-to-binary converter for this format.Other than the specific instructions, the input to the assemblersis largely architecture-independent; see``A Manual for the Plan 9 Assembler'',by Rob Pike,for more information..PPThe loader is an integral part of the compilation process.Each library header file contains a.CW #pragmathat tells the loader the name of the associated archive; it isnot necessary to tell the loader which libraries a program uses.The C run-time startup is found, by default, in the C library.The loader starts with an undefinedsymbol,.CW _main ,that is resolved by pulling in the run-time startup code from the library.(The loader undefines.CW _mainpwhen profiling is enabled, to force loading of the profiling start-upinstead.).PPUnlike its counterpart on other systems, the Plan 9 loader rearrangesdata to optimize access. This means the order of variables in theloaded program is unrelated to its order in the source.Most programs don't care, but some assume that, for example, thevariables declared by.P1int a;int b;.P2will appear at adjacent addresses in memory. On Plan 9, they won't..SHHeterogeneity.PPWhen the system starts or a user logs in the environment is configuredso the appropriate binaries are available in.CW /bin .The configuration process is controlled by an environment variable,.CW $cputype ,with value such as.CW mips ,.CW 386 ,.CW arm ,or.CW sparc .For each architecture there is a directory in the root,with the appropriate name,that holds the binary and library files for that architecture.Thus.CW /mips/libcontains the object code libraries for MIPS programs,.CW /mips/includeholds MIPS-specific include files, and.CW /mips/binhas the MIPS binaries.These binaries are attached to.CW /binat boot time by binding.CW /$cputype/binto.CW /bin ,so.CW /binalways contains the correct files..PPThe MIPS compiler,.CW vc ,by definitionproduces object files for the MIPS architecture,regardless of the architecture of the machine on which the compiler is running.There is a version of.CW vccompiled for each architecture:.CW /mips/bin/vc ,.CW /arm/bin/vc ,.CW /sparc/bin/vc ,and so on,each capable of producing MIPS object files regardless of the nativeinstruction set.If one is running on a SPARC,.CW /sparc/bin/vcwill compile programs for the MIPS;if one is running on machine.CW $cputype ,.CW /$cputype/bin/vcwill compile programs for the MIPS..PPBecause of the bindings that assemble.CW /bin ,the shell always looks for a command, say.CW date ,in.CW /binand automatically finds the file.CW /$cputype/bin/date .Therefore the MIPS compiler is known as just.CW vc ;the shell will invoke.CW /bin/vcand that is guaranteed to be the version of the MIPS compilerappropriate for the machine running the command.Regardless of the architecture of the compiling machine,.CW /bin/vcis.I alwaysthe MIPS compiler..PPAlso, the output of.CW vcLines 1–500 of 1450. Load more
.HTML "How to Use the Plan 9 C Compiler .TL How to Use the Plan 9 C Compiler .AU Rob Pike rob@plan9.bell-labs.com .SH Introduction .PP The C compiler on Plan 9 is a wholly new program; in fact it was the first piece of software written for what would eventually become Plan 9 from Bell Labs. Programmers familiar with existing C compilers will find a number of differences in both the language the Plan 9 compiler accepts and in how the compiler is used. .PP The compiler is really a set of compilers, one for each architecture \(em MIPS, SPARC, Intel 386, Power PC, ARM, etc. \(em that accept a dialect of ANSI C and efficiently produce fairly good code for the target machine. There is a packaging of the compiler that accepts strict ANSI C for a POSIX environment, but this document focuses on the native Plan 9 environment, that in which all the system source and almost all the utilities are written. .SH Source .PP The language accepted by the compilers is the core 1989 ANSI C language with some modest extensions, a greatly simplified preprocessor, a smaller library that includes system calls and related facilities, and a completely different structure for include files. .PP Official ANSI C accepts the old (K&R) style of declarations for functions; the Plan 9 compilers are more demanding. Without an explicit run-time flag .CW -B ) ( whose use is discouraged, the compilers insist on new-style function declarations, that is, prototypes for function arguments. The function declarations in the libraries' include files are all in the new style so the interfaces are checked at compile time. For C programmers who have not yet switched to function prototypes the clumsy syntax may seem repellent but the payoff in stronger typing is substantial. Those who wish to import existing software to Plan 9 are urged to use the opportunity to update their code. .PP The compilers include an integrated preprocessor that accepts the familiar .CW #include , .CW #define for macros both with and without arguments, .CW #undef , .CW #line , .CW #ifdef , .CW #ifndef , and .CW #endif . It supports neither .CW #if nor .CW ## , although it does honor a few .CW #pragmas . The .CW #if directive was omitted because it greatly complicates the preprocessor, is never necessary, and is usually abused. Conditional compilation in general makes code hard to understand; the Plan 9 source uses it sparingly. Also, because the compilers remove dead code, regular .CW if statements with constant conditions are more readable equivalents to many .CW #ifs . To compile imported code ineluctably fouled by .CW #if there is a separate command, .CW /bin/cpp , that implements the complete ANSI C preprocessor specification. .PP Include files fall into two groups: machine-dependent and machine-independent. The machine-independent files occupy the directory .CW /sys/include ; the others are placed in a directory appropriate to the machine, such as .CW /mips/include . The compiler searches for include files first in the machine-dependent directory and then in the machine-independent directory. At the time of writing there are thirty-one machine-independent include files and two (per machine) machine-dependent ones: .CW <ureg.h> and .CW <u.h> . The first describes the layout of registers on the system stack, for use by the debugger. The second defines some architecture-dependent types such as .CW jmp_buf for .CW setjmp and the .CW va_arg and .CW va_list macros for handling arguments to variadic functions, as well as a set of .CW typedef abbreviations for .CW unsigned .CW short and so on. .PP Here is an excerpt from .CW /386/include/u.h : .P1 #define nil ((void*)0) typedef unsigned short ushort; typedef unsigned char uchar; typedef unsigned long ulong; typedef unsigned int uint; typedef signed char schar; typedef long long vlong; typedef long jmp_buf[2]; #define JMPBUFSP 0 #define JMPBUFPC 1 #define JMPBUFDPC 0 .P2 Plan 9 programs use .CW nil for the name of the zero-valued pointer. The type .CW vlong is the largest integer type available; on most architectures it is a 64-bit value. A couple of other types in .CW <u.h> are .CW u32int , which is guaranteed to have exactly 32 bits (a possibility on all the supported architectures) and .CW mpdigit , which is used by the multiprecision math package .CW <mp.h> . The .CW #define constants permit an architecture-independent (but compiler-dependent) implementation of stack-switching using .CW setjmp and .CW longjmp . .PP Every Plan 9 C program begins .P1 #include <u.h> .P2 because all the other installed header files use the .CW typedefs declared in .CW <u.h> . .PP In strict ANSI C, include files are grouped to collect related functions in a single file: one for string functions, one for memory functions, one for I/O, and none for system calls. Each include file is protected by an .CW #ifdef to guarantee its contents are seen by the compiler only once. Plan 9 takes a different approach. Other than a few include files that define external formats such as archives, the files in .CW /sys/include correspond to .I libraries. If a program is using a library, it includes the corresponding header. The default C library comprises string functions, memory functions, and so on, largely as in ANSI C, some formatted I/O routines, plus all the system calls and related functions. To use these functions, one must .CW #include the file .CW <libc.h> , which in turn must follow .CW <u.h> , to define their prototypes for the compiler. Here is the complete source to the traditional first C program: .P1 #include <u.h> #include <libc.h> void main(void) { print("hello world\en"); exits(0); } .P2 The .CW print routine and its relatives .CW fprint and .CW sprint resemble the similarly-named functions in Standard I/O but are not attached to a specific I/O library. In Plan 9 .CW main is not integer-valued; it should call .CW exits , which takes a string argument (or null; here ANSI C promotes the 0 to a .CW char* ). All these functions are, of course, documented in the Programmer's Manual. .PP To use .CW printf , .CW <stdio.h> must be included to define the function prototype for .CW printf : .P1 #include <u.h> #include <libc.h> #include <stdio.h> void main(int argc, char *argv[]) { printf("%s: hello world; argc = %d\en", argv[0], argc); exits(0); } .P2 In practice, Standard I/O is not used much in Plan 9. I/O libraries are discussed in a later section of this document. .PP There are libraries for handling regular expressions, raster graphics, windows, and so on, and each has an associated include file. The manual for each library states which include files are needed. The files are not protected against multiple inclusion and themselves contain no nested .CW #includes . Instead the programmer is expected to sort out the requirements and to .CW #include the necessary files once at the top of each source file. In practice this is trivial: this way of handling include files is so straightforward that it is rare for a source file to contain more than half a dozen .CW #includes . .PP The compilers do their own register allocation so the .CW register keyword is ignored. For different reasons, .CW volatile and .CW const are also ignored. .PP To make it easier to share code with other systems, Plan 9 has a version of the compiler, .CW pcc , that provides the standard ANSI C preprocessor, headers, and libraries with POSIX extensions. .CW Pcc is recommended only when broad external portability is mandated. It compiles slower, produces slower code (it takes extra work to simulate POSIX on Plan 9), eliminates those parts of the Plan 9 interface not related to POSIX, and illustrates the clumsiness of an environment designed by committee. .CW Pcc is described in more detail in .I APE\(emThe ANSI/POSIX Environment, .R by Howard Trickey. .SH Process .PP Each CPU architecture supported by Plan 9 is identified by a single, arbitrary, alphanumeric character: .CW k for SPARC, .CW q for 32-bit Power PC, .CW v for MIPS, .CW 0 for little-endian MIPS, .CW 1 for Motorola 68000, .CW 2 for Motorola 68020 and 68040, .CW 5 for ARM v5 and later 32-bit architectures, .CW 6 for AMD64, .CW 7 for DEC Alpha, .CW 8 for Intel 386, and .CW 9 for 64-bit Power PC. The character labels the support tools and files for that architecture. For instance, for the 386 the compiler is .CW 8c , the assembler is .CW 8a , the link editor/loader is .CW 8l , the object files are suffixed .CW \&.8 , and the default name for an executable file is .CW 8.out . Before we can use the compiler we therefore need to know which machine we are compiling for. The next section explains how this decision is made; for the moment assume we are building 386 binaries and make the mental substitution for .CW 8 appropriate to the machine you are actually using. .PP To convert source to an executable binary is a two-step process. First run the compiler, .CW 8c , on the source, say .CW file.c , to generate an object file .CW file.8 . Then run the loader, .CW 8l , to generate an executable .CW 8.out that may be run (on a 386 machine): .P1 8c file.c 8l file.8 8.out .P2 The loader automatically links with whatever libraries the program needs, usually including the standard C library as defined by .CW <libc.h> . Of course the compiler and loader have lots of options, both familiar and new; see the manual for details. The compiler does not generate an executable automatically; the output of the compiler must be given to the loader. Since most compilation is done under the control of .CW mk (see below), this is rarely an inconvenience. .PP The distribution of work between the compiler and loader is unusual. The compiler integrates preprocessing, parsing, register allocation, code generation and some assembly. Combining these tasks in a single program is part of the reason for the compiler's efficiency. The loader does instruction selection, branch folding, instruction scheduling, and writes the final executable. There is no separate C preprocessor and no assembler in the usual pipeline. Instead the intermediate object file (here a .CW \&.8 file) is a type of binary assembly language. The instructions in the intermediate format are not exactly those in the machine. For example, on the 68020 the object file may specify a MOVE instruction but the loader will decide just which variant of the MOVE instruction \(em MOVE immediate, MOVE quick, MOVE address, etc. \(em is most efficient. .PP The assembler, .CW 8a , is just a translator between the textual and binary representations of the object file format. It is not an assembler in the traditional sense. It has limited macro capabilities (the same as the integral C preprocessor in the compiler), clumsy syntax, and minimal error checking. For instance, the assembler will accept an instruction (such as memory-to-memory MOVE on the MIPS) that the machine does not actually support; only when the output of the assembler is passed to the loader will the error be discovered. The assembler is intended only for writing things that need access to instructions invisible from C, such as the machine-dependent part of an operating system; very little code in Plan 9 is in assembly language. .PP The compilers take an option .CW -S that causes them to print on their standard output the generated code in a format acceptable as input to the assemblers. This is of course merely a formatting of the data in the object file; therefore the assembler is just an ASCII-to-binary converter for this format. Other than the specific instructions, the input to the assemblers is largely architecture-independent; see ``A Manual for the Plan 9 Assembler'', by Rob Pike, for more information. .PP The loader is an integral part of the compilation process. Each library header file contains a .CW #pragma that tells the loader the name of the associated archive; it is not necessary to tell the loader which libraries a program uses. The C run-time startup is found, by default, in the C library. The loader starts with an undefined symbol, .CW _main , that is resolved by pulling in the run-time startup code from the library. (The loader undefines .CW _mainp when profiling is enabled, to force loading of the profiling start-up instead.) .PP Unlike its counterpart on other systems, the Plan 9 loader rearranges data to optimize access. This means the order of variables in the loaded program is unrelated to its order in the source. Most programs don't care, but some assume that, for example, the variables declared by .P1 int a; int b; .P2 will appear at adjacent addresses in memory. On Plan 9, they won't. .SH Heterogeneity .PP When the system starts or a user logs in the environment is configured so the appropriate binaries are available in .CW /bin . The configuration process is controlled by an environment variable, .CW $cputype , with value such as .CW mips , .CW 386 , .CW arm , or .CW sparc . For each architecture there is a directory in the root, with the appropriate name, that holds the binary and library files for that architecture. Thus .CW /mips/lib contains the object code libraries for MIPS programs, .CW /mips/include holds MIPS-specific include files, and .CW /mips/bin has the MIPS binaries. These binaries are attached to .CW /bin at boot time by binding .CW /$cputype/bin to .CW /bin , so .CW /bin always contains the correct files. .PP The MIPS compiler, .CW vc , by definition produces object files for the MIPS architecture, regardless of the architecture of the machine on which the compiler is running. There is a version of .CW vc compiled for each architecture: .CW /mips/bin/vc , .CW /arm/bin/vc , .CW /sparc/bin/vc , and so on, each capable of producing MIPS object files regardless of the native instruction set. If one is running on a SPARC, .CW /sparc/bin/vc will compile programs for the MIPS; if one is running on machine .CW $cputype , .CW /$cputype/bin/vc will compile programs for the MIPS. .PP Because of the bindings that assemble .CW /bin , the shell always looks for a command, say .CW date , in .CW /bin and automatically finds the file .CW /$cputype/bin/date . Therefore the MIPS compiler is known as just .CW vc ; the shell will invoke .CW /bin/vc and that is guaranteed to be the version of the MIPS compiler appropriate for the machine running the command. Regardless of the architecture of the compiling machine, .CW /bin/vc is .I always the MIPS compiler. .PP Also, the output of .CW vc