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:

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.

  1. For each new library you wish to create make a directory called lib${NAME} where ${NAME} is the name you have chosen.
  2. Create subdirectories in the new directory and place your code in as complex a file tree as you desire.
  3. 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: