Make(1) scheme
Anyone maintaining USH needs to understand the method used to
maintain an integrated system of source, makefiles, and basic
documentation that is compiled on multiple platforms.
Much thought has been put into the maintenance scheme used to create the
USH utility. This deceptively simple-looking method makes it easy
to share, document, and organize thousands of source code files.
Some of the goals of this system are:
- Minimize number of makefiles needed to be maintained.
Only trivial changes to make(1) files are required to add new
trees of library source code.
- It is easy to maintain various versions of the libraries compiled
with different flags (debugging, optimization, ...).
- It is as simple as possible to add a new OS platform.
- Documentation and code can be easily shared using any common
HTML-compatible WWW browser.
- Code and documentation are integrated into a single file.
- All files can be maintained with a simple ASCII text editor.
- multiple library builds can occur simultaneously on different
platforms without interfering with each other.
- No intermediate .o files are retained.
For the special case of USH a single FORTRAN file is also generated
containing all the expanded source code. This is very handy for use with
analysis and flowcharting packages such as ftnchek(1) and flint(1) but
is not a generic part of the maintenance scheme.
Here is the basic file system layout:
(FORTRAN library prototype) (C library prototype)
*--------------------------*----------------------*----
| | |
lib${NAME} makefiles lib{$NAME}
| | |
|o LIBOBJ |o Makefile.F77 |o LIBOBJ
|o Makefile.F77 |o Makefile.F90 |o
|o Makefile.F90 |o Makefile.C |o Makefile.C
| |o $TARGET_REV.mk |
| | |
*--*--*--* (FORTRAN source tree) *--*--*--* (C source tree)
| | | | | | | |
where LIBOBJ contains the list of FORTRAN 77, Fortran 90+, and C code.
-
For each new library you wish to create make a directory called lib${NAME}
where ${NAME} is the name you have chosen.
-
Create subdirectories in the new directory and place your code in as
complex a file tree as you desire.
-
Go to the top of your library and create two files. For your LIBOBJ
file create a file that looks like:
LIBOBJ_F77 = \
$(LIB)(Geometry/arc2.o) \
$(LIB)(Geometry/uarc.o) \
\
$(LIB)(Shape/juaspct.o) \
\
$(LIB)(Stack/pop.o) \
$(LIB)(Stack/push.o) \
$(LIB)(Stack/Internal/store.o) \
$(LIB)(Stack/Internal/retrieve.o) \
$(LIB)(Stack/Internal/create.o) \
$(LIB)(Stack/Internal/delete.o) \
\
$(NULL)
You may find useful the output of
find . -name '*.[fFc]' -print > seed.list
In the example file above it is assumed you have created three
subdirectories called Geometry,Shape, and Stack. Note that Stack
contains a subdirectory called Internal.
Then create a small file called Makefile.F77 that looks like:
#===============================================================================
SHELL=/bin/sh
# name of library to build (by convention, I name directory to be lib$NAME)
include ../makefiles/INSTALL.mk
LIB=$(INSTALL)/XXXXXXX.a
TARGFILE=LIBOBJ
include ../makefiles/Makefile.F77
#===============================================================================
Where you change XXXXXXX.a to be lib${NAME}.a where ${NAME} is the library name
you chose.
If you are creating a C library instead of a FORTRAN 77 library, change "Makefile.F77"
to "Makefile.C".
All the master makefiles are in the directory "makefiles". The file
INSTALL.mk
defines where the directory is where all libraries will be placed.
Makefile.F77
and
Makefile.C
have the rules for creating library members from your source files. Then there
is a file called $TARGET_REV.mk for each operating system that your libraries
need built on. These currently exist:
Set the environment variable TARGET_REV to one of the supported names (SunOS,
Solaris,HPUX,HPUX10, ...) and the variable MYTARGET to a basic platform name.
Use the script
system(1)
to get the basic names:
TARGET_REV=`systemtype r`
MYTARGET=`systemtype`
Now you are ready to cd(1) into your directory and enter:
make -f Makefile.F77
Once you are set up you merely
put a source file where you want and put it's filename
into the LIBOBJ for that library file as shown.
Anyone can add as many $TARGET_REV files as they like with different compiler
switches (debug, profiling, performance, ...) if they desire.
When you make a library it will create a directory in the install directory called
$TARGET_REV (to keep it separate from the other libraries) and place your library
file there.
Everything is placed in /tmp while being compiled so that multiple machines can simultaneously
compile (assuming the machines have unique /tmp directories).
Keeping code as HTML documents
Files do no have to end in .f or .F or .c!
Major source files are kept in HTML-format to make it easier to locate
and document particular routines. The
html2f and
html2C
scripts and
a Makefile with rules for HTML files is used to create this simple
environment. When compiled, files ending in .html or .HTML will
have extracted only those lines between lines containing
<!--FORTRAN--><xmp>
</xmp><!--/FORTRAN-->
or
<!--FORTRAN90--><xmp>
</xmp><!--/FORTRAN90-->
or
<!--C--><xmp>
</xmp><!--/C-->
Building USH
In the case of USH the script make.shell
is run on each required platform. make.shell(1) uses the system(1)
script to get $MYTARGET and $TARGET_REV to desired values,
takes care of some annoying things like search path differences
on various platforms, and goes into each library directory and
starts make. All output is recorded into log files in the directory
where make.shell was started.
The non-library and non-basic builds
Hershey fonts
The Hershey fonts are data files, not library objects. The hershey directory is
an exception to the above. The makefile there compiles a program that reads the
Hershey definition files in and generates the binary files needed by the VOGLE
graphics library.
non-basic libvogle.a build
The makefile scheme is very extensible. You can actually have multiple target
lists in single directories and maintain multiple libraries from a single file
system or supplement the generic info in the makefiles directory with library-specific
options. The libvogle directory shows an example of this where platform-specific
variable names must be defined.
Main program builds and loads
Main programs are all compiled with
ccall and with otherwise normal makefiles. This is
because the load phase often takes radically different switches, library names,
library search paths and whatnot.
Proven portability
Note that many make(1) extensions or make-like utilities like GNU
make, Imake, and vendor extensions can be used to create a similar
environment but this method only depends on a standard POSIX make(1)
command and has been used on SunOS, NeXT, Solaris, UNICOS, ULTRIX,
HP-UX.9, HP-UX.10, AIX, IRIX64, Tru64, IRIX, LINUX, ... If you do hit a problem,
you should be able to use GNU make as a substitute for make.
If you can't find what you want, you may manually
index the LIBRARY files
The files outside of the makefiles directory used to make USH and the
libraries are:
These are conventional makefiles: