Getting started with

GMKPACK

By
Ryad El Khatib

CNRM / GMAP / ALGO

Version 6.1

2005-04-04

-----------------------------------------------------------------------------------------------------

Prefactory note

This document has been written in order to help people to use the procedure gmkpack.

gmkpack is a procedure that has been written by GCO  and myself in order to create an environment to compile and make binaries from Arpege, Aladin, ODB, ... or others libraries.

The previous version of this precedure, named mkpack, was based on the use of makefiles.
It solved the problem of the dependencies research between source files. But unfortunately it was not properly adapted to handle the so-called "duplicated" subroutines of Aladin. Furthermore the research of dependencies was very slow.

The present procedure is an improvement of the previous system ; it is composed of "home-made" scripts, written in Perl or Shell. Though one can find it less user-friendly, it solves the problem of duplicated subroutines. It is also faster than the previous one as far as dependencies compilation is concerned.

Like the previous system using makefiles, this one will find for you what should be compiled (or re-compiled), by checking the dependencies (due to the use of fortran modules), and by checking whether or not a source file is more recent than its corresponding object file. It will also provide for you all the necessary links to reach the source codes, object libraries, etc.

Nevertheless, there are several differences between the two systems in the way it works as in the way it should be used.
For instance, packs from mkpack and packs from gmkpack are not compatible.

-----------------------------------------------------------------------------------------------------

What is a pack ?

When you want to compile source codes, you have to copy your modified source codes "somewhere" (usually : a directory).
This "somewhere" is somehow a "pack".

A pack is a directory, containing specific subdirectories and files, that will be all created by running gmkpack.
Below this directory, you will compile your modifications and make your libraries and executables.

The use of Arpege/Aladin is made complicated by the need of various "include" files, modules and libraries to achieve an executable.
Gmkpack will provide for you all this environment that you will need.
Therefore, the pack that you will create in your user must depend on a pre-defined "environment", described by an existing Arpege reference cycle.

More generally, we can try to define a pack as follows :
 
 

A pack is a consistent ensemble of scripts, source files, libraries and executables
of all ClearCase projects related to Arpege/Aladin (ie : arp, ald, tfl, tal, odb, uti, ...)

-----------------------------------------------------------------------------------------------------

Why gmkpack ?

Preliminary tests showed that while mkpack.pl looked well designed for GCO purpose, it is actually not properly designed for developers. Gmkpack is a procedure which fits developers' work, and which is supposed to fit as well GCO's work later on.
 
 

gmkpack is a procedure to create a pack and  generate script files
to compile your modified source codes and to make libraries or executables.

-----------------------------------------------------------------------------------------------------

Prepare your environment

Before starting to create a pack, you should add the following lines in your file .profile on the machine where you will operate on your packs ("tora" at this time for Météo-France) :
 

export GMKROOT=/u/gp/mrpm/mrpm602/gmkpack
export ROOTPACK=/u/dp/marp/marp001/pub
export GMKFILE=VPP5000.TORA
  export GMKTMP=$TMPDIR
(or export GMKTMP=/tmp/$(id -u).$$ for instance, if you do not have any $TMPDIR defined yet)
  export HOMEPACK= (fill it yourself) The current custom is to create the binaries in the $workdir directory, because these files are huge.
The drawback is that the files in this directory are volatile, so your binaries may be removed out of your control.
But usually it is easy to re-create them, and meanwhile you can still save them on the archive machine, too.
export HOMEBIN= (fill it yourself) export PATH=$PATH:$GMKROOT/util
export CATMAN=$CATMAN:$GMKROOT/man

Example :
export GMKROOT=/u/gp/mrpm/mrpm602/gmkpack
export ROOTPACK=/u/dp/marp/marp001/pub
export GMKFILE=VPP5000.TORA
export HOMEPACK=$HOME/pack
export HOMEBIN=$WORKDIR/binpack
export PATH=$PATH:$GMKROOT/util
export CATMAN=$CATMAN:$GMKROOT/man
export GMKTMP=$TMPDIR

-----------------------------------------------------------------------------------------------------

Getting started

Before starting, one should have in mind that making a pack with gmkpack is very similar to getting a ClearCase view with cc_getview
 
 

As when you create a ClearCase branch upon an existing GCO release,
you will always create a pack upon an existing GCO pack.










Therefore you will have to define the characteristics of the GCO pack (called : "reference pack" or "source pack") upon which your own pack will be built.

To get the usage of gmkpack,  type :
gmkpack

