Chapter 7: The Poly/ML Make System

7.1 Introduction

PolyML.make is a function to help maintain consistency of programs made up of several modules. PolyML.make works on modules (files containing functors, structures and signatures) and tries to ensure that a module is consistent with respect to the modules it uses.

The Poly/ML compiler has two modes of operation: normal mode and 'make' mode. When the compiler is operating in 'make' mode and it encounters the name of a functor, structure or signature, it determines whether it is necessary to remake that object from its source code. It addition, the variable PolyML.Compiler.useRCS controls whether make attempts to invoke the popular GNU RCS system.

7.2 Non-RCS mode

When the variable PolyML.Compiler.useRCS is set to false, the make system operates in non-RCS mode. (This was the standard mode for releases of the Poly/ML system prior to version 3.0.)

The make system assumes that source code for functors, structures and signatures is kept in files whose names resemble those of the objects. The variable PolyML.Compiler.suffixes contains the list of filename suffixes recognised by the make system, in the order that the system tries them. The default list is ["", ".ML", ".sml"].

For example, if the object is called 'name', the system first tries to find a file called name, then tries name.ML, and finally tries name.sml if neither of the other files exists. Alternatively, 'name' may be a Unix directory containing a file called 'ml_bind.ML'. If the make system fails to find any matching file then it assumes the object is pervasive and will use the existing version of it.

7.3 RCS mode

When the variable PolyML.Compiler.useRCS is set to true, the make system operates in RCS mode. If you haven't installed the GNU RCS system, or you don't like the following behaviour, simply set PolyML.Compiler.useRCS to false.

When the make system is operating in RCS mode and requires a file called 'file', it will also accept a file called 'file,v' or 'RCS/file,v'. If the primary file doesn't exist but one of the RCS ',v' files is present, the make system will invoke the RCS check-out program co, to create the primary file. (You must have write permission in the source directory for this to work properly.) Once the file has been compiled, the make system will then use rm to restore the file system to its original state.

Note: The Poly/ML system makes the reasonable assumption that if you have PolyML.Compiler.useRCS set and your file system contains ',v' files, then you must have co in your standard search path. If this isn't true, then make will fail unpredictably.

Note: the system tries each ',v' variant of each suffix before trying the next suffix. This means that (with the default suffix list) name.ML,v would take precedence over name.sml.

7.4 Example

For example, suppose we have a system in which the structure Sort is created by applying the functor SORT to the structures Combinator and List and that Combinator is itself created by applying the functor COMBINATOR to the structure List.

To use the make system, we would create a directory Sort with subdirectory Sort/Combinator and the following files:

File Contents
Sort/List.ML Code for structure List
Sort/Combinator/COMBINATOR.ML Code for functor COMBINATOR
Sort/Combinator/ml_bind.ML Code to create Combinator
Sort/SORT.ML Code for functor SORT
Sort/ml_bind.ML Code to create Sort

These files should have the following format:

Sort/List.ML

structure List =
struct (* body of List *) end;

Sort/Combinator/COMBINATOR.ML

signature LSIG =
sig (* body of LSIG, as used by COMBINATOR *) end;

functor COMBINATOR(structure L : LSIG) =
struct (* body of COMBINATOR *) end;

Sort/Combinator/ml_bind.ML

structure Combinator =
COMBINATOR(structure L = List);

Sort/SORT.ML

signature CSIG =
sig (* body of CSIG *) end;

signature LSIG =
sig (* body of LSIG, as used by SORT *) end;

functor SORT (structure C : CSIG structure L : LSIG) =
struct
(* body of SORT *)
end;

Sort/ml_bind.ML

structure Sort =
SORT(structure L = List structure C = Combinator);

The first time we use PolyML.make "Sort", Poly/ML will enter 'make' mode and compile and bind (as appropriate) all the above modules.

If we edit the file Sort/Combinator/COMBINATOR.ML, then we need to recompile COMBINATOR, rebind Combinator and rebind Sort (in that order). This is precisely what PolyML.make "Sort" will do. There is no need to recompile the structure List or the functor SORT, since neither of these is affected by the change to COMBINATOR.

On the other hand, if we edit Sort/SORT.ML then we only need to recompile the functor SORT then rebind the structure Sort. Again, this is precisely what PolyML.make "Sort" does for us.

PolyML.make works using 'dependency lists'. Here the structure Sort depends on SORT, List and Combinator while the structure Combinator depends on COMBINATOR and List.

Each time the make system is invoked, it uses information stored from the previous call to find the dependencies of each functor, structure or signature. The file modification time of each dependent is compared with the time the corresponding database object was created to determine which objects need to be recreated.

Notes:

Copyright (c) 2000 CUTS and contributers.  Last updated: 15 January 2002 by David Matthews.