CMT
Configuration Management Tool

Version v1r19
Christian Arnault
arnault@lal.in2p3.fr

Document revision date : 2006-11-09

General index


 1 - Presentation

This environment, based on some management conventions and comprising several utilities, is an attempt to formalize software production and especially configuration management around a package -oriented principle.

The notion of packages represents hereafter a set of software components (that may be applications, libraries, documents, tools etc...) that are to be used for producing a system or a framework . In such an environment, several persons are assumed to participate in the development and the components themselves are either independent or related to each other.

The environment provides conventions (for naming packages, files, directories and for addressing them) and tools for automating as much as possible the implementation of these conventions. It permits the description of the configuration requirements and automatically deduce from the description the effective set of configuration parameters needed to operate the packages (typically for building them or using them).

CMT lays upon some organisational or managerial principles or mechanisms described below. However, it permits in many respects the users or the managers to control , specialize and customize these mechanisms, through parameterization, strategy control and generic specifications.

Following these definitions, the basic configuration management operations involved here (and serviced by the CMT tools) consist of :


 2 - The conventions

This environment relies on a set of conventions, mainly for organizing the directories where projects and packages are maintained and developed :


 3 - The architecture of the environment

This environment is based on the fact that one of its packages (named CMT ) provides the basic management tools. CMT , as a package, has very little specificities and as such itself obeys the general conventions.

Then the complete software base is organized in terms of projects (or sub-projects ), containing consistently managed package sets. Projects are localized either globally or individually:

Packages are localized respectively to the projects they belong to.

It should be noted that the choice of a location for installing CMT itself is totally independent of the locations where projects are installed and managed.

CMT is operated through one main user interface : the cmt command, which operates the CMT conventions and which provides a set of services for :

Several other utilities are also provided for some specific activities (such as the automatic production of shared libraries, C prototypes, management of interactions between CVS and CMT itself, the management of a similar architecture for Windows or OS9 , setting up protections for packages (through locks) etc...).


 3. 1 - Supported platforms

CMT has been ported and tested on a wide range of machines/operating systems, including : This in particular means that a package developped on one platform may be re-configured towards any of these platforms without any change to its configuration description. All platform specific tools will be dynamically reconfigured and parameterized transparently.

 4 - Defining and managing projects

In the CMT terminology, the complete software base is composed of CMT packages. Those packages are organized into sub-projects. The semantics of a sub-project is very opened since it's merely an area for grouping CMT packages. Typically sub-projects may correspond to

Considering the simple structuring aspects of sub-projects, two important configuration parameters (environment variables) handled by CMT must be understood before attempting to manage packages:

Projects receive detailed descriptions or specifications in a dedicated project file , always located in a cmt directory at their top directory level, and named cmt/project.cmt . It can receive the following specifications:

project <project-name>          [1]
project-use specifications...   [2]
strategy specifications...      [3]
  1. The project name specified here takes precedence over the project name specified in the directory structure. However when CMTPROJECTPATH is not specified, this may cause conflicts in the localization of projects. In this case it's highly recommended to always use the same naming convention in project files as in the directory hierarchy.

  2. Projects are hierarchized as a directed acyclic graph. The minimal hierarchy simply corresponds to the order of the CMTPATH items. A more complex hierarchy can be specified through use statements between sub-projects. This hierarchy also defines a parent/child relationship between projects. If a project A uses another project B , A is also named the parent and B the child

  3. CMT Strategies (for build or setup) are separately collected into each project. Therefore one can apply different strategies to different sub-projects. The strategy specifications may appear in requirements file of any package of a project or in the cmt/project.cmt project file.

    By default a project inherits the strategies of its parents. Or if it's the top project, it follows the default strategies defined by CMT (Refer to this appendix to see the default strategies currently defined by CMT).


 4. 1 - The project file

The project file can be created using the command:

> cmt create_project <project-name> [<release>] [<path>]
> cmt create_project <project-name> [<release>] [<path>] [-use=<package>:<version>:<path>]...

This will create the complete directory hierarchy from the current directory (or, when it is specified from the optional project path). It will also create a project file containing the project name, and optionnally will initialize it with some use statements.

Note that the <release> argument may be left empty (or to an empty string). In this case, the directory hierarchy will be limited to the single level of the project name.
<path>/<project-name>/<release>/cmt/project.cmt
<path>/<project-name>/cmt/project.cmt

As an example, we create the following projects:

> cmt create_project WorkArea "" /test
> cmt create_project ProjectA 1.0 /test
> cmt create_project ProjectB 1.0 /test

And we manually fill CMTPATH with:

/test/WorkArea:/test/ProjectA/1.0:/test/ProjectB/1.0

Then, when standing in the WorkArea the following projects will appear displayed from bottom to top as

> cd /test/WorkArea
> cmt show projects 
WorkArea (in /test/WorkArea) (current)
  ProjectA 1.0 (in /test/ProjectA/1.0)
    ProjectB 1.0 (in /test/ProjectB/1.0)

Of course the preferred way to characterize this software base should rather be based on specifying the relationships between those three sub-projects, through the use statements in the projects files.

For instance in our little example, we could add the following statement into the project file of WorkArea:

use ProjectA 1.0

and the following statement into the project file of ProjectB:

use ProjectB 1.0

Then instead of specifying CMTPATH we'd rather simply define CMTPROJECTPATH as:

/test

This complete sequence may also be shortened as follows:

> cmt create_project ProjectB 1.0 /test
> cmt create_project ProjectA 1.0 /test -use=ProjectB:1.0
> cmt create_project WorkArea "" /test -use=ProjectA:1.0

 4. 2 - Projects and strategies

Few behaviours of the configuration management process can be tailored with respect to CMT, via means of defining strategies . Then according to these strategies, CMT will behave in well defined ways.

Every strategy setting is a boolean value, instructing CMT to activate or not a given behaviour. As such it defines two mutually exclusive CMT tags and it activates one of them.

<project>_<have_item> 
<project>_<have_not_item> 

Examples

<project>_with_install_area
<project>_without_install_area
<project>_config
<project>_no_config
<project>_root
<project>_no_root
<project>_cleanup
<project>_no_cleanup
<project>_with_version_directory
<project>_without_version_directory
<project>_prototypes
<project>_no_prototypes

In the context of a hierarchy - a graph - of projects, strategies are transmitted along the graph, according to the use relationships specified between the projects. A project transmits its strategies to its clients except when one of them overrides those strategies.

Several mechanisms help defining project specific properties, and more specifically making use of the strategies:


 4. 3 - CMTPROJECTPATH

This is an environment variable containing a search list, very similar to the well know Unix or Windows PATH environment variable. It specifies a list of file paths where CMT projects can be found. The syntax of this search list follows the standard syntax of search lists, i.e. items are separated using a : character on Unix and a ; character on Windows.