The system will answer :
Usage: gmkpack -r release [-b branch ] [-n local-pack-version ] [-a -s | -u target-pack [-v reference-pack-version ]] [-l compiler-label ] [-o compiling-flag ] [-f rootpack-directory ] [-p project|program ] [-O] [-m]

Parameters :
--------
 -r = reference release label
 -u = target pack name
 -b = reference branch name (optional, default is "main")
 -v = reference pack version number (optional, default is the latest)
 -l = reference compiler version (optional, default is "L0209")
 -o = compiler options family, (optional, "x" : optimal [default], "g" : debug, "b" : bound checking)
 -f = alternative rootpack directory (optional)
 -p = project|program name for the compilation script
 -m = quiet mode (optional ; to make the compilation script only)
 -O = Observations handling libraries (optional)
 -a = To create a main pack (optional)
 -n = local pack version number (optional, default is the latest existing one)
 -s = To create the scripts to compile the system programs

To start with, let's consider only the mandatory parameter :

    -r : ARPEGE reference release label under Clearcase ; in other words : the main Arpege cycle to be considered.
You can get the list of existing releases by typing : rlspack

Two more arguments are very important, however :

    -u : User's target pack : you can set the name of your choice (it is recommended to choose a name which refers to your corresponding ClearCase branch). If you do not provide this argument the system will build one anyhow.
    -p : Program name to make an executable ; the possible values are listed below. If you do not provide this argument, gmkpack will create a pack without any script to compile or load. Anyhow it will be still possible to generate such scripts later.

Possible program names :

adbias
adscan
aladin
aldodb
arome
arpege
arpodb
atstprog
bator
biascv
blend
blendsur
cabias
cascan
check_limits
ctrodb
ctroulan
cybias
cyprep
cyscan
cysele
ddhc
ddhr
ddht
eatstpro
etestadj
fcqodb
gobptout
gptosp
ioassign
lamflag_odb
lecbdap
mandalay
odbtools
progrid
qscat_25to50
qscat_bufr
qscat_dconeqc
qscat_filter
sptogp
testadj
testfa
For example, let's make a pack named test0 upon the Arpege release CY24T1, with a script for compiling and loading aladin :
%gmkpack -utest0 -r26t1 -paladin

Displayed lines :
/u/gp/mrpm/mrpm602/gmkpack.6.1/util/gmkpack starts.
Creating pack /u/gp/mrpm/mrpm602/pack/test0 upon /u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack ...
Basic directories :
src
src/local
lib
bin -> /work08/mrpm602/binpack/test0/bin
Unsatisfied external references directories :
src/unsxref/quiet
src/unsxref/verboose
Sources control directory :
src/.gmak
Sources view :
local
main
Links :
src/main -> /u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main
Background source descriptors files :
main.sds
"main" tree for ald ...
"main" tree for arp ...
"main" tree for coh ...
"main" tree for odb ...
"main" tree for ost ...
"main" tree for sat ...
"main" tree for tal ...
"main" tree for tfl ...
"main" tree for uti ...
"main" tree for xrd ...
libald.a -> /u/dp/marp/marp001/tampon/lib/ald/al26/al26t1_main.01.L0209.x.a
libarp.a -> /u/dp/marp/marp001/tampon/lib/arp/cy26/cy26t1_main.01.L0209.x.a
libcoh.a -> /u/dp/marp/marp001/tampon/lib/coh/co26/co26t1_main.01.L0209.x.a
libobs.a -> /u/dp/marp/marp001/tampon/lib/obs/ob26/ob26t1_main.01.L0209.x.a
libodb.a -> /u/dp/marp/marp001/tampon/lib/odb/od26/od26t1_main.01.L0209.x.a
libodb.cma-main.a -> /u/dp/marp/marp001/tampon/lib/odb/od26/od26t1_cma-main.01.L0209.x.a
libodb.scr-main.a -> /u/dp/marp/marp001/tampon/lib/odb/od26/od26t1_scr-main.01.L0209.x.a
libost.a -> /u/dp/marp/marp001/tampon/lib/ost/os26/os26t1_main.01.L0209.x.a
libsat.a -> /u/dp/marp/marp001/tampon/lib/sat/sa26/sa26t1_main.01.L0209.x.a
libsct.a -> /u/dp/marp/marp001/tampon/lib/sct/st26/st26t1_main.01.L0209.x.a
libssa.a -> /u/dp/marp/marp001/tampon/lib/ssa/ss26/ss26t1_main.01.L0209.x.a
libssm.a -> /u/dp/marp/marp001/tampon/lib/ssm/sm26/sm26t1_main.01.L0209.x.a
libtal.a -> /u/dp/marp/marp001/tampon/lib/tal/ta26/ta26t1_main.01.L0209.x.a
libtfl.a -> /u/dp/marp/marp001/tampon/lib/tfl/tf26/tf26t1_main.01.L0209.x.a
libuti.a -> /u/dp/marp/marp001/tampon/lib/uti/ut26/ut26t1_main.01.L0209.x.a
libuti.ddl-main.a -> /u/dp/marp/marp001/tampon/lib/uti/ut26/ut26t1_ddl-main.01.L0209.x.a
libxrd.a -> /u/dp/marp/marp001/tampon/lib/xrd/xr26/xr26t1_main.01.L0209.x.a
Background include/module paths ...
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/ald/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/coh/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/odb/misc
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/odb/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/ost/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/sat/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/tal/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/tfl/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/uti/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/module
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/ald_inc/function
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/ald_inc/interface
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/ald_inc/namelist
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/common
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/function
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/interface
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/arp/namelist
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/coh/common
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/coh/namelist
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/odb/CCMA
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/odb/ECMA
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/odb/ECMASCR
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/odb/include
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/odb/interface
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/ost/common
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/ost/interface
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/ost/namelist
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/tal/interface
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/tfl/interface
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/uti/include
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/uti/namelist
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/ddh
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/fa
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/grib_io/include
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/include
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/lfi
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/svipc/include
-I/u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main/xrd/utilities/include
done.
Genesis :
/u/gp/mrpm/mrpm602/gmkpack.5.4/util/gmkpack -r cy26t1 -b main -v 01 -u test0 -l L0209 -o x -p aladin
 The following line has been appended to your file ~/.kshrc :
