vmodels - a guide to writing standard Vesta-2 user models



This man page is a tutorial for writing Vesta-2 user models to conform to the existing bridge and standard environment models. In particular, it documents the common/std_env/18 and common/cxx/14 packages (presumably, this guide will continue to apply to later versions of those packages as well).

To understand this guide, you will probably want to refer to the vtypes(5) man page, which describes the data types used in the common models. To learn about how libraries are structured and built in Vesta-2, see the vlibraries(5) man page. Finally, to build a model with overrides, refer to the voverrides(5) man page.

Non-Library Package Models

The top-level model of every Vesta-2 package is named "build.ves". This is the model invoked by the control panel's ".main.ves" file.

The build.ves model should evaluate to a binding of type "PkgResult". This binding maps names to 0-argument closures (not counting the implicit environment argument) of type "PkgFunc". These functions build libraries and executables exported by the package.

Most non-library package models build a collection of main programs executed by the package, and possibly a collection of test programs. By convention, the corresponding closures are named "progs" and "tests". It is often convenient to define each of these closures by its own model. In that case, the "build.ves" model is quite simple:

    progs = progs.ves;
    tests = tests.ves;
    return [ progs, tests ];
Each of the models progs.ves and tests.ves lists the files needed to build the programs, constructs a binding of the library to link against, optionally defines some overrides for the compilation, and then invokes the bridge's "program" function for each program. Since "program" returns a singleton binding, the result of the model is formed by simply overlaying the results of each of the individual "program" calls. Here is a typical "progs.ves" model from the vesta/log package:
    vappendlog = [ vappendlog.C ];
    vdumplog   = [ vdumplog.C ];
    // required libraries
    v_libs = ./Cxx/libs/vesta;
    libs = < v_libs/log, v_libs/basics >;

    // overrides
    ovs = [ Cxx/switches/program = [ shared_libs = "-non_shared" ]];

      ./Cxx/program("vappendlog", vappendlog, [], libs, ovs) +
      ./Cxx/program("vdumplog",   vdumplog,   [], libs, ovs);
In this case, both programs are built with the same libraries and overrides. The overrides for linking the program are passed as an explicit parameter to the program function. See the voverrides(5) man page for details.

Leaf Library Package Models

The current standard models require that a package export at most one library. If a package builds multiple libraries, they should be wrapped up into a single umbrella, as described below. In either case, the package's build.ves model is required to evaluate to a binding of type "LibPkgResult" that contains a field named "lib". Like a non-library model, a library model may also export utility programs and test programs. Here is a prototypical build.ves file for a leaf model:

    lib = lib.ves;
    progs = progs.ves;
    tests = tests.ves;
    return [ lib, progs, tests ];
If the package exports a leaf library, its lib closure should be a value of type "LibFunc. In particular, it should return the result of calling the bridge's "leaf" function. Here is a typical lib.ves model, taken from the vesta/log package:
    c_files = [Recovery.C, VestaLog.C];
    h_files = [Recovery.H, VestaLog.H, VestaLogPrivate.H];
    return ./Cxx/leaf("libVestaLog.a", c_files, h_files);
If the library uses some header files that should be hidden from clients, they can be bound to an optional fourth argument named "priv_h_files" of the bridge's leaf function. It is also possible to specify overrides for the library; see the voverrides(5) man page for details.

Prebuilt Library Package Models

The models for a prebuilt library (one built outside of Vesta) are nearly identical to the models for building a leaf library. The only difference is in the lib.ves model. Here's an example based on the zlib compression library:

    archive = [libz.a];
    headers = [zlib.h, zconf.h];
    return ./C/prebuilt("libz.a", headers, archive);

Umbrella Library Package Models

The models for building an umbrella library are a lot like the models for building a leaf library, but with two differences.

First, the library must name of all the packages that export libraries included in the umbrella. The result of the build.ves model must be a value of type "UmbrellaPkgResult" that binds the name "children" to the set of child packages. The child packages themselves are represented by a value of type "QNamedPkgs". A value of this type is a two-level binding of qualified package names; each qualified name is bound to the corresponding package's build.ves model.

Second, the library is constructed by a call to the bridge's "umbrella" function. This function requires the name of the resulting umbrella library and a list of the libraries in the umbrella. Each element of the list is a "LibPkgResult", that is, the result of evaluating a library package. Typically, the list is formed by selecting library descriptions out of "./bridge/libs/.

As an example, here is the build.ves model for the vesta/vesta_umb package:

from /vesta/src.dec.com/vesta import
  vesta_kids = [
      run_tool/4, repos/5, cache/9, fp/1,
      log/4, srpc/4, config/3, basics/22 ];
    // closure for dynamically building list of libraries
    lib_models(models: NamedPkgs): LibPkgResults {
      	res = <>;
	foreach [ nm = model ] in models do
            res += < ./Cxx/libs/vesta/$nm >;
      	return res;

    // closure for building umbrella library
    lib(): NamedLibDesc {
        return ./Cxx/umbrella("libVestaUmb.a", lib_models(vesta_kids));

    // "eval_field(f)" is a closure for evaluating the "f" field
    // of the library models named in "vesta_kids"
    eval_field(f)(): binding {
        res = [];
        foreach lib in lib_models(vesta_kids) do {
            res += if lib!$f then lib/$f() else [];
        return res;

    // return result
    children = [ vesta = vesta_kids ];
    return [ lib, children,
      progs = eval_field("progs"),
      tests = eval_field("tests") ];
Unlike the previous examples, there are no auxiliary models in this package: the lib, progs, and tests fields are bound to locally-defined closures. This model is more complicated than the previous ones, so a more thorough description is in order.

The import clause selects the particular versions of those child packages that are part of the umbrella. The "vesta_kids" value is then used at the end of the model to form the set "children" of qualified package names returned in the result. Notice how the extra name "vesta" was inserted in the formation of the "children" binding to qualify the package names.

The model defines a local function, "lib_models(models)". Given the argument "models", a collection of named packages, this function iterates over the names and selects the corresponding packages out of "./Cxx/libs/vesta", forming a list of the resulting library package results. The actual models to which the names are bound are ignored in case some transient package overrides were applied when the standard environment was constructed.

The result of "lib_models(vesta_kids)" is then passed as the second argument to the "./Cxx/umbrella" function in the "lib closure.

Finally, the umbrella model implements the "progs" and "tests" closures by simply invoking the corresponding functions of each of the child packages. It uses a single, parameterized closure for this purpose. The closure iterates over the package results in "lib_models(vesta_kids)", evaluates the closure named by the "f" parameter if it is defined, and overlays the result.

See Also

vlibraries(5), voverrides(5), vtypes(5).


Allan Heydon

Last modified on Sun Sep 26 19:09:57 EDT 2004 by ken@xorian.net
     modified on Mon Mar 16 17:02:52 PST 1998 by heydon
This page was generated automatically by mtex software.