4.3BSD/usr/contrib/spms/doc/4.manage.ms

Compare this file to the similar file:
Show the results in this format:

.nr PS 12
.NH
Software Management
.nr PS 10
.XS
\*(SN Software Management
.XE
.PP
Although the
.UX 
operating system offers a rich variety of programming tools, a frequent
complaint is that there are too few guidelines showing how to use them
in a coherent way. SPMS provides the `glue' for coordinating the use
of these tools and this section describes the techniques which have been
devised for the development and maintenance of software packages.
.NH 2
Program Development Techniques
.XS
\*(SN Program Development Techniques
.XE
.PP
Before discussing the maintenance of complete software packages, it is
worthwhile to review the basic commands for managing individual programs
and libraries. The commands are summarized in table 2 and explained below
in more detail.
.KF

.SM
.ce
\fITable 2.\fR   Program development commands
.NL

.so develop.tbl
.KE
.NH 3
\fIProgram compilation\fR
.XS
\*(SN Program compilation
.XE
.PP
The command
.ID
%  \fBmake\fR
.DE
compiles source files into object files and loads them together
to produce an executable program. Although
.I make
uses built-in information for generating the object files
from the source files, the decision on how to load the program is
left to the user. By default, the program makefiles produced by
.I mkmf
use the C compiler for this purpose. However, if the programming
language is not C, the LINKER macro definition in the makefile should
be altered accordingly. For Fortran this can be done by typing the command
.ID
%  \fBmkmf  LINKER=f77\fR
.DE
and for Pascal
.ID
%  \fBmkmf  LINKER=pc\fR
.DE
.PP
Compiler options can be specified by adding certain macros to a
makefile.  For example, the macro
.ID
CFLAGS = \-O
.DE
causes a C program to be compiled with optimization, and the macro
.ID
CFLAGS = \-I../../include  \-g
.DE
tells the C compiler to search for header files in the directory
`../../include' as well as in the current directory (see \(sc\|2.9.1),
and to compile the program with debugging information. FFLAGS and
PFLAGS can be used similarly to set options for the Fortran and Pascal
compilers respectively.
.NH 3
\fIInstallation\fR
.XS
\*(SN Installation
.XE
.PP
The command
.ID
%  \fBmake  install\fR
.DE
installs a program or library (see \(sc\|2.9.3). If any source code
files are newer than their corresponding object files they are
recompiled and the program or library reformed. Even if the object
files are up-to-date, a program may still be relinked if the libraries
on which it depends are newer than the program itself.
.PP
Normally a program is stripped of its symbol table and relocation
bits when it is installed, to save space. This can be avoided
if the
.B \-s
option is removed from the
.I install
command line in the makefile.
.NH 3
\fIUpdating\fR
.XS
\*(SN Updating
.XE
.PP
If a program or library is out-of-date \- that is, some of the source
code files are newer than the installed version \- the command
.ID
\fBmake update\fR
.DE
recompiles and reinstalls the program or library. This command is more
powerful than \fImake install\fR because it is not affected by the
absence of the object files. In the case of an out-of-date library, all
the object files are extracted from the library before any
recompilation takes place, and removed once the library has been
reinstalled.
.NH 3
\fIDependency analysis\fR
.XS
\*(SN Dependency analysis
.XE
.PP
Although the
.I make
program has a set of built-in rules for recompiling a program if any of
the files on which it depends have changed since the last time it was
constructed, these rules do not extend to included files. It is
necessary to add explicit dependency rules to a makefile so that if
a header file is changed, the affected source files will be recompiled
and a new program produced. For instance, if the rule
.ID
vs.o:  vs.h  hash.h  list.h
.DE
is added to the makefile for the `vs' program, the file `vs.c' will be
recompiled if any of the included files (see \(sc\|2.9.1) have changed
since the last time it was compiled. The command
.ID
%  \fBmake depend\fR
.DE
calls on the
.I mkmf
makefile editor to insert header file dependencies into a makefile.
.NH 3
\fIProgram checking\fR
.XS
\*(SN Program checking
.XE
.PP
Programs written in C can be checked for bugs, obscurities, wasteful
or error prone constructions, type and function usage, and portability
by the
.I lint
program\|[4]. If a makefile contains the line
.ID
lint:;  @lint $(LINTFLAGS) $(SRCS) $(LINTLIST)
.DE
where the LINTFLAGS macro definition specifies
.I lint
options, SRCS represents the source files making up the program or library,
and LINTLIST is a list of lint libraries (see below), the command
.ID
%  \fBmake lint\fR
.DE
will check that the program or library is consistent.
.PP
To set up the `vs' program might be set up for ``linting'', the macro
definitions would be
.DS
LINTFLAGS \kx= \-I../../include

SRCS\h'|\nxu'= vs.c

LINTLIST\h'|\nxu'= \ky../../lib/llib-lhash.ln \\\\
\h'|\nyu'\&../../lib/llib-llist.ln \\\\
\h'|\nyu'\-lc
.DE
.PP
Just as program libraries share functions among different programs,
lint libraries can be used to check that those functions have been used
correctly. Lint libraries are created by \fIlint \-C\fR as shown by the
following entry in the makefile belonging to the `hash' library
.DS
$(LINTLIB):  \kx$(SRCS) $(HDRS) $(EXTHDRS)
\h'|\nxu'@echo "Loading $(LINTLIB) . . ."
\h'|\nxu'@lint $(LINTFLAGS) \-C$(LIBNAME) $(SRCS)
\h'|\nxu'@echo done
.DE
where LIBNAME is defined in the makefile as `hash', and LINTLIB is defined
as `llib-l$(LIBNAME).ln' in accordance with standard lint library naming
conventions.
.NH 3
\fIVersion control and releases\fR
.XS
\*(SN Version control and releases
.XE
.PP
During the time that a program is being developed it is quite likely
that it will undergo several revisions. Features are added and
algorithms are improved. Often changes are made which are later found
not to work and need to be undone. One way to handle these changes is
to save a copy of each file before it is revised. However, this quickly
becomes expensive in terms of space. A better solution is to use a
version control system like
.I SCCS
(Source Code Control System)\|[6] or
.I RCS
(Revision Control System)\|[10] which stores only the changes made to the
source code together with details such as when each change was made,
why it was made, and who made it.
.PP
Once a program is ready for release, all of the source files should be
stamped with a common version name or number so that it can be recreated
at any time regardless of any subsequent changes.
.I RCS
has the advantage over
.I SCCS
in this respect because it enables the user to stamp each release with a
unique name. For example, if the makefile and all the source files in
release 2 of the `list' library are stamped `V2', the command sequence
.ID
%  \fBco  \-rV2  Makefile\fR
%  \fBmake  VERSION=V2  co\fR
.DE
will create that release
by extracting or ``checking out'' the Makefile and the source files from the
.I RCS
system
using the
.I co
command.
.NH 3
\fIFunction tagging\fR
.XS
\*(SN Function tagging
.XE
.PP
By creating a database of function names\**
.FS
For C, Fortran, and Pascal programs only.
.FE
with the command
.ID
%  \fBmake tags\fR
.DE
it is possible for the user to find and edit a function without having
to remember the name of the file in which the function is located. For
example, in the `src' directory of the `libhash' subproject, the
command
.ID
%  \fBvi  \-t  htinit\fR
.DE
invokes the
.I vi
editor on the file `htinit.c' and positions the cursor at the beginning of the
`htinit' hash table initialization function.
.PP
A list of functions which make up the program or library,
together with the line number and file in which each is defined, can be
obtained by the command
.ID
%  \fBmake index\fR
.DE
.NH 3
\fIPrinting\fR
.XS
\*(SN Printing
.XE
.PP
To print all of the program source and header files on the line printer
.I lpr,
type
.ID
%  \fBmake  print  |  lpr\fR
.DE
By default the files are formatted by
.I pr
so that the output is separated into pages headed by a date, the name of
the file, and a page number. Another format can be specified by changing
the PRINT macro definition in the makefile.
.NH 3
\fICleaning up\fR
.XS
\*(SN Cleaning up
.XE
.PP
To save space once a program has been completed, the command
.ID
%  \fBmake clean\fR
.DE
removes object files plus any other files which can be regenerated easily.
.NH 3
\fITesting\fR
.XS
\*(SN Testing
.XE
.PP
Using the test cases prepared previously (see \(sc\|3.4), it is possible
to test an entire program or library by typing the command
.ID
%  \fBptest\fR
.DE
.I Ptest
reports the outcome of each test \- i.e. whether it passes or fails \- and if
it fails, saves the error diagnostics in a file called E\fItest\fR where
.I test
is the name of the test.
.PP
Because
.I ptest
uses a number of temporary working files for each test and creates an error
diagnostic file for each test that fails, it is a good idea not to clutter up
the directories that contain source code or test cases, but instead perform
the testing in another directory such as `work' (see \(sc\|4.3.5).
.NH 3
\fICompound commands\fR
.XS
\*(SN Compound commands
.XE
.PP
The
.I make
program can process multiple requests. For example,
.ID
%  \fBmake install tags clean\fR
.DE
installs a program or library, creates function tags, and removes
any unneeded files. The only operation which may cause problems
if it is used in conjunction with
.I install
or
.I update
is \fImake depend\fR because it recreates the include file dependencies
.B after
the
.I make
command has already read the makefile.
.NH 3
\fIUser-defined commands\fR
.XS
\*(SN User-defined commands
.XE
.PP
Most of the tasks described above are handled by the
.I make
command. More complex programming tasks can also be defined by adding
extra instructions to each makefile. However, rather than modify every
program and library makefile in a project individually, the user can
get
.I mkmf
to use alternative `p.Makefile' and `l.Makefile' makefile templates when
creating program and library makefiles respectively, if these templates
exist in the project `lib' directory (see fig. 3). The templates for
project `vs' include directives for type checking and version control (see
appendix B). It is a worthwhile exercise to compare them against the
standard templates shown in appendix A.
.NH 2
Layered Construction of Software Packages
.XS
\*(SN Layered Construction of Software Packages
.XE
.PP
A complex software package may be built and installed in \fIlayers\fR\|[2]
as shown in table 3.
.KF

.SM
.ce
\fITable 3.\fR   Layers of software
.NL

.so layer.tbl
.KE
.PP
Each layer is assigned a specific label so that it can be built individually,
as well as a priority level so that the complete software package can be
constructed in a predetermined sequence. Layers are implemented by attaching
type labels to the directories which are part of the building process.
Table 4 suggests a set of type labels for each layer. By convention, type
label `update' is used for the construction of the entire software package.
.KF

.SM
.ce
\fITable 4.\fR   Layer type labels and priority levels
.NL

.so construct.tbl
.KE
.PP
If the project `vs' is organized into layers in the manner shown in figure 11,
.KF
.sp 34
.SM
.ce
\fIFigure 11.  \fRLayers of project `vs'

.NL
.KE
then the command
.ID
%  \fBpexec \-T\|libsrc  make  update\fR
.DE
brings the program libraries up-to-date, while the command
.ID
%  \fBpexec \-T\|cmdsrc  make  update\fR
.DE
does the same for the programs
.I vs
and
.I vstutor.
By typing
.ID
%  \fBpexec \-T\|update  make  update\fR
.DE
the entire software package can be updated.
.NH 2
Maintenance of Software Packages
.XS
\*(SN Maintenance of Software Packages
.XE
.PP
Having established the conventions for maintaining the individual components
of a software package, global tasks such as printing,
testing, cleaning, etc., can now be described in more detail. The type
labels that provide the means for coordinating these tasks are
summarized in table 5. Some of the labels have the letter
.I n
to indicate priority because the directories to which they are attached
must be processed in a particular order (see \(sc\|2.10.2). 
.KF

.SM
.ce
\fITable 5.\fR   Type label conventions
.NL

.so label.tbl
.KE
.NH 3
\fICounting of source lines\fR
.XS
\*(SN Counting of source lines
.XE
.PP
The total number of lines of source code in a software package can be counted
by concatenating the source files in each `src' directory and piping them
to the word count program as
.ID
%  \fBpexec  \-q  \-T\|src  make  PRINT=cat  print  |  wc  \-l\fR
.DE
where
.B \-q
suppresses the printing of project directory titles, and
.B \-l
tells
.I wc
to count lines only.
.NH 3
\fICataloging of functions\fR
.XS
\*(SN Cataloging of functions
.XE
.PP
A list of functions, together with the line number and file in which
each is defined, may be obtained\** for each program in a software package
.FS
For C, Fortran, and Pascal programs only.
.FE
by the command
.ID
%  \fBpexec  \-T\|cmdsrc  make index\fR
.DE
.PP
A comprehensive index of all the library functions can be generated by
outputting the function definitions in each library (e.g. `libhash' and
`liblist') to the
.I sort
program by
.ID
%  \fBpexec  \-q  \-Tlibsrc  make index  | sort\fR
.DE
.NH 3
\fIPrinting\fR
.XS
\*(SN Printing
.XE
.PP
After printing all of the source code in a project by
.ID
%  \fBpexec  \-T\|print  make print  |  lpr\fR
.DE
a table of contents can be produced by
.ID
%  \fBpexec  \-Tprint  make \\\&"PRINT=ls \-C\^\\\&" print  |  lpr\fR
.DE
Backslash `\\' characters prevent the double quotes `"' from being stripped
from the PRINT macro definition by the shell before the
.I make
command is executed in each directory.
.NH 3
\fIProgram checking\fR
.XS
\*(SN Program checking
.XE
.PP
Software packages written in C can be cross-checked for function and type usage
by applying the
.I lint
command to the source code in each of the project directories containing a
program or library
.ID
%  \fBpexec  "\-T\|libsrc\||\|cmdsrc"  make lint\fR
.DE
.NH 3
\fITesting\fR
.XS
\*(SN Testing
.XE
.PP
All of the tests previously prepared for a software package are exercised
by the command
.ID
%  \fBpexec  \-T\|test  ptest  >  testlog\fR
.DE
in the directories labeled `test'. In the case of project `vs', the
following directories are labeled `test'
.DS
.so test.tbl
.DE
The outcome of each test \- i.e. whether it passes or fails \- is recorded
in the file called `testlog' in the current working directory. If a test
fails, the cause of the failure is recorded in a file bearing the
name `E\fItest\fR' where
.I test
is the name of the test, located in the directory where the test is
executed.
.NH 3
\fIComparing versions\fR
.XS
\*(SN Comparing versions
.XE
.PP
The method for comparing the source code in two different versions of a
project depends on the way in which the versions are stored. If they
are stored in separate projects the
.I pdiff
command can be used to compare the contents of the directories belonging
to each of the two projects. For example, if `nvs' is a new version of
the project `vs', then the command
.ID
%  \fBpdiff  \-T\|src  ^vs  ^nvs\fR
.DE
will produce a summary of the differences between them. However, if the
different versions are stored as deltas in a version control system such as
.I SCCS
or
.I RCS,
then either the
.I sccsdiff
command or the
.I rcsdiff
command must be used instead. To show how this is done with
.I RCS,
.ID
%  \fBpexec  \-T\|src  make  VERSION=V2  diff\fR
.DE
compares the current working version of the source code in the project
`vs' with a previous version labeled `V2'.
.NH 3
\fIReleases\fR
.XS
\*(SN Releases
.XE
.PP
If the source code for a software package is stored in a version control
system like
.I RCS,
it is possible to re-create any particular version of the package provided
that all the source files in that version have previously been stamped
with a symbolic version name\** (for example, `V2').
.FS
\fISCCS\fR does not have this feature.
.FE
The process is carried out in two stages. After removing the current version
of the source code (hopefully, it has already been stored in the version
control system) by the following command sequence,
.ID
%  \fBpexec  \-T\|src  \'rm  \`make PRINT=echo print\`  Makefile\'\fR
.DE
the makefile and source files for the desired version (say `V2') are
checked out by
.ID
%  \fBpexec  \-T\|src  \'co  \-rV2  Makefile;  make  VERSION=V2  co\'\fR
.DE
.NH 3
\fICleaning up\fR
.XS
\*(SN Cleaning up
.XE
.PP
If a software package is in a stable state \- that is, it is not being
modified \- then, as an economy measure, the amount of space that it
takes up can be reduced by removing object files plus any other files
that can be regenerated easily. This task is implemented by
.ID
%  \fBpexec  \-T\|clean  make clean\fR
.DE
assuming that the directories containing the files to be removed are
labeled `clean'.