One should understand this search list as the primary mechanism to locate sub-projects in the software base, and therefore packages. This in particular can completely replace the CMTPATH -based search mechanism for packages that was used before v1r18 . However the two mechanisms are still both supported and in fact interact with each other.

A sub-project in itself is a multi-level directory structure, located below one of the items of this search list, and composed of:

Then, below this directory structure, we find

A typical example of such a structure could be:

/project-area1/Reconstruction/1.0/cmt/project.cmt
                                 /RecA/...
                                 /RecB/...
/project-area1/Reconstruction/2.0/cmt/project.cmt
                                 /RecA/...
                                 /RecB/...

/project-area1/Simulation/1.0/cmt/project.cmt
                             /SimA/...
                             /SimB/...
/project-area1/Core/1.0/cmt/project.cmt
                       /CoreA/...
                       /CoreB/...


/project-area2/ProductA/1.1.2/cmt/project.cmt
                             /PA_A/...
                             /PA_B/...
                             /PA_C/...
/project-area2/ProductB/v1r8p3/cmt/project.cmt
                              /PB_A/...
                              /PB_B/...
/project-area2/ProductB/v1r10/cmt/project.cmt
                             /PB_A/...
                             /PB_B/...   

In this example:

This search list is used to interpret the use statements written in the project files. This project use statement takes the form:

project-use : use project-name project-release

Typically, in our example one could construct the project file of the Reconstruction sub-project as follows:

use Core 1.0
use ProductA 1.1.2

Note that sub-project release identifiers are always considered using a perfect-match principle.

Structuring the set of sub-projects comprising a software base is sufficient to permit CMT to find all sub-projects and thus all packages in them. Defining CMTPROJECTPATH and installing the list of use statements in all appropriate project files entirely suppress the need of manually defining the CMTPATH search list.


 4. 4 - CMTPATH

This is an environment variable containing a search list, very similar to the well know PATH environment variable, containing a list of file paths where CMT packages can be found. The syntax of this search list follows the standard syntax of search lists, i.e. items are separated using a : character on Unix and a ; character on Windows.

When the software base is organized and configured using the CMTPROJECTPATH search list and project-use statements in the project files, this search list is automatically and internally generated by CMT, and therefore it should not be manually defined nor manipulated. If this is your case, you can skip this section

It is possible to manually define this search list (when CMTPROJECTPATH is not defined or when project files are not provided)

There should be one entry per package area, and the list is ordered. The order of items is used to prioritize the package search.

CMTPATH can be specified:

The project file (i.e. the file cmt/project.cmt ), when it exists for the current package (i.e. upstream in the directory hierarchy), also provides an automatic value for the CMTPATH search list.

 5 - Installing a new package

We consider here the installation of a user package. Installing CMT itself requires special attention and is described in a dedicated section of this document.

Therefore, we assume that CMT is already installed in some location in the system. One first has to setup CMT in order to gain access to the various management utilities, using for example the shell command:

csh> source /lal/CMT/v1r19/mgr/setup.csh

or 

ksh> . /lal/CMT/v1r19/mgr/setup.sh

or 

dos> call \lal\CMT\v1r19\mgr\setup.bat

Obviously, this operation must be performed (once) before any other CMT action. Therefore it is often recommended to install this setup action straight in the login script.


The setup script used in this example is a constant in the CMT environment : every configured package will have one such setup script automatically generated and installed by CMT . It is one important entry point to any package (and thus to CMT itself). It provides environment variable definitions for all related (used ) packages (A corresponding cleanup script is also provided). This script contains a uniform mechanism for interpreting the  requirements  file so as to dynamically define environment variables, aliases for the package itself and all its used packages. It is constructed once per package installation by the cmt create command, or restored by the cmt config command (if it has been lost).


It is generally good to start by immediately defining a project . This project is our first disk area where CMT packages will be located. Remember that several such projects can be set up and defined. The simplest way to do this is:

> cmt create_project Dev
------------------------------------------
Configuring environment for project Dev
CMT version v1r19.
------------------------------------------
Installing the cmt directory
Creating a new project file 

This creates a project structure Dev/cmt/project.cmt from the current directory. Once this project has been created we have a complete environment to start creating packages below Dev and working out our software base.

A package is primarily defined by a name and a version identifier (this duet actually forms the complete package identifier ). These two attributes will be given as arguments to cmt create such as in the following example :

csh> cd Dev
csh> cmt create Foo v1
------------------------------------------
Configuring environment for package Foo version v1.
CMT version v1r19.                              [1]
Root set to /home/arnault/Dev.
System is Linux-i686                                     [2]
------------------------------------------
Installing the package directory                         [3]
Installing the version directory
Installing the cmt directory
Installing the src directory
Creating setup scripts.
Creating cleanup scripts. 
  1. This shows which actual CMT version you are currently using
  2. This shows the current configuration tag (also available by the cmt system command). In this example this is a Linux machine
  3. This shows the detailed construction of the complete directory structure, starting from the top directory which has the name of the package. Since we are creating a completely new package, there will be by default only two branches below the version directory : cmt and src .

The package creation occured from the current directory, creating from there the complete directory tree for this new package.

In the next example, we install the package in a completely different area, by explicitly specifying the path to it as a third argument to cmt create :

> cmt create Foo v1 /ProjectB 
------------------------------------------
Configuring environment for package Foo version v1.
CMT version v1r19.
Root set to /ProjectB.
System is Linux-i686
------------------------------------------
Installing the path directory
Installing the package directory
Installing the version directory
Installing the cmt directory
Installing the src directory
Creating setup scripts.
Creating cleanup scripts. 

Several file creations occurred at this level : One may then setup this new package by running the setup script (which will not have much effect yet since the requirements file is empty) :
sh> cd ~/mydev/Foo/v1/cmt 
sh> . setup.sh 
or
csh> cd ~/mydev/Foo/v1/cmt 
csh> source setup.csh 
or
dos> cd \mydev\Foo\v1\cmt 
dos> call setup.bat

The FOOROOT and FOOCONFIG environment variables are defined automatically by this operation.

It should be noted that running the setup script of a package is not always necessary for building operations. The only situation where running this script may become useful, is when an application is to be run, while requiring domain specific environment variables defined in one of the used packages. Besides this particular situation, running the setup scripts may not be needed at all.

Lastly, this newly created package may be removed by the quite similar remove command, using exactly the same arguments as those used for creating the package.

csh> cd mydev
csh> cmt remove Foo v1 
------------------------------------------
Removing package Foo version v1.
CMT version v1r19.
Root set to /home/arnault/mydev.
System is Linux-i686
------------------------------------------
Version v1 has been removed from /home/arnault/mydev/Foo
Package Foo has no more versions. Thus it has been removed.
or:
csh> cmt remove Foo v1 /ProjectB
------------------------------------------
Removing package Foo version v1.
CMT version v1r19.
Root set to /ProjectB.
System is Linux-i686
------------------------------------------
Version v1 has been removed from /ProjectB/Foo
Package Foo has no more versions. Thus it has been removed.

