commit 04a8d973223717c101ce4aff9934632f7f88803b
parent 147dad103e0f63f931618d5c68161d84c70192c1
Author: Roberto E. Vargas Caballero <k0ga@shike2.net>
Date: Thu, 19 Mar 2026 19:10:07 +0100
doc: Add documentation for cc1 and cc2
While they are not expected to be used directly having
them documented helps in the development process. Also,
improve the documentation for the scc-cc driver.
Diffstat:
4 files changed, 716 insertions(+), 119 deletions(-)
diff --git a/doc/man1/Makefile b/doc/man1/Makefile
@@ -8,6 +8,8 @@ PAGES =\
scc-addr2line.1\
scc-ar.1\
scc-cc.1\
+ scc-cc1.1\
+ scc-cc2.1\
scc-cpp.1\
scc-nm.1\
scc-objdump.1\
diff --git a/doc/man1/scc-cc.man b/doc/man1/scc-cc.man
@@ -1,164 +1,536 @@
.TH SCC-CC 1 scc\-VERSION
.SH NAME
-scc-cc \- simple C compiler with magic
+scc-cc \- C compiler driver
.SH SYNOPSIS
.B scc-cc
-.RB [ \-cdgkqQsw ]
-.RB [ \-M | \-E | \-S ]
-.RB [ \-D
-.IR def[=val] ] ...
-.RB [ \-I
-.IR dir ] ...
-.RB [ \-L
-.IR dir ] ...
-.RB [ \-U
-.IR def ] ...
-.RB [ \-l
-.IR lib ]
-.RB [ \-a
-.IR arch ]
-.RB [ \-o
+.RB [ \-c | \-S | \-E ]
+.RB [ \-std= standard ]
+.br
+.RB " " [ \-g ]
+.RB [ \-Olevel ]
+.br
+.RB " " [ \-Wwarn ...]
+.br
+.RB " " [ \-Idir ...]
+.RB [ \-Ldir ...]
+.br
+.RB " " [ \-Dmacro [ =defn ]...]
+.RB [ \-Umacro ]
+.br
+.RB " " [ \-foption ...]
+.RB [ \-mmachine-option ...]
+.br
+.RB " " [ \-o
.IR outfile ]
-.RB [ \-O
-.IR level ]
+.RB [ \-l lib ]...
+.br
+.RB " " [ \-Msdk ]
+.RB [ \-q | \-Q ]
+.br
+.RB " " [ \-a
+.IR arch ]
.RB [ \-t
.IR sys ]
-.RB sourcefile ...
+.br
+.RB " "
+.IR infile ...
.SH DESCRIPTION
-.B scc
-is a simple C compiler which takes several
-.I sourcefiles
-and compiles them to an executable. The default output file is
-.B a.out,
-which can be changed by defining some
-.I outfile.
-.SH OPTIONS
+.B scc-cc
+is the compiler driver of the scc toolchain.
+It accepts C source files, intermediate representation files,
+assembler source files, object files, and archive libraries,
+and orchestrates the tools required to turn them into an
+executable or object file.
+.PP
+For each C source file
+.RB ( .c ),
+.B scc-cc
+runs a pipeline of sub-processes connected by pipes:
+the frontend
+.B cc1
+compiles the source to scc IR, the backend
+.B cc2
+lowers the IR to assembly (or to QBE IR when QBE mode is active),
+the optional
+.B qbe
+stage compiles QBE IR to native assembly,
+and finally the assembler
+.B as
+produces an object file.
+When linking is not suppressed, the resulting object files are
+passed to the linker
+.B ld
+to produce the final executable.
+.PP
+Files with other extensions are handled as follows:
.TP
-.B \-c
-Do not run the linker.
+.B .ir
+Passed directly to
+.BR cc2 ,
+skipping the
+.B cc1
+stage.
.TP
-.B \-d
-Do output internal tool messages.
+.B .qbe
+Passed directly to
+.BR qbe ,
+skipping
+.B cc1
+and
+.BR cc2 .
.TP
-.BI \-D " define[=value]"
-Specify a
-.I define
-for the preprocessor.
+.B .s
+Passed directly to the assembler, skipping all compiler stages.
+.TP
+.B .o ", " .a
+Passed directly to the linker.
+.SH OPTIONS
+.SS Compilation Control
+.TP
+.B \-c
+Compile and assemble, but do not link.
+One object file is produced for each input source file.
+If
+.B \-o
+is also specified, only a single input file is permitted.
.TP
.B \-E
-Stop after the preprocessing stage, do not run the compiler and output the then
-resulting source.
+Stop after preprocessing.
+The preprocessed source is written to standard output,
+or to
+.I outfile
+if
+.B \-o
+is given.
+Cannot be combined with
+.B \-M
+or the stop flags
+.BR \-S ,
+.BR \-k .
.TP
-.B \-g
-Do generate debug information.
+.B \-M
+Emit a
+.BR make (1)
+dependency rule describing the
+.B #include
+dependencies of each source file, then exit.
+No compilation is performed.
+Cannot be combined with
+.BR \-E .
.TP
-.BI \-I " directory"
-Define a include
-.I directory
-to get header files from. This directory is searched for before standard
-include directories.
+.B \-S
+Stop after compilation; do not assemble.
+Assembly source is written to a file with the same base name as
+the input and the suffix
+.BR .s .
+.SS Preprocessor
.TP
-.B \-k
-Do keep temporary objects.
+.BI \-D macro [ =value ]
+Define the preprocessor macro
+.I macro
+with an optional replacement text
+.IR value .
+If
+.I value
+is omitted, the macro is defined with the value
+.BR 1 .
+This option may be repeated to define multiple macros.
.TP
-.BI \-l " library"
-Link against this
-.I library.
+.BI \-U macro
+Undefine the preprocessor macro
+.IR macro .
+This option may be repeated.
.TP
-.BI \-L " directory"
-Define a library
-.I directory
-to resolve dependencies from. This directory is used before the standard
-paths.
+.BI \-I dir
+Prepend
+.I dir
+to the list of directories searched for header files.
+User-specified directories are searched before system include
+directories.
+This option may be repeated.
+.SS Optimisation
.TP
-.BI \-a " architecture"
-Define the
-.I architecture
-to compile for (i.e. amd64, i386 ...).
+.BI \-O level
+Specify the optimisation level.
+This option is accepted for compatibility with other compiler
+driver interfaces but is otherwise ignored;
+.B scc-cc
+does not perform its own optimisation passes.
+.SS Linker
.TP
-.B \-M
-Output a rule for
-.B make
-describing the dependencies of the main source file.
+.BI \-L dir
+Add
+.I dir
+to the list of directories searched for libraries.
+.TP
+.BI \-l lib
+Link against the library
+.IR lib .
+.SS Output
.TP
.BI \-o " outfile"
-Define the name of the
-.I outfile.
+Place the output into
+.IR outfile .
+When compiling and linking, the default output name is
+.BR a.out .
+When compiling to an object file
+.RB ( \-c ),
+the default output name is derived from the input file name.
+.SS Debugging and Symbols
+.TP
+.B \-g
+Generate debugging information.
+This flag is forwarded to the assembler and linker.
.TP
-.BI \-O " level"
-Define the optimisation
-.I level
-to compile with. (This is a stub for compatibility reasons.)
+.B \-s
+Strip all symbol table and relocation information from the output
+executable.
+This flag is forwarded to the linker.
+.SS Warnings
+.TP
+.B \-w
+Enable warning messages for dubious constructs.
+The flag is forwarded to
+.BR cc1 .
+.TP
+.BI \-W param
+Enable warnings.
+The parameter
+.I param
+is ignored; the effect is the same as
+.BR \-w .
+Accepted for compatibility with other compiler driver interfaces.
+.SS Target
+.TP
+.BI \-a " arch"
+Select the target architecture.
+Overrides the
+.B ARCH
+environment variable.
+.TP
+.BI \-t " sys"
+Select the target operating system.
+Overrides the
+.B SYS
+environment variable.
+.SS Driver Behaviour
+.TP
+.B \-d
+Enable verbose driver output.
+The exact command line executed for each sub-process is printed
+to standard error before that process is started.
+.TP
+.B \-k
+Keep intermediate files.
+When this flag is set,
+.B scc-cc
+saves the IR, QBE IR, and assembler output produced during
+compilation alongside the object file,
+using the base name of the input file with the suffixes
+.BR .ir ,
+.BR .qbe ,
+and
+.BR .s ,
+respectively.
+The final object file is also kept even when linking.
.TP
.B \-q
-Do not use
-.I QBE.
+Disable QBE mode.
+.B cc2
+produces native assembly directly, without invoking
+.BR qbe (1).
.TP
.B \-Q
-Do use the
-.I QBE.
-.TP
-.B \-s
-Strip all symbol tables and relocation information from the resulting executable.
+Enable QBE mode (default).
+.B cc2
+produces QBE IR, which is then compiled to native assembly by
+.BR qbe (1).
+.SS Compatibility Options
+The following options are accepted and silently ignored for
+compatibility with other compiler driver interfaces:
+.BR \-static ,
+.BR \-dynamic ,
+.BR \-pedantic ,
+.BR \-ansi ,
+any option beginning with
+.BR \-std= ,
+any
+.BI \-f option
+and any
+.BI \-m option.
+.SH COMPILATION PIPELINE
+For each C source file,
+.B scc-cc
+constructs and runs the following pipeline:
+.PP
+.EX
+cc1 | cc2[\-qbe_arch\-abi] | [qbe] | as
+.EE
+.PP
+Each stage is a separate process.
+The stages are connected by anonymous pipes so that no large
+intermediate files are created on disk unless
+.B \-k
+is used.
.TP
-.B \-S
-Stop after the compilation stage, do not assemble and output the assembler
-source.
+.B cc1
+The C compiler frontend.
+It reads the C source file, preprocesses it, parses it,
+performs type checking and semantic analysis,
+and emits the scc intermediate representation (IR) to standard
+output.
+It is installed as
+.IR $SCCPREFIX/libexec/scc/cc1 .
.TP
-.BI \-t " system"
-Define the
-.I system
-to compile for (i.e. linux, openbsd ...).
+.B cc2
+The C compiler backend.
+It reads the scc IR and emits either native assembly or QBE IR.
+The exact binary invoked depends on the target architecture, ABI,
+and whether QBE mode is active.
+In QBE mode (the default), the binary name has the form
+.BI cc2\-qbe_ arch \- abi ;
+in native mode
+.RB ( \-q )
+the form is
+.BI cc2\- arch \- abi .
+These binaries are installed under
+.IR $SCCPREFIX/libexec/scc/ .
.TP
-.BI \-U " define"
-Undefine a previously defined
-.I define
-by the -D parameter.
+.B qbe
+The QBE compiler backend.
+Only invoked in QBE mode.
+It reads QBE IR and emits native assembly.
+.B qbe
+is looked up in the standard
+.BR PATH .
.TP
-.BI \-W " param"
+.B as
+The target assembler.
+It assembles the native assembly into an object file.
+The assembler command and its arguments are determined at
+build time via the
+.B ascmd
+configuration variable in
+.I sys.h
+and may include
+.B %a
+(architecture),
+.B %s
+(system),
+.B %b
+(ABI),
+.B %p
+(library prefix),
+and
+.B %o
+(output file) wildcards.
+.PP
+After all source files are compiled, the linker is invoked unless
+.BR \-c ,
+.BR \-S ,
+.BR \-E ,
or
-.B \-w
-Show warning messages.
-The parameter of
-.B \-W
-is ignored for compatibility reasons.
+.B \-M
+suppresses linking:
.TP
-.BI \-f " param"
-and
-.BI \-m " param"
-are ignored for compatibility with other compiler command lines.
-In the same way,
-the options
-.BI \-static ,
-.BI \-dynamic ,
-.BI \-pedantic ,
-.B \-ansi
-and any option beginning with
-.B \-std=
-are ignored for the same reason.
+.B ld
+The target linker.
+The linker command and its arguments are determined at build time
+via the
+.B ldcmd
+configuration variable in
+.IR sys.h .
+The same wildcards as for
+.B as
+are supported, and
+.B %c
+expands to the full list of input object files.
.SH ENVIRONMENT VARIABLES
-Certain environment variables control the behaviour of scc.
.TP
.B ARCH
-defines the
-.I architecture
-to compile for (i.e. amd64, i386 ...).
+Target architecture name (e.g.
+.BR amd64 ,
+.BR arm64 ,
+.BR i386 ).
+Overridden by
+.BR \-a .
.TP
.B SYS
-defines the
-.I system
-to compile for (i.e. linux, openbsd ...).
+Target operating system name (e.g.
+.BR linux ,
+.BR openbsd ).
+Overridden by
+.BR \-t .
.TP
.B ABI
-defines the
-.I application binary interface
-to compile for (i.e. sysv ...).
+Target ABI name (e.g.
+.BR sysv ).
.TP
.B FORMAT
-defines the format of the output executable.
+Target object file format (e.g.
+.BR elf ,
+.BR coff ).
.TP
.B SCCPREFIX
-defines the path prefix scc will search the scc suite in.
+Path prefix under which the scc suite is installed.
+Used to locate
+.B cc1
+and
+.B cc2
+under
+.IR $SCCPREFIX/libexec/scc/ .
+If not set, the compile-time
+.B PREFIX
+value is used.
+.TP
+.B SCCLIBPREFIX
+Path prefix for scc libraries.
+Expanded from the
+.B %p
+wildcard in linker and assembler command templates.
+If not set, the compile-time
+.B LIBPREFIX
+value is used.
+.TP
+.B TMPDIR
+Directory used for temporary files created during compilation.
+If not set or empty, the current directory is used.
+.SH EXAMPLES
+.PP
+Compile a C source file and link into an executable:
+.IP
+.EX
+scc-cc \-o hello hello.c
+.EE
+.PP
+Compile to an object file only:
+.IP
+.EX
+scc-cc \-c hello.c
+.EE
+.PP
+Compile multiple source files and link:
+.IP
+.EX
+scc-cc \-o prog main.c util.c \-lm
+.EE
+.PP
+Preprocess only and view the output:
+.IP
+.EX
+scc-cc \-E hello.c
+.EE
+.PP
+Generate make dependency rules:
+.IP
+.EX
+scc-cc \-M hello.c
+.EE
+.PP
+Stop after compilation, keeping intermediate files:
+.IP
+.EX
+scc-cc \-k \-c hello.c
+.EE
+.PP
+Compile for a specific target:
+.IP
+.EX
+ARCH=arm64 ABI=sysv SYS=linux scc-cc \-o hello hello.c
+.EE
+.PP
+Compile in native mode (no QBE):
+.IP
+.EX
+scc-cc \-q \-o hello hello.c
+.EE
+.PP
+Show all sub-process command lines:
+.IP
+.EX
+scc-cc \-d \-c hello.c
+.EE
+.PP
+The
+.B \-d
+flag prints the exact command line of each sub-process to standard error.
+For example, compiling
+.I hello.c
+on an amd64 Linux system in QBE mode produces:
+.IP
+.EX
+/usr/local/libexec/scc/cc1 \-I /usr/local/include/scc/bits/amd64/ \e
+ \-I /usr/local/include/scc/bits/linux/ \e
+ \-I /usr/local/include/scc/bits/linux/amd64/ \e
+ \-I /usr/local/include/scc/ hello.c
+/usr/local/libexec/scc/cc2\-qbe_amd64\-sysv
+qbe \-t amd64_sysv
+as \-o hello.o
+.EE
+.SH DIAGNOSTICS
+When a sub-process in the compilation pipeline fails,
+.B scc-cc
+reports an error to standard error and exits with a non-zero status.
+.PP
+If
+.B cc1
+exits with a non-zero status, the error message comes from
+.B cc1
+itself (a compilation error such as a syntax or type error) and
+.B scc-cc
+exits silently.
+Likewise, if the linker
+.B ld
+fails, its own error output is displayed and
+.B scc-cc
+exits without an additional message.
+.PP
+If any stage terminates by a signal
+or any other stage in the pipeline
+.RB ( cc2 ,
+.BR qbe ,
+or
+.BR as )
+terminates with non-zero exit then
+these conditions are considered an internal error.
+In this case
+.B scc-cc
+prints the following message to standard error:
+.IP
+.EX
+scc-cc:tool: internal error
+.EE
+.PP
+where
+.I tool
+is the name of the failing sub-process.
+This message indicates a bug in the toolchain rather than an error in
+the user's source code.
+The same message is printed if
+.B scc-cc
+cannot
+.BR execvp (2)
+the sub-process binary (for example because
+.B SCCPREFIX
+is set incorrectly and
+.B cc1
+or
+.B cc2
+cannot be found).
+In this case,
+Using the option
+.B \-d
+combined with
+.B \-k
+is very useful because
+it provides all the information to run the tool in isolation
+and debug the issue.
.SH SEE ALSO
-.BR scc-cpp (1),
-.BR scc-make (1)
+.BR scc (1),
+.BR scc\-cc1 (1),
+.BR scc\-cc2 (1),
+.BR scc\-cpp (1),
+.BR scc\-ld (1),
+.BR scc\-as (1),
+.BR scc\-ir (7),
+.BR qbe (1)
diff --git a/doc/man1/scc-cc1.man b/doc/man1/scc-cc1.man
@@ -0,0 +1,130 @@
+.TH SCC-CC1 1 scc\-VERSION
+.SH NAME
+scc-cc1 \- C compiler frontend
+.SH SYNOPSIS
+.B cc1
+.RB [ \-Ewd ]
+.RB [ \-M ]
+.RB [ \-a
+.IR architecture ]
+.RB [ \-D
+.IR def[=val] ] ...
+.RB [ \-U
+.IR def ] ...
+.RB [ \-I
+.IR dir ] ...
+.RI [ input ]
+.SH DESCRIPTION
+.B cc1
+is the C compiler frontend of the scc toolchain.
+It reads a C source file (or standard input if no
+.I input
+file is given), performs preprocessing, parsing, type checking,
+and semantic analysis, and emits the scc intermediate representation (IR)
+to standard output.
+.PP
+.B cc1
+is not normally invoked directly.
+It is called by the compiler driver
+.BR scc\-cc (1),
+which pipes its output to
+.BR cc2 ,
+the code generation backend that produces assembly output.
+.B cc1
+is installed as
+.IR $prefix /libexec/scc/cc1.
+.SH OPTIONS
+.TP
+.BI \-a " architecture"
+Select the target architecture.
+The following architectures are supported:
+.RS
+.TP
+.B amd64-sysv
+64-bit x86 with the System V ABI (default).
+.TP
+.B arm64-sysv
+64-bit ARM with the System V ABI.
+.TP
+.B riscv64-sysv
+64-bit RISC-V with the System V ABI.
+.TP
+.B i386-sysv
+32-bit x86 with the System V ABI.
+.TP
+.B z80-scc
+Zilog Z80 with the scc ABI.
+.RE
+.TP
+.BI \-D " def[=val]"
+Define the preprocessor macro
+.I def
+with an optional value
+.IR val .
+If
+.I val
+is omitted, the macro is defined with the value
+.BR 1 .
+This option may be repeated to define multiple macros.
+.TP
+.B \-E
+Stop after preprocessing.
+Emit the preprocessed C source to standard output instead of IR.
+No compilation is performed.
+.TP
+.BI \-I " dir"
+Prepend
+.I dir
+to the list of directories searched for header files.
+This option may be repeated to add multiple directories.
+User-specified directories are searched before any system include directories
+added by
+.BR scc\-cc (1).
+.TP
+.B \-M
+Emit a
+.BR make (1)
+dependency rule describing the
+.B #include
+dependencies of the input file, then exit.
+No compilation is performed.
+.TP
+.BI \-U " def"
+Undefine the preprocessor macro
+.IR def .
+This option may be repeated.
+.TP
+.B \-d
+Enable internal debug output.
+.TP
+.B \-w
+Enable warning messages for dubious constructs.
+.SH OUTPUT
+.B cc1
+writes the scc IR to standard output.
+The IR is a line-oriented, tab-separated format.
+Declarations begin in column 0; expressions are indented with a tab
+and written in reverse Polish notation.
+For a full description of the IR format, types, storage classes,
+and statement encoding, see
+.BR scc\-ir (7).
+.PP
+When only preprocessing is requested
+.RB ( \-E
+or
+.BR \-M ),
+the preprocessed source or dependency rule is written to standard output
+instead.
+.PP
+If any compilation error occurs, the output stream is closed immediately
+so that the backend
+.B cc2
+receives no output and can detect the failure.
+.B cc1
+exits with a non-zero status on error.
+.SH SEE ALSO
+.BR scc\-cc (1),
+.BR scc\-cpp (1),
+.BR scc (1),
+.BR scc\-cc2 (1),
+.BR scc\-ir (7)
diff --git a/doc/man1/scc-cc2.man b/doc/man1/scc-cc2.man
@@ -0,0 +1,93 @@
+.TH SCC-CC2 1 scc\-VERSION
+.SH NAME
+scc-cc2 \- C compiler backend
+.SH SYNOPSIS
+.B cc2
+.RB [ \-d ]
+.RI [ irfile ]
+.SH DESCRIPTION
+.B cc2
+is the C compiler backend of the scc toolchain.
+It reads the scc intermediate representation (IR) from standard input
+(or from
+.I irfile
+if given), and emits assembly code to standard output.
+.PP
+.B cc2
+is not normally invoked directly.
+It is called by the compiler driver
+.BR scc\-cc (1),
+which pipes the IR produced by
+.B cc1
+into
+.BR cc2 .
+.B cc2
+is installed as
+.IR $prefix /libexec/scc/cc2-*.
+.SH OPTIONS
+.TP
+.B \-d
+Enable internal debug output.
+When set, debugging information about the IR tree and the control flow
+graph is printed to standard error during compilation.
+.SH INPUT
+.B cc2
+reads the scc IR produced by
+.BR cc1 .
+The IR is a line-oriented, tab-separated text format.
+If
+.I irfile
+is specified, standard input is replaced by that file.
+Otherwise the IR is read from standard input, which is the normal mode
+when
+.B cc2
+is used inside the pipeline constructed by
+.BR scc\-cc (1).
+.PP
+For a full description of the IR format see
+.BR scc\-ir (7).
+.SH OUTPUT
+.B cc2
+writes to standard output.
+Depending on the variant of
+.B cc2
+that is invoked, the output is either:
+.TP
+.B Native assembly
+The target architecture assembly language, ready to be assembled by the
+system assembler.
+This is the output of the
+.BI cc2\- arch \- abi
+variants.
+.TP
+.B QBE IR
+The intermediate language accepted by the QBE compiler backend.
+This is the output of the
+.BI cc2\-qbe_ arch \- abi
+variants.
+QBE subsequently compiles this IR to native assembly.
+.SH BACKENDS
+.B cc2
+is a family of architecture-specific binaries.
+Each binary is compiled for a specific target and installed as a separate
+executable under
+.IR $SCCPREFIX/libexec/scc/ .
+The following target backends are available:
+.TP
+.B cc2\-z80\-scc
+Native code generator for the Zilog Z80 with the scc ABI.
+.TP
+.B cc2\-qbe_amd64\-sysv
+QBE IR emitter for 64-bit x86 with the System V ABI.
+.TP
+.B cc2\-qbe_arm64\-sysv
+QBE IR emitter for 64-bit ARM with the System V ABI.
+.TP
+.B cc2\-qbe_riscv64\-sysv
+QBE IR emitter for 64-bit RISC-V with the System V ABI.
+.SH SEE ALSO
+.BR scc\-cc (1),
+.BR scc\-cc1 (1),
+.BR scc\-cpp (1),
+.BR scc (1),
+.BR scc\-ir (7)