Corporate What's New? Support Contact Us Home



 

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:

  1. 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.
  2. 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.
  3. Execute the make(1) to compile the source code according to the information in the Makefile.
  4. If necessary, debug the source code and/or Makefile and recompile.
  5. Test the functionality of the program; modify and recompile as necessary.
  6. Test the performance of the program; modify and recompile as necessary.
  7. 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.

program translation stages

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.

compilation commands

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:

identifiers

Table 3 - Identifiers

 

In addition, the C preprocessor supports the following identifiers:

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

 


E-Mail Webmaster  | Legal | Copyright © 2001 MODCOMP, Inc. | Rendered Sept. 28, 2001

MODCOMP is a subsidiary of CSP Inc