So far our package is not very useful since no constituent (application or library) is installed yet. You can jump to the section showing how to work on an application or on a library for details on these operations or we can roughly draw the sequence used to specify and build the simplest application we can think of as follows:

csh> cd ~/mydev/Foo/v1/cmt
csh> cat >../src/FooTest.c 
#include <stdio.h>

int main ()
{
  printf ("Hello Foo\n");
  return (0);
}

csh> vi requirements 
... 
application FooTest FooTest.c 
csh> gmake
csh> source setup.csh
csh> FooTest.exe
Hello Foo

Directly running the application is possible since the application has been installed after being built in an automatic installation area reachable through the standard PATH environment variable

This can also be integrated in the build process by providing the -check option to the application definition:

csh> cd ../cmt 
csh> vi requirements 
... 
application FooTest -check FooTest.c 
csh> gmake check
Hello Foo

 6 - Localizing a package

In the next sections, we'll see that packages reference each other by means of use relationships. Generally packages are found in different locations, according to the project - or sub-project - they belong to. CMT provides a quite flexible mechanism for localizing the referenced packages.

The first ingredient we need at this level is to understand how projects themselves are localized, since packages will be found inside project areas. You should therefore refer to the section on projects where the complete mechanism based on CMTPROJECTPATH or CMTPATH is described.

However, there is one special case where this path list can be avoided, i.e. when only one project is considered. In this case, the knowledge of this single project area can simply be deduced from the detection of the project file, created at the top of its disk space.

A given version of a given package is always referred to by using a use statement within its  requirements  file. This statement should specify the package through three keys :

use Bar v7r5                    [1]
or
use Bar v7r5 A                  [2]
or
use Bar v7r5 /ProjectB/A        [3]