alias test0='cd $HOMEPACK/test0;ls -l'

Prepare script(s) ...

>  copy compilation and load script on /u/gp/mrpm/mrpm602/pack/test0/ics_aladin ...
/u/gp/mrpm/mrpm602/gmkpack.5.4/util/gmkpack ends.

Comments :

-----------------------------------------------------------------------------------------------------

Visiting a created pack

Now let's visit the pack test0 you have just created :
%test0
total 64
lrwxrwxrwx  logname   group
30
  MM dd hh:mm bin -> $HOMEBIN/test0/bin
-rw-r--r-- logname   group
6958
  MM dd hh:mm ics_aladin
drwxr-xr-x logname   group
512
  MM dd hh:mm lib
drwxr-xr-x logname   group
512
  MM dd hh:mm src

Comments :

total 32
drwxr-xr-x  12 logname  group         512 MM dd hh:mm local
lrwxrwxrwx    1 logname  group           59 MM dd hh:mm main ->  /u/dp/marp/marp001/pub/cy26t1_main.01.L0209.x.pack/src/main         Below each of this directories, you will find again the ClearCase-style of sub-directories. Again :

You will have to put your modified source files below local/ppp at the proper place,
as you would do in a ClearCase session below the project ppp !

-----------------------------------------------------------------------------------------------------

Visiting the script for compilation and load

Let's comment the script ics_aladin for compilation and load (click here) :


Submitting the job of compilation and load, if the job is sucessfull, you will get libraries of your modifications and possibly a binary to execute as well. The procedure will usually generate one library per project involved in your modification, with the name : lib$project.local.a
If not, the tail of the output will tell you why the job failed. Note that meanwhile, if you had already existing libraries or binaries, they will be removed for security reasons.

-----------------------------------------------------------------------------------------------------

Making a comprehensive pack

We shall now explain the optional parameters of gmkpack :

 -b : reference branch name
Like a branch in ClearCase, you may have to work upon a reference pack that is a modification of a main release : this is typically the case for a bugfix.
Therefore you will have to invoke gmkpack giving with : -b branch_name
The default is "main", which correspond to the main release (like in ClearCase).

 -v : reference pack version number
The version number of the pack related to the branch name and release (even if the branch name is "main"). In that case, you will have also to invoke gmkpack with : -v : version_number
By default, the procedure selects the highest existing version number for the selected branch and release.

 -l : reference compiler version
This is a label for the machine compiler version used while building the reference pack. This parameter should not be used so often.

 -o : reference compiler option
This is a character to symbolize the compiling options used for building the reference pack. This parameter should not be used so often. The option "g" stands for a debugging pack, to be used when we really are in a big mess.

 -O : Observations handling libraries
Those who work on data assimilation will need to link more libraries : to force the use of observation libraries one should invoke gmkpack with the option -O ; anyhow this option should no more be used since it is possible to get these libraries linked if the program name has been properly chosen (example : arpodb or aldodb instead of arpege or aladin).

