Programming Environment
The REAL/IX programming environment includes a system
C compiler and assembler, as well as the standard UNIX System V tools
for debugging, and analyzing programs and managing development projects.
The General Language System (GLSC) is an optional package that provides
additional compilers and debugging tools.
The typical program development cycle is as follows:
- Write the source code, using the syntax of the compiler to be
used. The source code may be broken into several separate modules,
including header files and library archives.
- Create a Makefile that defines how the program will be
compiled. For a simple program consisting of one source code file,
this may be unnecessary, but for more complex applications, using
a Makefile streamlines the compilation step.
- Execute the make(1) to compile the source code according
to the information in the Makefile.
- If necessary, debug the source code and/or Makefile and
recompile.
- Test the functionality of the program; modify and recompile
as necessary.
- Test the performance of the program; modify and recompile as
necessary.
- When the program is released for general use, install it under
the Source Code Control System (SCCS).
The REAL/IX Operating System supports all standard UNIX
System V tools for program development. Many additional tools are
available; the Unsupported tape supplied with your REAL/IX
software includes a sampling of some freely distributed tools.
Programmers who are used to other programming environments
will notice the lack of an official Job Control Language (JCL). The
shell itself serves as a JCL with UNIX operating systems: files are
addressed by either full or relative path
name (discussed in Chapter 5) and devices are addressed through
special device files (discussed
in Chapter 6). Shell scripts provide JCL-like functionality, allowing
you to execute a sequence of programs
in order (discussed in Chapter 7); these shell scripts can be set
up to run once or periodically at a specified time using cron(1M)
(discussed in Chapter 7).
This chapter gives an overview of the REAL/IX programming
environment. For more details, refer to the Programmer's Guide,
Languages and Support Tools Guide, the manual pages, appropriate
GLS documentation, and the material listed in Chapter
10.
Program Translation
Transforming a source code file into an object file
that can be executed as a program is a multi-step process that is
similar for all languages supported on the system. Figure 9-1 illustrates
the steps involved in translating a program from source code to executable
code.
Figure 1 - Program Translation Stages
One command executes the entire translation string from
source file to executable object file. Table 9-1 lists the compilation
commands, including the subcommands called.
Table 1 - Compiler Compilation Commands
When necessary, individual steps of the translation
process can be run separately, or options can be given to the compilation
command to stop the translation phase at a specified spot.
When using GLS compilers, programs written in one language
can call routines written in any other supported language. Refer to
the GLS Programming Guide for a discussion of the interlanguage
calling requirements.
System C Compiler
The C compiler native to the REAL/IX Operating System
is referred to as the system C compiler (/bin/cc), which provides
the C syntax documented in Version 1 of Kernighan and Ritchie, The
C Programming Language plus industry-standard extensions.
This compiler must be used to compile the kernel (including all drivers
and customer-defined system calls). The following identifiers are
reserved as keywords:
Table 3 - Identifiers
In addition, the C preprocessor supports the following
identifiers:
Table 4 - Identifiers
For a full description of the syntax of the C compiler,
refer to the C programming documentation supplied with your system.
Assembler
The system assembler (/bin/as) is used to assemble
the code produced by any supported compiler. In addition to the basic
translation
to assembler language, options enable you to specify
the following:
- alignment of structures: packed (two-byte alignment), unpacked
(four-byte alignment), or determined on a line-by-line basis according
to #pragma statements in the source code.
- structure element alignment checking (check that all elements
obey both the 16-bit and 32-bit rules).
For more information on the assembler subcommands and
options, see the relevant manual pages; for more information on the
system assembler syntax, refer to the Programmer's Guide.
Link Editor
The link editor (ld(1)) combines several object
files into one, performs relocation, resolves external symbols, incorporates
startup routines, and supports symbol table information used by the
symbolic debugger, sdb(1). The output of the link editor is
named a.out unless you specify a different name with the -o
option to the compiler; the structure of the a.out file is described
in the /usr/include/a.out.h file.
The cc(1) and gcc(1) commands automatically
invoke the link editor unless otherwise specified. If necessary, the
Link Editor Command Language can be used to manipulate the object
file in the following ways:
- specify the memory configuration of the target machine.
- control the arrangement of the sections of an object file.
- bind sections to specific addresses or within specific portions.
of memory.
- define or redefine global symbols.
Optimizer
The optimizer is an optional final pass of the compilation
process. It accepts assembly language as input; its output is an optimized
version of the same file. The GLS compilers have an optional optimizer
embedded in the compiler code.
The system C compiler supports two separate sets of
optimizations. Options to the cc(1) line determine whether one or
both of these optimizations are applied. Other command line options
allow you to turn off selected optimizations as required.
coptim(1) is the high-level optimizer, which
provides the following:
- common subexpression elimination optimization
- automatic allocation of frequently-used variables to registers
optim(1) is the low-level optimizer, which provides
the following optimizations:
- merge common tails of basic blocks
- peephole optimizations
- short branch optimizations
- loop rotations
The GLS C, FORTRAN, and Pascal compilers support the
following optimizations. Some of these are called automatically by
the compiler; others require that you specify the -O compiler
option:
- register allocation for frequently-accessed values
- memory allocation that favors small, frequently-used variables
- entry and exit code optimization
- stack adjustment coalescing
- static address elimination
- loop rotation
- peephole optimizations
- loop optimizations
- in-line optimizations
- loop variant analysis
- strength reduction
Common Object File Format
The Common Object File Format (COFF) defines the structure
of executable object files for the system. The /usr/include/a.out.h
file defines the COFF and lists the header files that define sections
of COFF.
Shared Libraries
The REAL/IX Operating System supports the use of shared
libraries. Shared libraries enable a program to share a single copy
of library code and constant data resulting in a significant savings
of memory and disk resources. REAL/IX shared libraries are static-linked
libraries, meaning that a program's external symbols are resolved
and bound to a particular version of a shared library when the program
is linked. This allows the shared library program to start up with
a speed comparable to that of an archived library program. It also
means that the program must continue to use the version of the shared
library with which it was linked and, thus, cannot automatically use
a new version when it becomes available.
Each REAL/IX shared library consists of two components:
the host library and the target library. The host library is accessed
and used in the same manner as a standard archive library. When a
program linked with a host library is executed, the host library provides
the information used to resolve external symbols and provides a "lib"
section which causes the loading of the target library. The target
library contains the library code and data, and must be present and
executable in order for a program which has been linked with the shared
library to properly execute.
Shared libraries are provided for a number of the standard
system libraries and for most of the REAL/VU libraries. Archive libraries
are provided for all libraries.
Program Management
The REAL/IX programming environment includes tools for
managing the programming environment.
make
The REAL/IX Operating System supports the modular approach
when writing an application. This means that the source code for one
executable program may be created in several source and library files.
The make(1) facility allows you to create a file that defines
all file dependencies and compiler operations required to compile
the program or application. After creating or modifying one or more
of the source files, execute the make command rather than issuing
the compilation command directly. In addition to removing the onus
of remembering all the file dependencies and compiler options required,
make can determine which modular files need to be recompiled
and which only need to be relinked.
SCCS
The Source Code Control System (SCCS) is a maintenance
and enhancement tracking tool that is provided with the operating
system. SCCS takes custody of a file and, when changes are made, identifies
and stores them in the file with the original source code and/or documentation.
The original file or any set of changes can be retrieved.
Debugging
The REAL/IX programming environment includes a number
of tools to assist in debugging programs. These are described below.
sdb
The sdb(1) commands provide access to the UNIX
System V symbolic debugger. sdb is used to examine the core
image of an aborted user-level program and to provide an environment
for monitoring and controlling the execution of a program.
Use the -g option to the compiler when compiling
programs to be analyzed by sdb. This causes the compiler to
generate additional information about the variables and statements
of the compiled program. After executing the program that was compiled
with -g, sdb can be used to obtain a trace of the called
functions at the time of the abort and interactively display the values
of variables.
When using sdb to monitor an executing process,
breakpoints can be placed at selected statements or the program can
be single-stepped on a line-by-line basis.
(k)db and crash
When writing drivers and system calls, (k)db(1M)
and crash(1M) can be used to monitor and debug the kernel.
crash is the UNIX System V utility that enables you to view kernel
data structures, including the stack, on either the executing kernel
or a post-mortem kernel image saved after a system panic. (k)db
allows you to view the executing kernel and also to interactively
modify the kernel. When running the debug kernel, a panic condition
causes the system to go into (k)db, from which you can
reboot the system or debug the system.
Analyzing
The REAL/IX programming environment includes tools for
analyzing the functionality and performance of programs on the system.
The following sections describe some of these .
cflow
cflow(1) produces a chart of the external references
in C, yacc(1), lex(1), and assembly language files.
This enables you to determine all the external calls and routines
that are being called from the program.
ctrace
ctrace(1) lets you follow the execution of a C program
statement by statement. It takes a C source file as input and inserts
statements in the source code to print out variables as each program
statement is executed; you must redirect the output of this process
to a temporary C source file that is suffixed with ".c".
The temporary file (or set of files) is then compiled and executed;
the messages output during execution are quite valuable for determining
where values went awry or similar functionality problems.
Options to ctrace enable you to limit the number
of times a loop is executed. The source code can contain functions
that turn the trace on and off, to limit the output to portions of
the program that are of particular interest.
cxref
cxref(1) analyzes a group of C source code files
and builds a cross-reference table of the automatic, static, and global
symbols in each file. This can be used to provide a sort of "data
dictionary" for an application, as well as identifying symbols
that have been multiply defined.
prof and gprof
prof(1) and gprof(1) are process profilers
that identify where a process is spending most of its execution time.
This enables you to concentrate code optimization efforts on sections
where it will be of the greatest benefit. Programs to be run through
prof should be compiled with the -p option to cc(1),
to produce a call graph profile file (named mon.out by default);
programs to be run through gprof should be compiled with the
-qg option to cc, and the call graph profile file is
named gmon.out by default. The call graph profile file is correlated
with the symbol table in the object file specified to the prof
or gprof command.
Both prof and gprof produce a flat profile
that shows the total execution times and call counts for each function
in the program, sorted by decreasing time. gprof then propagates
these numbers along the edges of the call graph, to identify cycles
and calls into a cycle that identify the time of the cycle. A second
listing shows the functions sorted according to the time they represent,
including the time of their call graph descendants. Below each function
entry is shown its (direct) call graph children and how their times
are propagated to this function. A similar display above the function
shows how this function's time and the time of its descendants is
propagated to its direct call graph parents.
Disassemblers
dis(1) is a disassembler that prints the output
of the as(1) portion of the compilation process. This output
can be used to identify places where the code was compiled in some
way that was different than what you intended. When debugging kernel-level
code, the disassembled object can be viewed using the dis function
of the crash(1M) command.
Portability Concerns
One of the most important factors explaining the popularity
of the UNIX operating systems is its hardware independence, so that
programs developed for one machine can be easily ported to another
machine. The REAL/IX Operating System supports source code compatibility
with most SVID-compliant operating systems.
Although the operating system supports portable code,
the programmer must adhere to certain conventions in order to create
portable programs. Note that portability of kernel-level code is not
guaranteed between UNIX operating systems; none of the existing or
developing standards apply to drivers and operating system code. However,
the general shape of most driver code is similar across all UNIX operating
systems, and drivers can usually be ported to the REAL/IX Operating
System with relatively few modifications as long as they are installed
under the compatibility modes. Rewriting drivers to be fully semaphored
takes a bit more effort, although it is usually much less effort than
writing the driver from scratch.
Isolating Non-Portable Code
To write applications that take full advantage of the
features of the REAL/IX Operating System, it is usually necessary
to utilize specific REAL/IX features that may not be supported on
other operating systems. Similarly, existing code may utilize features
that were specific to some other operating system and are not supported
on the REAL/IX Operating System.
Note: Saying that code is SVID-compliant indicates
that it uses all SVID features appropriately. SVID-compliant code
may also include calls and routines that are not defined in SVID.
If the non-SVID code uses features of a specific operating system
(as opposed to routines described as part of the application), those
sections will require modification to run on another operating system.
Specific sections of code that use operating-system
specific features, references to particular hardware configurations
or features, or other non-portable characteristics should be isolated
in #ifdef ("if defined") or #ifndef ("if not defined")
constructions. For example, if you have an existing program from another
operating system that includes a section that will run more efficiently
using specific REAL/IX features, you can isolate the existing code
in #ifndef, followed by a #ifdef section that includes the replacement
code, as in the following:
#ifndef realix
original code that does not access REAL/IX features
#endif
#ifdef realix
code that accesses special REAL/IX features
#endif
When compiled on the old operating system, the original
code will compile, but when the same file is compiled on the REAL/IX
Operating System (where realix is true), the more efficient code will
be compiled instead. See cpp(1) for a complete list of system
definitions for the system, and the Programmer's Guide for
more information on porting code.
lint
lint(1) examines C language source programs for
bugs and obscurities, and is used to identify coding practices which
may impact the portability of the program to other hardware platforms
or operating systems. It enforces the type rules of the C language
more strictly than the C compiler. lint accepts multiple input
files and library specifications and checks them for consistency.
- unused variables and functions
- variables that are used before they are set
- unreachable portions of a program
- function values that are never used
- type checking across certain binary operators and implied assignments,
at the structure selection operators, between the definition and
uses of functions, and in the use of enumerations
- type casts
- signed characters that have negative values (these are allowed
for both C compilers, but are not allowed on all C compilers)
- assignments of long to int, which may truncate the contents
on other compilers
- "strange" constructions which, while legal, may make
the code difficult to maintain or invalid (This check can be avoided
by using the -h option to lint.)
- obsolete syntax for assignment operators and initialization
- pointer assignments that may be illegal on other machines
- simple scalar variables whose value is determined by a complex
expression that may evaluate differently on other C compilers
Special Purpose Languages
The REAL/IX Operating System supports the UNIX System
V special purpose languages that can be used to supplement C and FORTRAN
in applications.
awk
awk(1) scans an input file for lines that match
the patterns described in a specification file. On finding a line
that matches a pattern, awk performs actions also described
in the specification.
Caution: The upgrade to the nawk command
presents a non-upward compatibility problem in that pattern-action
statement pairs must be separated by either a ";" or by
a new line. This should present a problem only when the nawk
script is written as part of the nawk command line and the
newlines have been "escaped" away. If the nawk script
is in a file, there are no known upward compatibility problems.
awk can be used as a "report generator"
with applications that are written in C language or FORTRAN; it can
be used to work with associative arrays and produce formatted output
with much less code than required in C or FORTRAN.
lex
lex(1) is a tool for generating lexical analyzers
that can be added to C or FORTRAN programs. A lexical analyzer is
interested in the vocabulary of a language rather than its grammar
(which is a system or rules defining the structure of a language).
lex can produce C language subroutines that recognize regular
expressions specified by the user, take some action when a regular
expression is recognized, and pass the output stream on to the next
program.
yacc
yacc(1) (Yet Another Compiler Compiler) is a
tool for describing an input language to a computer program. yacc
produces a C language subroutine that parses an input stream according
to rules laid down in a specification file. The yacc specification
file establishes a set of grammar rules together with actions to be
taken when tokens in the input match the rules. By using lex(1)
and yacc together, it is possible to control the input process
and pass tokens to the parser that applies the grammar rules.
curses
curses(3X) is a library of C functions that serve
as a special-purpose language for generating formatted terminal screens.
It works in conjunction with the terminfo
library described in Chapter 7 so that once a screen is defined,
it can run on any terminal that has a properly-defined terminfo
file associated with it.
The curses library contains routines that manipulate
data structures called windows that can be thought of as two-dimensional
arrays of characters representing all or part of a terminal screen.
A default window called stdscr is supplied, which is the size of the
terminal screen. Additional windows can be created with newwin().
The window data structures are manipulated with the routines described
on the curses manual page. curses routines that are
prefaced with a "w" apply to a specific screen defined with
newwin; if not prefaced with "w", the routine is
applied to stdscr.
Go to Chapter 10 TOC