Given these keys, the referenced package is looked for according to a prioritized search list which is (in decreasing priority order) :

  1. the absolute access path, if the use path is absolute (case #3),
  2. the access paths registered in the configuration parameter CMTPATH (and in decreasing priority, the first element being searched for first).

If the path argument is specified as a relative path (case #2 above) (ie. there is no leading slash character or it's not a disk on windows machines), it will be used as an offset to each search case. The search is done starting from the list specified in the CMTPATH configuration parameter; and the offset is appended at each searched location.

As an example, if the CMTPATH parameter contains:

/home/arnault/mydev:/ProjectB 

Then a use statement (defined within a given package) containing :

... 
use Bar v7r5
use BarA v1 A
would look for the package Bar from :
  1. /home/arnault/mydev/Bar/v7r5/cmt
  2. /ProjectB/Bar/v7r5/cmt
Whereas the package BarA would be searched from :
  1. /home/arnault/mydev/A/BarA/v1/cmt
  2. /ProjectB/A/BarA/v1/cmt
The packages are searched assuming that the directory hierarchy below the access paths always follow the convention :
  1. there is a first directory level exactly named according to the package name (this is case sensitive),
  2. then (optionally) the next directory level is named according to the version tag,
  3. then there is a branch named cmt ,
  4. lastly there is a requirements file within this cmt branch.
Thus the list of access paths is searched for until these conditions are properly met.

The actual complete search list can always be visualized by the command:

> cmt show path
# Add path /home/arnault/dev from CMTPATH
# Add path /ProjectB from CMTPATH
#
/home/arnault/dev:/ProjectB


 7 - Assigning semantics to packages. Common practices

Generally speaking, CMT makes no assumption on how or why is used a package. However past experience has shown that packages can be categorized according to their purpose or their type of contents.

 7. 1 - The primary package

This is the most general and basic pakage type, which provides actual pieces of software, such as libraries or applications. Generally the main activities performed by such a package include building the software (compiling, linking), testing, generating the documentation, installing, ...

A typical package of that kind will contain:

The requirements file will generally contain at least library and application statements.


 7. 2 - The policy package

This kind of package only provides conventions, working methods, general purpose shell scripts but generally provides no software per se. It is designed to gather all policies and management conventions for a project or a sub project.

The basic contents of such a package is the requirements file including

In principle the idea when such a policy package is defined, is that all packages of the project or of the sub-project will use it

Global patterns may be specified so as to automate the applying of basic policies and conventions.

Typical examples of policies that are profitably specified in such a package are:

In large projects, it is even often desirable to split the policies into a set of specialized policies and to associate one dedicated policy package with each of those.

Then the global policy package will use them

 7. 3 - The container or management package

In large projects, it's often useful to decompose the software base into specialized domains (Core software, Graphics, Database, Online, etc...) or subsets of the software (eg per detector in a physics experiment). Then a container package consists in constructing a simple package with only one requirements file in it and only containing a set of use statements.

Management activities directly related with the associated sub-domain can then be undertaken through this special package:

Generally the use statements installed in a container package make use of explicit version specification (and prohibit wild carding) since each version of this container package acts as a reference of the set of version tags validated for the packages of the domain.


 7. 4 - The release package

This package is one particular example of the container concept, but dedicated to manage the project-wide activities. This release package is the primary target of the project manager. It will generally receive as its version tags the version tags assigned to the project releases themselves.

 7. 5 - The glue or interface package

This kind of package defines an interface to an existing software product not managed in the context of the project itself. Typical examples concern:

The primary goal fo such a glue package is to convert the management conventions and policies expected by the referenced product to the ones appropriate for the current project.

Generally this kind of package only provides a requirements file, or make fragments used to automate some actions (typically when document generation is expected from thie interfaced product)


 8 - Managing site dependent features - The CMTSITE environment variable

Software bases managed by CMT are often replicated to multiple geographically distant sites (as opposed to machines connected through AFS-like WAN). In this kind of situation, some of the configuration parameters (generally those used for instance to reference local installations of external software) take different values.

The CMTSITE environment variable or registry in Windows environments, is entirely under the control of the site manager and can be set with a value representing the site (typical values may be LAL , Virgo , Atlas , LHCb , CERN , etc.).

This variable, when set, corresponds to a tag which can be used to select different values for make macros or environment variables.

A typical use for this tag is to build up actual values for the location path of an external software package. Here we take the example of the Anaphe utility:

macro AnapheTOP "" \
      CERN  "/afs/cern.ch/sw/lhcxx" \
      BNL   "/afs/rhic/usatlas/offline/external/lhcxx" \
      LBNL  "/auto/atlas/sw/lhcxx"

 9 - Configuring a package

The first ingredient of a proper package configuration is the set of configuration parameters which has to be specified in a text file uniquely named  requirements  and necessarily installed in the cmt branch of the package directory tree.

An empty version of this file is automatically created the first time the package is installed, and the package manager is expected to augment it with configuration specifications.

The primary goal of this configuration file is to specify any configuration information for this package. There is virtually no limit to what could be specified there. And we can expect to find exhaustive information about:

Many configuration parameters are supposed to be described into this  requirements  file - see the detailed syntax specifications here - namely :

Generally, every such appropriate parameter will be deduced on demand from the  requirements  file(s) through the various query functions available from the cmt main driver. Therefore there is no systematic package re-configuration per se, besides the very first time a package is newly installed in its location (using the cmt create action).

Query actions (generally provided using the cmt show ... family of commands) are to be embedded in the various productivity tools, such as the setup shell scripts, or makefile fragment generators.

These query actions always interpret the set of  requirements  files obtained from the current package and from the packages in the effective used chain. Symbols, tags and other definitions are then computed and built up according to inheritance-like mechanisms set up between used packages.

Conversely one may say that parameters defined in a  requirements  file are meant to be exported to the clients of the package.

Other configuration parameters are also optionally inserted from the HOME and USER context requirements files

Typical examples of these query functions are:


10 - Selecting a specific configuration

A configuration describes the conditions in which the package has to be built (ie. compiled and linked) or applications can be run. This configuration can depend on : Carefully describing this configuration is essential both for maintenance operations (so as to remember the precise conditions in which the package was built) and when the development area is shared between machines running different operating systems, or when a project has to be deployed on several sites.

10. 1 - Describing a configuration

CMT relies on several complementary conventions or mechanisms for this description and the associated management. All these conventions rely on the concept of configuration tags .

  1. Some aspects of the configuration - and their associated tags - are automatically deduced from some standard environment variables that the user is expected to specify (typically using shell commands):

    • CMTCONFIG describes the current settings for producing binary objects. One default value is provided automatically by CMT, but generally project will override it to apply specific conventions.

      The default value is computed by CMT in the ${CMTROOT}/mgr/cmt_system.sh shell script.

      This script automatically builds a value characterizing both the machine type and the opebrating system type (using a mixing of the uname standard UNIX command with various operating system specific definitions such as the AFS based fs sysname command)


    • CMTSITE characterizes the current site. Its syntax is completely free

    • CMTEXTRATAGS may contain a space-separated list of additional tags to systematically activate


    Note that the CMTBIN variable which represents the current binary installation of CMT itself does NOT correspond to any tag.

  2. Some aspects of the configuration represents the implicit knowledge CMT gets of the current context:

    • The value given by the uname standard Unix facility is always a valid configuration tag. (eg. Linux )
    • The current major version id of CMT is a valid tag and takes the form CMTv<n> (eg. CMTv1 )
    • The current minor version id of CMT is a valid tag and takes the form CMTr<n> (eg. CMTr19 )
    • The current patch id of CMT is a valid tag and takes the form CMTp<n> (eg. CMTp20030616 )
    • The current sub-project to which the current package belongs, and the various tags automatically generated by CMT to qualify the strategy options.
    • The current hardware understood as filled in the cmt_hardware macro
    • The current OS understood as filled in the cmt_system_version macro
    • The version of the C++ compiler understood as filled in the cmt_compiler_version macro

  3. During a make session, each individual target being rebuilt may define its own context, when the -target_tag is set to the associated constituent, and this is materialized with a dedicated tag named target_<constituent> .

    For instance, a package defines a library A and an application P , both in the default group. Both constituents have their -target_tag option set. Thus, when the standard make command is run, then those two targets will be rebuilt successively (eg A then B ). Then, during the build of A (and only then) the tag named target_A will be active and during the build of B , the tag named target_B will in turn be active.

    library A -target_tag A.cxx
    application P -target_tag P.cxx
    
    macro_append cppflags "" target_A "-DA" target_P "-DP"

  4. During the execution of an action , a specific context is created, which is materialized with a dedicated tag named target_<action> , very similarly to the target tags for constituents.

  5. User defined tags can be explicitly or implicitly activated:

    • explicitly from the cmt command line, using the -tag=<tag-list> option
    • explictly from requirements files using the apply_tag <tag> syntax
    • implicitly from requirements files using the tag association syntax, when a tag is associated with an otherwise activated tag. One example is the Unix tag associated by CMT itself with most Unix variants
The minimal tag set available from CMT can be visualized as follows (note that the exact output will obviously not necessarily be the one presented in this document according to the context effectively used):
> cd ${CMTROOT}
> cmt show tags
CMTv1 (from CMTVERSION)                                                   [1]
CMTr19 (from CMTVERSION) package CMT implies [CMTr14]                     [1]
CMTp20040701 (from CMTVERSION)                                            [1]
Linux (from uname) package CMT implies [Unix]                             [2]
i686-rh73-gcc32-opt (from CMTCONFIG)                                      [3]
CERN (from CMTSITE)                                                       [4]
CMT_prototypes (from PROJECT) excludes [CMT_no_prototypes]                [5]
CMT_with_installarea (from PROJECT) excludes [CMT_without_installarea]
CMT_setup_config (from PROJECT) excludes [CMT_setup_no_config]
CMT_setup_root (from PROJECT) excludes [CMT_setup_no_root]
CMT_setup_cleanup (from PROJECT) excludes [CMT_setup_no_cleanup]
CMTr14 (from package CMT)
i686 (from package CMT)                                                   [6]
rh73 (from package CMT)                                                   [7]
gcc32 (from package CMT)                                                  [8]
Unix (from package CMT) excludes [WIN32 Win32]                            [9]
  1. Implicit tags deduced from the current version of CMT
  2. Implicit tag obtained from the uname command (note that there is an associated tag defined here)
  3. The current value of CMTCONFIG
  4. The current value of CMTSITE
  5. The strategy tags
  6. Automatic detection of the hardware
  7. Automatic detection of the current OS
  8. Automatic detection of the C++ compiler version
  9. A indirectly activated tag (associated with another active tag)

10. 2 - Defining the user tags

The user configuration tags can generally be specified though various complementary mechanisms:


10. 3 - Activating tags

By default, CMTCONFIG , uname and CMTSITE (also named system tags) are always active.

The tag associated with the current project name as well as those describing the strategy properties of all projects are also always active.

The target tags associated with constituents (when the -target_tag option was set on them) or with actions are automatically activated during the build of the constituent or during the execution of the action.

It is possible to activate other tags through the following arguments to any cmt command:


Beware that giving these arguments generally make the selected tag set active only during the selected command. Therefore two different CMT commands run with different tag sets will generally yield different results.

However it's often useful to state that a given tag or tag set should be active. This can be obtained by the following mechanisms:

  1. Forcing a tag in a requirements file using the apply_tag  syntax

    Eg the following syntax installed in a requirements file will force the tag foo :
    tag_apply foo
    > cmt show tags
    CMTv1 (from CMTVERSION)
    CMTr19 (from CMTVERSION)
    CMTp0 (from CMTVERSION)
    Linux (from uname)
    Linux-i686 (from CMTCONFIG) package CMT implies [Linux]
    A (From PROJECT)
    Default (from Default)
    foo (from package Foo)
  2. Implying a tag from another one using the tag association syntax
    tag Linux foo
    > cmt show tags
    CMTv1 (from CMTVERSION)
    CMTr19 (from CMTVERSION)
    CMTp0 (from CMTVERSION)
    Linux (from uname) package Foo implies [foo]
    Linux-i686 (from CMTCONFIG) package CMT implies [Linux]
    A (From PROJECT)
    Default (from Default)
    foo (from package Foo)
  3. Through conventionally encoded values of CMTCONFIG
    tag Linux-foo Linux foo
    > export CMTCONFIG=Linux-foo
    > cmt show tags
    CMTv1 (from CMTVERSION)
    CMTr19 (from CMTVERSION)
    CMTp0 (from CMTVERSION)
    Linux (from uname)
    Linux-foo (from CMTCONFIG) package Foo implies [Linux foo]
    A (From PROJECT)
    Default (from Default)
    Linux-i686 (from package CMT) package CMT implies [Linux]
    foo (from package Foo)

The current active tag set can always be visualized using the cmt show tags command.

> cmt show tags
CMTv1 (from CMTVERSION)
CMTr19 (from CMTVERSION)
CMTp0 (from CMTVERSION)
Linux (from uname)
Linux-i686 (from CMTCONFIG) package CMT implies [Linux]
A (From PROJECT)
Default (from Default)

> cmt -tag_add=tag1,tag2,tag3 show tags
CMTv1 (from CMTVERSION)
CMTr19 (from CMTVERSION)
CMTp0 (from CMTVERSION)
Linux (from uname)
Linux-i686 (from CMTCONFIG) package CMT implies [Linux]
A (From PROJECT)
tag1 (from arguments)
tag2 (from arguments)
tag3 (from arguments)
Default (from Default)

Typical usages of those extra tags are:

All symbol definitions providing specific values triggered by the active selectors will be selected, such as in:

macro_append cppflags "" \
             debug    " -g "

11 - Working on a package

In this section, we'll see, through a quite simple scenario, the typical operations generally needed for installing, defining and building a package. We are continuing the example of the Foo package already used in this document.


11. 1 - Working on a library

Let's assume, as a first example, that the Foo package is originally composed of one library libFoo.a itself made from two sources : FooA.c and FooB.c . A shared flavour of the library libFoo.so or libFoo.sl or libFoo.dll ) is also foreseen.

The minimal set of branches provided by CMT (once the cmt create operation has been performed) for a package includes src for the sources and cmt for the Makefiles and other scripts.

The various tools CMT provide will be fully exploited if one respects the roles these branches have to play. However it is always possible to extend the default understanding CMT gets on the package by appropriate modifiers (typically by overriding standard macros).

Assuming the conventional usage is selected, the steps described in this section can be undertaken in order to actually develop a software package.

We first have to create the two source files into the src branch (typically using our favourite text editor). Then a description of the expected library (ie. built from these two source files) will be entered into the requirements file. The minimal syntax required in our example will be :

csh> cd ../cmt
csh> vi requirements             (1)
library Foo FooA.cxx FooB.cxx
  1. the  requirements  file located in the cmt branch of the package receives the description of this library component. This is done using one library statement.

The cmt create command had generated a simple Makefile (or NMake file) which is generaly sufficient for all standard operations, since CMT continuously and transparently manages the automatic reconstruction of all intermediate makefile fragments. We therefore simply and immediately execute gmake as follows:

...v1/cmt> gmake QUIET=1
------> (Makefile.header) Rebuilding constituents.make
------> (constituents.make) Rebuilding setup.make Linux-i686.make         [1]
setup.make ok
------> (constituents.make) Rebuilding library links
------> (constituents.make) all done
------> (constituents.make) Building Foo.make                             [2]
Library Foo
------> (constituents.make) Starting Foo
------> (Foo.make) Rebuilding ../Linux-i686/Foo_dependencies.make         [3]
rebuilding ../Linux-i686/FooA.o
rebuilding ../Linux-i686/FooB.o
rebuilding library
------> Foo : library ok
------> Foo ok
Installing library libFoo.so into /home/arnault/mydev/InstallArea/Linux-i686/lib
installation done                                                         [4]
------> (constituents.make) Foo done
 all ok.
Linux-i686.make ok
gmake[2]: `config' is up to date.
gmake[2]: `all' is up to date.
  1. Some intermediate makefile fragments are automatically built to reflect the current effective set of Makefile macros deduced from the configuration (read from the  requirements  file). These fragments are automatically rebuilt (if needed) each time one of the  requirements  file changes.
  2. Each component of the package (be it a particular library or a particular executable ) will have its own makefile fragment (named ../${CMTCONFIG}/<name>.[n]mak[e] ). This dedicated makefile takes care of filling up the library and creating the shared library (on the systems where this is possible).
  3. The directory which is used for the binaries (i.e. the results of compilation or the libraries) has been automatically created by a generic target (dirs ) which is defined within [N]Makefile.header . A new binary directory will be created each time a new value of the CMTCONFIG environment variable is defined or a tag is provided on the command line to make .
  4. An automatic installation mechanism is applied for all successfully built binaries.
or, for nmake:
...v1/cmt> nmake /f nmake 

This mechanism relies on some conventional macros and incremental targets used within the specific makefiles. Some are automatically generated, some have to be specified in user packages. It's quite important to understand the list of possible customization macros, since this is the main communication medium between CMT and the package manager. See the complete table of those conventional macro when you want to interact with the standard CMT behaviour.

However, it is also possibble to use a simplified and platform independent form to build a constituent

...v1/cmt> cmt make 

This syntax is identical on all platforms, and also does not require any cmt config nor source setup operation


11. 2 - Working on an application

Assume we now want to add a test program to our development. Then we create a FooTest.cxx source, and generate the associated makefile (specifying that it will be an executable instead of a library) :

csh> cd ../src 
csh> emacs FooTest.cxx
... 
csh> cd ../cmt 
csh> vi requirements 
... 
application FooTest FooTest.cxx
So that we may simply build the complete stuff by running :
> cmt make QUIET=1
------> (Makefile.header) Rebuilding constituents.make
------> (constituents.make) Rebuilding setup.make Linux-i686.make
setup.make ok
------> (constituents.make) Rebuilding library links
------> (constituents.make) all done
------> (constituents.make) Building Foo.make
Library Foo
------> (constituents.make) Starting Foo
------> Foo : library ok
------> Foo ok
installation done
------> (constituents.make) Foo done
------> (constituents.make) Building FooTest.make
Application FooTest
------> (constituents.make) Starting FooTest
------> (FooTest.make) Rebuilding ../Linux-i686/FooTest_dependencies.make
rebuilding ../Linux-i686/FooTest.o
rebuilding ../Linux-i686/FooTest.exe
------> FooTest ok
Installing application FooTest.exe into /home/arnault/mydev/InstallArea/Linux-i686/bin
installation done
------> (constituents.make) FooTest done
 all ok.
Linux-i686.make ok
gmake[2]: `config' is up to date.
gmake[2]: `all' is up to date.
Which shows that a program FooTest.exe has been built from our sources. Assuming now that this program needs to access the Foo library, we'll just add the following definition in the  requirements  file :
... 
macro Foo_linkopts " -lFoo " \
      WIN32        " $(FOOROOT)/$(Foo_tag)/Foo.lib "
... 

The Foo_linkopts conventional macro will be automatically inserted within the use_linkopts macro. And the shared library location will be automatically set to the installation areas.

It is also possible to select extra tag sets when running gmake as follows (in this example we first cleanup the previous build and rebuild with debug options added to the compiler and linker commands) :

> cmt make clean
> cmt make CMTEXTRATAGS=debug

Like all other make macros used to build a component, the Foo_linkopts will be specified within the  requirements  which gives several benefits:


11. 3 - Working on a test or external application

It is also possible to work on a test or external application, ie. when one does not wish to configure the development for this application using CMT . Even in this case, it is possible to benefit from the packages configured using CMT by partially using CMT , just for used relationships.

Here, no special convention is assumed on the location of the sources, the binaries, the management scripts, etc... However, it is possible to describe in a  requirements  file the use relationships, as well as the make macro definitions, quite similarly to the package entirely configured using CMT .

Most of the options provided by the cmt user interface are still available in these conditions.


12 - Defining a document generator

In a Unix environment, documents are built using make (well generally its gnu flavour) or nmake in Windows environments. The basic mechanism provided in CMT relies on make fragment patterns containing instructions on how to rebuild document pieces. Many such generators are provided by CMT itself so as to take care of of the most usual cases (e.g. compilations, link operations, archive manipulations, etc...). In addition to those, any package has to possibility to provide a new generator for its own purpose, i.e. either for providing rules for a special kind of document, or even to override the default ones provided by CMT . This mechanism is very similar to the definition or re-definition of macros or environment variables in that every new generator has to be first declared in a  requirements  file belonging to a package (CMT actually declares all its default generators within its  requirements  file), allowing all its client packages to transparently acquire the capacity to generate documents of that sort.

CMT manages two categories of constituents:

  1. Applications and Libraries are handled using pre-defined make fragments (mainly related with languages) and behaviour.
  2. Documents offer a quite general framework for introducing completely new behaviours through user-defined make fragments. This includes actually generating documents, but also simply performing an operation (in which case sometimes no real document is produced).

In this section we only discuss the latter category and the following paragraphs explain the framework used for defining new document types.

The main concept of this framework is that each document to be generated or manipulated must be associated with a "document-type" (also sometimes named "document-style"), which corresponds to a dedicated make fragment of that name. Then, when specified in a document statement, this make fragment will be instanciated once or several times (typically once per source file) to construct a complete and functional make fragment, containing one main target. Both the resulting make fragment and the make target will have the name of the constituent.


12. 1 - An example : the tex document-style


This section discusses one simple example (the production of postscript from latex files) available in the standard CMT distribution kit.

Converting a latex source file into a postcript output implies to chain two text processors, with an intermediate dvi format.

The fragment described here exactly performs this sequence, taking care of intermediate file deletion. The document style is named "tex" (the associated fragment shown here and named "tex" is actually provided by CMT itself, and can be looked at in ${CMTROOT}/fragments/tex .) :

============ tex ===================================== 
${CONSTITUENT} :: ${FILEPATH}/${NAME}.ps

${FILEPATH}/${NAME}.dvi : ${FULLNAME} 
	cd ${doc}; latex ${FULLNAME} 

${FILEPATH}/${NAME}.ps : ${FILEPATH}/${NAME}.dvi 
	cd ${doc}; dvips ${FILEPATH}/${NAME}.dvi 

${CONSTITUENT}clean ::
	cd $(doc); /bin/rm -f ${FILEPATH}/${NAME}.ps ${FILEPATH}/${NAME}.dvi

====================================================== 

12. 2 - How to create and install a new document style


This section presents the general framework for designing a document generator.


  1. Select a name for the document style. It should not clash with existing ones (use the cmt show fragments for a complete list of document types currently defined).
  2. A fragment exactly named after the document style name must be installed into a subdirectory named fragments below the cmt branch of a given package (which becomes the provider package).
  3. Optionally, two other fragments may be installed into the same subdirectory, one of them will be the header of the generated complete fragment, the other will be its trailer
  4. Those fragments must be declared in the  requirements  file of the provider package as follows:
    make_fragment <fragment-name> [ options... ] 
    where options may be :

    -suffix=<suffix> provide the suffix of the output files (without the dot)
    -header=<header> provide another make fragment meant to be prepended to the constituent's make fragment.
    -trailer=<trailer> provide another make fragment meant to be appended to the constituent's make fragment.
    -dependencies install the automatic generation of dependencies into the constituent's make fragment

Once a fragment is installed and declared, it may be used by any client package (ie a package using the provider), and queried upon using the command

> cmt show fragment <fragment name> 

which will show where this fragment is defined (ie. in which of the used packages).

The cmt show fragments commands lists all declared fragments.

If a package re-defines an already declared make fragment, ie it provides a new copy of the fragment (possibly with new copies of the header and the trailer), and declares it inside its requirements file, then this package becomes the new provider for the document style.

For building a fragment, one may use pre-defined generic "templates" (which will be substituted when a fragment is copied into the final constituent's makefile).

CONSTITUENT the constituent name
CONSTITUENTSUFFIX the optional constituent's output suffix
FULLNAME the full source path name (including directory and suffix)
FILENAME the complete source file name (only including the suffix)
NAME the short source file name (without directory and suffix)
FILEPATH the source directory
SUFFIX the suffix provided in the -suffix option
OBJS (only available in headers) the list of outputs, formed by a set of expressions :
$(${CONSTITUENT}_output)${NAME}${SUFFIX} 

Templates must be enclosed between ${ and } or between $( and ) and will be substituted at the generation time. Thus, if a fragment contains the following text :

$(${CONSTITUENT}_output)${NAME}${SUFFIX}

then, the expanded constituent's makefile will contain (refering to the "tex" example)

$(MyDoc_output)doc1.ps 

Which shows that make macros may be dynamically generated.

3 - The architecture of document generation.

12. 3 - Examples

  1. rootcint

    It generates C++ hubs for the Cint interpreter in Root.

    ========= rootcint ========================================= 
    $(src)${NAME}.cc :: ${FULLNAME}   
    	${rootcint} -f $(src)${NAME}.cc -c ${FULLNAME} 
    ============================================================ 
  2. agetocxx and agetocxx_header.

    It generates C++ source files (xxx.g files) from Atlas' AGE description files.

    ========= agetocxx ========================================= 
    output=$(${CONSTITUENT}_output) 
    
    $(output)${NAME}.cxx : $(${NAME}_cxx_dependencies) 
    	(echo '#line 1 "${FULLNAME}"'; cat ${FULLNAME}) > /tmp/${NAME}.gh.c 
    	gcc -E -I$(output) $(use_includes) -D_GNU_SOURCE \ 
    	  cd ${output}; $(agetocxx) -o ${NAME} -ohd ${FILEPATH} \
    	  -ohp ${FILEPATH} /tmp/${NAME}.gh 
    	rm -f /tmp/${NAME}.gh /tmp/${NAME}.gh.c 
    	cd $(bin); $(cppcomp) $(use_cppflags) $(${CONSTITUENT}_cppflags) \
    	  $(${NAME}_cppflags) ${ADDINCLUDE} $(output)${NAME}.cxx 
    	cd $(bin); $(ar) $(${CONSTITUENT}lib) ${NAME}.o; /bin/rm -f ${NAME}.o 
    ============================================================ 
    ========= agetocxx_header ================================== 
    ${CONSTITUENT}lib       = $(bin)lib${CONSTITUENT}.a 
    ${CONSTITUENT}stamp     = $(bin)${CONSTITUENT}.stamp 
    ${CONSTITUENT}shstamp   = $(bin)${CONSTITUENT}.shstamp 
    
    ${CONSTITUENT} :: dirs ${CONSTITUENT}LIB 
    	@/bin/echo ${CONSTITUENT} ok 
    
    ${CONSTITUENT}LIB :: $(${CONSTITUENT}lib) $(${CONSTITUENT}shstamp) 
    	@/bin/echo ${CONSTITUENT} : library ok 
    
    $(${CONSTITUENT}lib) $(${CONSTITUENT}stamp) :: ${OBJS} 
    	$(ranlib) $(${CONSTITUENT}lib) 
    	cat /dev/null >$(${CONSTITUENT}stamp) 
    
    $(${CONSTITUENT}shstamp) :: $(${CONSTITUENT}stamp) 
    	cd $(bin); $(make_shlib) $(tag) ${CONSTITUENT} \
    	  $(${CONSTITUENT}shlibflags); \
    	  cat /dev/null >$(${CONSTITUENT}shstamp) 
    
    ============================================================ 
    It must be declared as follows :
    make_fragment agetocxx -suffix=cxx -dependencies -header=agetocxx_header 

13 - The tools provided by CMT

The set of conventions and tools provided by CMT is mainly composed of : The setup script found in the CMT installation directory actually adds its location to the definition of the standard UNIX PATH environment variable in order to give direct access to the main cmt user interface.

The sections below will detail the complete syntax of the  requirements  file since it is the basis of most information required to run the tools as well as the main commands available through the cmt user interface.


13. 1 - The requirements file


13. 1. 1 - The general requirements syntax

  • A requirements file is made of statements , each describing one named configuration parameter.

    Statements generally occupy one single line, but may be split into several lines using the reverse-slash character (in this case the reverse-slash character must be the last character on the line or must be only followed by space characters).

    Each statement is composed of words separated with spaces or tabulations.

    The first word of a statement is the name of the configuration parameter.

    The rest of the statement provides the value assigned to the configuration parameter.

  • Words composing a statement are separated with space or tab characters. They may also be enclosed in quotes when they have to include space or tab characters. Single or double quotes may be freely used, as long as the same type of quote is used on both sides of the word.

    Special characters (tabs, carriage-return and line-feed) may be inserted into the statements using an XML-based convention:

    tabulation <cmt:tab/>
    carriage-return <cmt:cr/>
    line-feed <cmt:lf/>

  • Comments : they start with the # character and extend up to the end of the current line.

The complete syntax specification is available in Appendix .

13. 2 - The concepts handled in the requirements file


13. 2. 1 - The package structuring style

Packages are installed in a directory structure that can optionnally include a version directory (just after the top directory of the package name). This is controlled through the structuring style or structuring strategy parameters specified using one of the following means:

  1. Through the environment variable CMTSTRUCTURINGSTYLE taking one of the alternate values:
    with_version_directory
    without_version_directory

  2. Through the command line options -with_version_directory or -without_version_directory

  3. Through the structure_strategy specification entered into the project file of the current project, using the alternate values:
    with_version_directory
    without_version_directory

It should be noted that the command line option will take precedence over the strategy specification, in case of conflict.


13. 2. 2 - Meta-information : author, manager

The author and manager names

13. 2. 3 - package, version

The package name and version. These statements are purely informational.

13. 2. 4 - Constituents : application, library, document

Describe the composition of a constituent. Application and library correspond to the standard meaning of an application (an executable) and a library, while document provides for a quite generic and open mechanism for describing any type of document that can be generated from sources.

Applications and libraries are assigned a name (which will correspond to a generated make fragment, and a dedicated make target).

A document is first associated with a document type (which must correspond to a previously declared make fragment). The document name is then used to name a dedicated make fragment and a make target.

Various options can be used when declaring a constituent:

option
validity
usage
-s=directory any switch to a new default directory (1)
-x=regexp any specify an exclusion regular expression to be applied to the sources (1)
-k=regexp any specify a finer selection regular expression to be applied to the sources (1)
-no_share libraries do not generate the shared library
-no_static libraries do not generate the static library (not yet implemented )
-prototypes applications, libraries do generate the prototype header files
-no_prototypes applications, libraries do not generate the prototype header files
-check applications generate a check target meant to execute the rebuilt application
-group=<group-name> any install the constituent within this group target
-suffix=<suffix> applications, libraries provide a suffix to names of all object files generated for this constituent (2)
-import=<package> applications, libraries explicitly import for this constituent the standard macros from a package that has the -no_auto_imports option set
-target_tag any construct a specific tag named target_<constituent> . This tag will only be active during the make session for this constituent. (4)
-windows applications When used in a Windows environment, generates a GUI-based application (rather than a console application)
<var-name>=<var-value> any define a variable and its value to be given to the make fragment (3)
  1. The sources of the constituents are generally specified as a set of file names with their suffixes, and are by default expected from the ../src directory

    library A A.cxx B.cxx

    Then it is possible to change the default search location as well as to use a simplified wildcarding syntax:

    library A -s=A *.cxx -s=B *.cxx
    • -s=A means that next source files should be taken searched from ../src/A
    • -s=B means that next source files should be taken searched from ../src/B . Note that this new specification is not relative to the previous -s=A but relative to the default search path ../src
    • *.cxx indicates that all files with a .cxx suffix in the current search path should be considered

    It's also possible to select or exclude files using regular expressions from general wildcarding techniques:

    library A -s=A -x=[0-9] *.cxx -s=B -k=^B *.cxx
    • The exclusion specification -x=[0-9] added to the statement will exclude all files from ../src/A containing a number in their name.
    • The selection specification -k=^B added to the statement will select files from ../src/B strictly starting with the B letter.

  2. When several constituents need to share source files, (a typical example is for building different libraries from the same sources but with different compiler options), it is possible to specify an optional output suffix with the -suffix=<suffix> option. With this option, every object file name will be automatically suffixed by the character string "<suffix> ", avoiding name conflicts between the different targets, as in the following example:

    library AXt  -suffix=Xt  *.cxx
    library AXaw -suffix=Xaw *.cxx
  3. It's possible to specify in the list of parameters one or more pairs of variable-name =variable-value (without any space characters around the"=" character), such as in the next example:

    make_fragment doc_to_html                             (1)
    
    document doc_to_html Foo output=FooA.html FooA.doc    (2) (3)
    1. This makefile fragment is meant to contain some text conversion actions and defines a document type named doc_to_html .
    2. This constituent exploits the document type doc_to_html to convert the source FooA.doc into an html file.
    3. The user defined template variable named output is specified and assigned the value FooA.html . If the fragment doc_to_html contains the string ${output} , then it will be substituted to this value.

  4. For any constituent that has the -target_tag option set, a dedicated tag named target_<constituent> is automatically constructed by CMT. This tag becomes active during the construction of this constituent when using make , and therefore can be used as any other tag to select symbol values, or other configuration parameters.


13. 2. 5 - Groups

Groups permit the organization of the constituents that must be consistently built at the same development phases or with similar constraints.

Each group is associated with a make target (of the same name) which, when used in the make command, selectively rebuilds all constituents of this group.

The default group (into which all constituents are installed by default) is named all , therefore, running make without argument, activates the default target (ie. all ).

As a typical usage of this mechanism, one may examplify the case in which one or several constituents are making use of one special facility (such as a database service, real-time features, graphical libraries) and therefore might require a controled re-build. This is especially useful for having these constituents only rebuilt on demand rather than rebuilt automatically when the default make command is run.

One could, for instance specify within the requirements file :

# Constituents belonging to the default all group

... constituents without group specification ...
library Foo *.cxx

# Constituents belonging to specific groups

library Foo-objy -group=objy <sources making use of Objectivity>

application FooGUI -group=graphics <sources making use of Qt>
application BarGUI -group=graphics <sources making use of Qt>
(Beware of the position of the -group option which must be located after the constituent name. Any other position will be misunderstood by CMT)

Then, running gmake all would only rebuild the un-grouped constituents, whereas running

> gmake objy
> gmake graphics

in the context of the Foo package would rebuild objy related or graphics related constituents.


13. 2. 6 - Languages

Some computer languages are known by default by CMT (C , C ++, Fortran77 , Java , lex , yacc ). However it is possible to extend this knowledge to any other langage.

We consider here languages that are able to produce object files from sources.

Let's take an example. We would like to install support for Fortran90. We first have to declare this new language support to CMT within the requirements file of one of our packages (Notice that it's not at all required to modify CMT itself since all clients of the selected package will inherit the knowledge of this language).

The language support is simply named fortran90 and is declared by the following statement:

language fortran90 \
  -suffix=f90 -suffix=F90 \             [1]
  -linker=$(f90link) \                  [2]
  -preprocessor_command=$(ppcmd)
  1. The recognized suffixes for source files will be f90 and F90
  2. The linker command used to build a Fortran90 application is described inside the macro named f90link (which must defined in this requirements file but which can also be overridden by clients)

The language support being named fortran90 , two associated make fragments are expected, one under the name fortran90 (for building application modules), the other with the name fortran90_library (for modules meant to be archived), both without extension.

These two fragments should be installed in the fragments sub-directory of the cmt branch of our package.

Due to the similarity of the example to fortran77, we may easily provide the expected fragments simply by copying the f77 fragments found in CMT (thus the fragments ${CMTROOT}/fragments/fortran and ${CMTROOT}/fragments/fortran_library

These fragments make use of the fcomp macro, which holds the fortran77 compiler command (through the for macro).

macro for             "f77" \
...
macro fcomp           "$(for) -c $(fincludes) $(fflags) $(pp_fflags)"

We therefore simply replace these macros by new macros named f90comp and f90 , defined as follows:

macro f90             "f90"
...
macro f90comp         "$(f90) -c $(fincludes) $(fflags) $(pp_fflags)"

Some languages (this has been seen for example in the IDL generators in Corba environments) do provide several object files from one unique source file. It is possible to specify this feature through the (repetitive) -extra_output_suffix option like in:

language idl -suffix=idl -fragment=idl -extra_output_suffix=_skel
where, in this case, two object files are produced for each IDL source file, one named <name >.o the other named <name >_skel.o .

13. 2. 7 - Symbols

This is a generic concept supporting the notion of valued symbols. Several alternate semantics are implemented by these symbols, all specified using the same syntactic schema, but leading to different behaviours or interpretations by CMT:

  • The set keyword is translated into an environment variable definition.
  • The macro keyword is translated into a make 's macro definition.
  • The path keyword is translated into a prioritized path -like environment variable, which is supposed to be composed of search paths separated with colon characters ':' (on Unix) or semi-colon characters ';' (on Windows). It is generally recommended to construct such a variable by iteratively concatenating individual items one by one using path_append or path_prepend
  • The action keyword is translated into a shell command definition, that can be activated using the cmt do <action> command or the associated make target.
  • The alias keyword is translated into a shell alias definition,

Variants of these keywords are also provided for modifying already defined symbols. This generally happens when a package needs to modify (append, prepend or subtract) an inherited symbol (ie. which has been already defined by a used package).

The translations occur while running either the setup scripts (for alias, set or path) or the make command (for macro and actions).

All these definitions follow the same pattern:

symbol : symbol-type symbol-name default-value tag-expr value  ...   ] 
symbol-type : definition
| modification
definition : macro
| set
| path
| action
| alias
modification : macro_prepend
| macro_append
| macro_remove
| macro_remove_regexp
| macro_remove_all
| macro_remove_all_regexp
| set_prepend
| set_append
| set_remove
| set_remove_regexp
| path_prepend
| path_append
| path_remove
| path_remove_regexp
tag-expr : tag & tag  ...   ] 

  • The symbol-name identifies the symbol.

  • Values are generally quoted strings (using either simple or double quotes). They may be unquoted only if they are composed of one single non-empty word, since the general syntax parsing relies on space separated words.

  • The default-value is mandatory (although it can be an empty string) optionally followed by a set of tag/value pairs, each representing an alternate value for this symbol.

  • Each tag-value pair describes an alternate value to be used when the corresponding tag or tag-expression is active.

  • When several alternate values are specified through several tag-value pairs the first matching condition is selected. Therefore one should always specify the most contraining condition first.

  • The removal operations can be specified using either plain sub-strings or regular rexpressions. One shou