- a : to create a reference pack
This option is used to create a reference pack which should contain everything needed. Usually this option is used by administrators only, though anybody can make his own "main" packs.

-n : to select the version of a pack to create.
By default you start with 1. To increment the version you can set the number of your choice, but it is recomended to set "-n +" : that way the system will consider the highest exiting version number and will increment it.

-f : alternative rootpack directory
This is to be used if you create your packs over a reference pack which does not belong the the official administrator (ROOTPACK)

-s : system program script
For those who makes reference pack : this option creates the script to build some system programs (precompilers) like odb98.x

 -m : Quiet mode
One may be interested in simulating the creation of a pack without making the pack itself. For that you should invoke
gmkpack with the option -m  ; this option will disable the creation of the pack but it will generate the name of the reference
pack and a local script file for compilation and load, that you can check. This option is mainly used to develop the procedure.

Example : Create a pack named mydevs, based on the branch op4 of cycle 26t1, and with a script to compile odbtools program :
%gmkpack -r26t1 -bop4 -umydevs -podbtools

More details are given in the man page of gmkpack.

-----------------------------------------------------------------------------------------------------

Tools

rmpack to remove a pack
flushpack from the current directory : to recursively remove all files except the source files
clearpack from the current directory : to recursively remove all the files except source files and object files
lspack from the current directory : to recursively list all the files
scanpack from the current directory : to recursively list all the source files
vipack to find and edit files
usrpack to list the user's existing packs
admpack to list administrator's existing packs
rlspack to list administrator's existing releases
envpack to display current environment variables for gmkpack
genpack to display the genesis of a pack
logpack to print the logfile of a pack
progpack to list all possible program names handled by gmkpack
resetpack to remove some control files in case of strange behavior of the system.
On the machine Andante, you will find another useful procedure named cc_pack in the directory /u/mrpm/mrpm602/bin ;
this procedure enables you to export source files from a ClearCase branch to you pack on the machine tora, respecting the Clearcase directories tree.
Usage : cc_pack -f filename -l list | -v | -b -P packname
-P packname is the name of your pack on tora ; this option must be supplied.
-f filename to export a single file ; for example : cc_pack -Ptest0 -f dia/wrfudm.F90
-l listname to export the files listed in the file listname
-b to export the whole branch
-v to export the entire view
Notice : to use cc_pack,
    - you should be under a ClearCase session,
    - you should have exported the variable HOMEPACK of tora on Andante (you can set it in your file .profile on Andante for instance)
    - you should have a file .rhosts on tora, containing the line "e-andante.meteo.fr" (to enable remote command from Andante to tora)

-----------------------------------------------------------------------------------------------------

Miscellaneous

-----------------------------------------------------------------------------------------------------

Frequently Asked Questions (... or something like that)

-----------------------------------------------------------------------------------------------------

Manuals

All procedures described have man pages. For more information you are invited to read them !
For example, type : %man gmkpack

-----------------------------------------------------------------------------------------------------

Comment ça marche ?

Le script construit par Gmkpack, baptisé du générique "ics" (Initiative de Compilations Simultanées) par manque de modestie évidente, s'articule en 3 parties :

  1. Compilation
  2. Confection des librairies de code-objet
  3. Edition de liens


La compilation vise à compiler les sources présents dans le pack, sous réserve que :
    - le fichier-objet pour un fichier-source donné n'existe pas,
        ou
    - le fichier-objet est plus ancien que son fichier-source correspondant.
On parlera alors de fichier-objet "périmé" pour le fichier-source en question.
A cette compilation dite "locale" (car directement liée aux fichiers-sources modifiés par l'utilisateur) s'ajoute de façon optionnelle une "compilation des dépendances" : il s'agit de recompiler tous les fichiers qui se trouvent modifiés par le jeu des dépendances des sources les uns par rapport aux autres, sans que leur codes soient eux-même modifiés par l'utilisateur.
La compilation de toutes les dépendances est, en principe, nécessaire avant la constitution de toute librairie de code-objet. On peut cependant s'en affranchir si les 2 conditions suivantes sont respectées (au moins sur les machines Fujitsu) :
    1/ un module de données n'est modifié que par l'ajout de nouvelles variables à la fin du code du module en question
    2/ un module modifié n'est pas lui-même utilisé par un autre module

Voici les étapes successives pour élaborer la compilation :
 

  • Etablissement de la liste des éléments contenus dans le pack : on recherche les fichiers ayant l'une des extensions suivantes : .F90, .F, .f90, .f, .c, .sql, .h, .ddl
  • Précompilation des fichiers *.ddl et mise à jour des fichiers-souches statiques : ceci ne sert qu'à ODB. On contrôle la gestion de nouvelles tables en analysant la date d'un fichier *.ddl par rapport à sont "objet" correspondant, qui est le fichier de même radical et d'extension ".ddl_". On met ensuite à jour les fichiers-souche statiques en cas de modifications dans les requètes sql. les fichiers créés sont rajoutés au contenu du pack.
  • Etablissement du fichier-descripteur des éléments du pack : il s'agit d'un fichier décrivant pour chaque élément son nom, ses dépendances, sa branche d'origine et éventuellement sont nom de module si c'est un module.
  • Traitement des interfaces explicites : on les crée si nécessaire, puis on met à jour le contenu du pack et le fichier-descripteur des éléments du pack.
  • Etablissement de la liste des répertoires contenant des inclusions ou des modules : utile à la compilation, cette étape aboutit à l'élaboration des fichiers cachés .incpath, .incpath.local, .modpath, .modpath.local sour le répertoire principal de tous les fichiers-source. Pour permettre la compilation en mode parallèle, il a été nécessaire d'indiquer le chemin absolu de chaque répertoire pour éviter des problèmes à la traversée des liens symboliques. On fabrique également sous forme d'un fichier caché (.srcpath) la liste des chemins contenant des fichiers-source : cela peut servir à un outil de debugging (Totalview par exemple, en s'en servant pour initialiser la variable TVSEARCHPATH).

  •  
  • Etablissement de la liste ordonnée des éléments à (re)compiler : l'ordre repose sur l'interdépendances des éléments entre eux. Si on demande la compilation des dépendances, la liste ordonnée s'allonge des éléments dépendants extérieurs à la branche de l'utilisateur. Cette étape est particulièrement cruciale. Dans la version actuelle on sépare les éléments ne possédant aucune dépendances des autres, et on rajoute un ordonnancement par rapport à la hiérarchie des "projets" : respectivement pour accélérer la compilation parallèle et permettre un traitement "incrémental" de la compilation dans un souci de mise au point. Ce dernier point pose un problème avec l'existance de modules dupliqués, qui doivent être bannis !

  •  
  • Etablissement de fichiers-descripteurs des éléments à (re)compiler : cette étape permet d'accelérer un peu l'algorithme de compilation parallèle.

  •  
  • Boucle de compilation : la compilation se fait par "étage" : chaque étage correspond à un ensemble d'éléments qui peuvent être compilés simultanément. Pour selectionner les éléments d'un étage, on parcourt la liste ordonnée des éléments à (re)compiler : si un élément donné ne dépend pas des modules figurant parmi ses prédecesseurs, il est traité dans l'étage courant. Si cet élément est un module, il s'ajoute à la liste des modules prédécesseurs. Les "inclusions" (fichiers *.h), n'étant pas compilables, sont systématiquement sélectionnées ; cependant, une exception est faite pour certaines "interfaces" qui sont des fichiers non-compilables mais qui utilisent potentiellement des modules : elles doivent être traitées au même titre que les modules si elles dépendent de modules.

  • Dès qu'on détecte un élément utilisé par l'un de ses prédécesseur, on incrémente l'étage de compilation : ce choix pénalise un peu la parallélisation dès que l'on atteint des sous-programmes simples, mais il permet d'accélérer la fabrication de la liste pour chaque étage qui est nécessairement mono-processeur.
    NB. : la compilation par étage n'est pas indispensable en compilation monoprocesseur, mais elle est nécessaire à la compilation en parallèle.
    Une fois que la liste des éléments d'un étage est établie, on parcourt cette liste pour identifier les fichiers-sources dont l'objet est "périmé". Si un fichier-objet existe et est périmé, on le détruit, et on détruit immédiatement toutes ses dépendances : cette étape cruciale permet de maintenir constamment à jour les éléments d'un pack, et de façon récursive ; en particulier, c'est cette opération que permet de compiler successivement les éléments du pack sans les dépendances d'abord, puis avec les dépendances sans pour autant recompiler ce qui est à jour.
    Néammoins, il existe une option permettant de supprimer cette mise à jour ; dans ce cas tout le contenu du pack sera recompilé.
    Une fois que la liste des éléments périmés d'un étage est établie, on distribue cette liste entre les processeurs. Pour le moment, cette distribution est simplement circulaire. C'est suffisant si le nombre de processeur est petit devant le nombre d'éléments à compiler ; dans le cas contraire, il faudrait, pour optimiser la parallélisation, distributer circulairement la liste des éléments ordonnés par taille décroissante.
    La compilation peut alors se faire par "paquets" d'éléments.
    A la fin de la compilation de tous les éléments d'un étage, on vérifie que tous les fichiers-objets qui ont dû être créés à cet étage sont bien présents dans le pack. Si des fichiers-objets manquent, la procédure envoie un message d'erreur signalant les manquants et s'interrompt : on ne passe pas à l'étage suivant.
    N.B. : lors de l'exploration des éléments périmés, on considère que le fichier-objet d'une inclusion est un fichier suffixé .ok, et sa "compilation" consiste simplement à le créer ("touch").
    Remarque : on peut ignorer la compilation de certains éléments (en particulier quand ils deviennent périmés mais qu'ils apparaissent dans la liste des éléments à recompiler, par le biais des dépendances) : ils doivent alors être signalés de façon explicite dans le script de compilation.
     
  • Compilation : elle s'effectue toujours sur un répertoire temporaire, en particulier lorsqu'il s'agit de compiler des dépendances, pour deux raisons : d'une part parce que la recherche des inclusions se fait toujours prioritairement sur le répertoire où se trouve l'élément à compiler (ainsi fonctionnent les compilateurs !) ; d'autre part pour éviter l'apparition de fichiers-sources "zombies" dans le pack local en cas d'arrêt brutal de la procédure (par temps limite dépassé, ou par toute interruption brutale du système).

  • La compilation des éléments locaux se fait selon les options de compilation demandées par l'utilisateur, et produit un listing. La compilation des dépendances se fait selon les options de compilation du pack de référence, et sans produire de listing.
     


    Toute compilation réussie implique la fabrication d'une librairie de code-objet contenant les modifications faites.
    Il y a en réalité autant de librairies fabriquées que de "projets" (au sens Clearcase) concernés, afin de différentier les sous-programmes dits "dupliqués" (on peut éventuellement créer plusieurs sous-librairies pour un même projet - non détaillé ici pour le moment, mais effectif pour odb et uti).
    En cas d'ambigüité fortuite (2 fichiers-objets de même nom essaient d'entrer dans la même librairie), la procédure envoie un message d'erreur et s'interrompt (ce cas peut se produire si un élément du pack a été écrit dans un mauvais répertoire, et que le jeux des dépendances implique la recompilation de ce même élément).
    Si une librairie existe déjà (à la suite d'une compilation antérieure) et qu'une recompilation effective a eu lieu, cette librairie est détruite, puis recréée avec les fichiers-objets présent dans le pack.
    Que la compilation échoue ou pas, toutes les librairies existantes susceptibles de dépendre de la compilation sont détruites.
    Si une librairie existante devient inutile à l'édition de lien (car plus aucune modification n'y affaire), elle est détruite.
    Dans les autres cas, une librairie existante n'est pas remise à jour si la liste des fichiers-objets du pack est identique à celle de la librairie et que la date de création de chacun de ces fichiers-objets est antérieure à celle de la librairie.
     


    L'édition de lien est conditionnée par la définition (par l'utilisateur) d'un point d'entrée. L'utilisateur garde la main sur le choix et l'ordre des librairies à charger (la procédure propose un choix par défaut aussi "juste" que possible) ainsi que sur les options de chargement.
    Avant l'édition de lien proprement dite, on vérifie que toutes les librairies sont présentes sur disque. Si ce n'est pas le cas pour une librairie de *GCO*, on essaie de la récupérer depuis la machine d'archivage (par l'utilisation de la commande gget). La procédure renvoie la liste ordonnée des librairies effectivement utilisées (en suivant les liens symboliques). Si une librairie est portée manquante, la procédure envoie un message d'erreur et s'interrompt.
    On recherche ensuite le point d'entrée en explorant les éléments du pack. Si le point d'entrée n'est pas trouvé, la procédure envoie un message d'erreur et s'interrompt.
    L'édition de lien se fait sur un répertoire temporaire (GMKTMP) mais l'executable est sauvegardé dans un sous-répertoire du répertoire HOMEBIN, ce qui rend l'executable volatile dans la mesure où HOMEBIN est souvent lui-même défini comme un sous-répertoire de la WORKDIR : ce choix est préféré à celui d'un répertoire de sauvegarde permanent car les executables sont très volumineux.
    Avant l'édition de lien, les librairies à charger sont symboliquement liées sur le répertoire temporaire avec des noms très courts (lib[*]) : ce choix est consécutif à un incident : il semble qu'il y ait une limite à la longueur de la ligne de commande du chargeur (par la même occasion, cela rend l'écho de la commande plus lisible).
     


    1/ Sélection d'un pack à interfaces explicites ou pas :
    Pour chaque projet on commence par définir à partir de quel cycle-clé on traite les interfaces explicites auto-générées ("intfb").
    Si cette définition est omise, c'est qu'on traite l'intfb. Par défaut pour les projets existants autre que arp et ald, le cycle-clé est mis à 99.
    Ensuite, dans les scripts de compilation on définit systématiquement une variable listant les projets supplémentaires à interfaces
    explicites. Pour un pack utilisateur, par défaut il n'y a aucun "projet supplémentaire à interface explicite".
    Pour un pack administrateur, par défaut on définit les "projets supplémentaires à interfaces explicites" en fonction du cycle et
    des fichiers de configuration pour les intfb.
    Ainsi un pack administrateur traite les intfb indiqués dans le script ; tandis qu'un pack utilisateur traite les intfb indiqués dans le script ainsi que ceux du pack-source.

    2/Localisation des interfaces explicites dans les packs :
    elles son placées dans un répertoire caché (".intfb" par défaut) sous chacune des branches (afin de conserver l'usage de la procédure d'élaboration de la liste des dépendances) et sous chaque projet (c'est plus simple que de créer les arborescences complètes).
    Au niveau de la liste des répertoires d'inclusion pour la compilation on rajoute systématiquement les répertoires d'intfb locaux.

    3/Etablissement du contenu du pack local :
    Les procédures d'exploration (scanpack, lspack) ignorent le répertoire .intfb
    Les procédures de nettoyage (clearpack,flushpack) explorent le répertoire .intfb s'il existe.
    En prélude à l'établissement du contenu définitif du pack, et sous réserve que le pack n'est pas un pack administrateur, on détruit toutes les intfb qui ne correspondent pas à une procédure présente dans le pack local (cas d'un sous-programme retiré du pack local).
    Pour toutes les procédures (mais pas les modules) Fortran 90 du pack local qui appartiennent à l'ensemble des projets à interfaces explicites on génère l'interface explicite dans un répertoire temporaire si elle n'existe pas déjà ou si la procédure de référence est plus récente que l'intfb existante ; si cette intfb n'est pas "à jour", on la copie dans le pack local.
    => Pour définir si une intfb est "à jour" on recherche d'abord s'il existe déjà une intfb dans la "vue" du pack ("local", sinon
    branches, sinon "main" ... en mélangeant tous les projets pour ne pas créer d'interfaces dupliquées) ; l'intfb est "à jour" si il
    existe déjà une intfb dans la "vue" et que celle-ci est identique à celle qui a été générée.
    On ajoute les nouvelles intfb à la liste du contenu du pack.

    4/Compilation :
    => On exécute un précompilateur qui réalise les trois tâches suivantes :
    - Contrôle des intfb en trop :
    Une intfb en trop est l'apparition d'une directive d'inclusion d'une intfb dans une procédure alors que cette procédure
    n'appelle pas le sous-programme interfacé par l'intfb. En cas d'intfb en trop on signale l'erreur et on aborte la compilation de
    la procédure incriminée.
    - Contrôle des intfb manquantes :
    Une intfb manquante est l'absence d'une directive d'inclusion d'une intfb alors que le sous-programme concerné est appelé,
    qu'il n'est pas associé à un fichier-interface explicite dans le code-source, et qu'il appartient aux projets à interfaces
    explicites (nécessite de définir la liste des intfb à inclure et la comparer à celle qui est effectivement utilisée). En cas d'intfb
    manquante on signale l'erreur et on aborte la compilation de la procédure incriminée.
    - Exécution du "norms checker" dont le diagnostic sera copié en fin de listing et (partiellement) sur la "dayfile" de compilation.
     


    Le but ultime de cet opération est de ne plus utiliser les options non-standards de l'éditeur de liens symboliques. le traitement ci-dessous n'est cependant pas complètement au point. Mais il fonctionne assez pour traiter des packs administrateurs de type "export".
    Une référence insatisfaite est soit :
    - l'apparition d'une directive d'inclusion dans une procédure, pour laquelle le fichier à inclure n'est pas disponible
    - l'appel à un sous-programme ou une fonction dans une procédure, pour lequel le fichier-objet correspondant n'est pas disponible.
    Pour traiter ces problèmes, un ébauche de solution est en place : un répertoire est créé au même niveau que le répertoire des fichiers-source locaux. Ce répertoire est lui-même subdivisé en deux sous-répertoire. On y loge dans l'un ou l'autre chacun des fichiers manquant. Quand il s'agit d'un fichier à inclure autre qu'une intfb, un fichier vide du même nom suffit. Si il s'agit d'une intfb il faut que ce fichier contienne au moins une ligne pour "passer" le "norms checker. Pour les sous-programmes et les fonction, il suffit d'un fichier vide dont le nom soit celui de la référence insatisfaite suivie d'un caractère "underscore"(par exemple : le sous-programme manquant "toto" sera résolu par l'apparition d'un fichier vide nommé "toto_").
    La liste des références insatisfaites est scindée de façon à différencier un comportement purement passif d'un comportement verbeux ("should not be called"). Elle reprend la liste des procédures externes non-exportées du pack de référence à la création du pack local via des librairies-objets supplémentaires.
     


    La grande nouveauté c'est que les sources accessibles pour modification d'un pack donné se trouvent toujours dans un répertoire qui porte le même nom (par exemple : "local"), quelque soit l'utilisateur. Pour tout sur-pack, les "branches" sont des liens sur le répertoire local d'un autre pack.
    Cette innovation a la vertu d'unifier la gestion des packs utilisateurs, "main", branche sur "main" ou sur un autre utilisateur.
    Une complication de gestion apparait au niveau des recherches de dépendances :
    - le fichier-descripteur des fichiers-source ("gmak.pl" chez gco, "local.sds" sous gmkpack) doit être sauvegardé et devient un fichier caché (sous un répertoire ".gmak" sous le répertoire de tous les fichiers-source) pour éviter tout erreur de manipulation de la part de son propriétaire (effacement, modification incontrôlée).
    A la création d'un sur-pack, les fichiers-descripteurs des branches non-locales doivent être importés et modifiés dans le
    pack local afin d'y remplacer le nom de branche "local" par celui de la branche-lien correspondante (sauf dans le cas "gco"
    ou le fichier est bon tel que : il suffit alors de faire un lien dessus). Dans tous les cas il serait préférable à terme de supprimer ce second champ (information redondante entre la localisation ou le nom du fichier, et son contenu !!)
    Sous re répertoire .gmak on trouvera également d'autres fichiers de contrôle sauvegardés, dont le but est d'accélérer le processus de compilation lorsque certains de ces fichiers de contrôle se trouvent être "à jour" (analyse par rapport au non-changement des inter-dépendances entre les fichiers-source du pack). Néammoins, cette fonction peut être "remise à zéro" en exécutant la commande "resetpack" qui détruira certains fichiers sous ce répertoire .gmak (la destruction des fichiers-descripteurs venant des autres branches serait fatale au pack !).
     


    C'est le cas en particulier du précompilateur "odb98.x".
    On prévoit l'utilisation d'un compilateur odb externalisé : cf variable ODBNAME du fichier de configuration.
    Si cette variable est vide, on fabrique le compilateur dans le pack "main", et on utilise le compilateur du pack main pour les
    packs-utilisateurs. Sinon on utilise le compilateur externe.
    La variable GMKSYS représente le répertoire principal pour l'installation de programmes-système (non-encore
    externalisés) liés à l'utilisation de gmkpack (typiquement : odb98)
    Ce répertoire n'est créé que pour un pack "main". On ne crée ces programmes-système que si GMKSYS est non-vide.
    On crée un lien (un peu maladroit !) entre une fonction externe (comme ODBNAME) et la fonction-remplaçante interne, par
    nom (obsolete !).
    Gmkpack lancé avec l'option "-s" fabrique un script de fabrication pour ce programme-système (répertorié dans les fichiers de configuration) mais il n'est pas nécessaire de l'utiliser : une compilation générale d'un "pack" de base créera ce précompilateur "dans la foulée".
     


    Les fichiers *.ddl sont transcodés par odb98.x en fichiers une série de fichiers : *.ddl_, *.h et *.c qu'on rajoute dans le pack le
    cas échéant (c'est à dire : si le fichier *.ddl_ est différent du fichier *.ddl). On applique en premier lieu le préprocesseur cpp,
    ce qui permet de travailler de façon indépendante de l'organisation des fichiers-source. Il est ainsi inutile de recopier sous chaque "base" les fichiers d'inclusion nécessaires. par contre, chaque "base" doit absolument contenir son fichier *.ddl à côté des requètes .sql, car c'est la seule façon sûre de précompiler les requètes .sql sans faire d'hypothèse sur les noms des fichiers .c qui seront créés par le précompilateur odb98.x ; ainsi, à la première compilation, un répértoire contenant des requètes .sql ne devrait contenir que des fichiers .ddl.