38 Compute Dependencies Between Aldor Source Files

 38.1 Extract Constructor Definitions and Uses
 38.2 Build a Dependency Graph without Extensions
 38.3 Add Extensions to the Dependency Graph
 38.4 Saturate Dependencies
 38.5 Make Minimal Dependencies
 38.6 Write Dependencies to STDOUT

This Perl script is intended to generate the files src/Makefile.dep and test/Makefile.dep. This is done by parsing the Aldor source files for constructors that are defined in them and then determining the interdependencies of the files from the constructors that are defined in them.

The output is in Makefile format, see Sections 33.4.2 and 41.4.2.

With this script we avoid to have a list of nearly identical Makefiles in each subdirectory of src and test and we also avoid to write dependencies at all.

ToDo 25 Finding interrelations of extended domains is problematic and not yet fully implemented. If a domain is extended only once in one library, the script should be sufficient, though.

Suppose the following 3 lines are in 3 different files.

D: with {a: () -> ()} == add { ... }                 --one.as
extend D: with {b: () -> ()} == add {b(): () == a()} --two.as
extend D: with {c: () -> ()} == add {c(): () == b()} --three.as

Of course it is possible to figure out that the files have to be compiled in the order they appear above, but the script dependencies.pl.nw is not able to do it, since it relies on explicit category names.

For such cases, the compiler would have to be run on each file to figure out what is missing. The files that compile are then truly compiled an put into a library. Here one.as compiles. In the second run, two.as and three.as are tried to compile resulting in the fact that only two.as compiles while tree.as fails.

With more than just 3 files that becomes a waste of time in useless compilation of files.

The script takes as input tree parameters.

  1. The first parameter is a file that lists names of input files (one per line). Each file name is taken as a relative filename rooted at PROJECTROOT and should be prepended by the corresponding library it will belong to. A prefix (see LIBPREFIX) can/should appear at the third position. For example,
    myalps src/myalps/arith my

    could be one entry in such a file. The extension .as should not be given. See the target asfiles.list in src/Makefile.nw and the generated files src/asfiles.list and test/tcasfiles.list.

    These files will be scanned for constructors defined in them and will also be parsed for constructors that are defined in other files if the corresponding library in front of the filename is equal to the second parameter. Note also the convention given in Section 38.1.

  2. The second parameter is the name of a library that should be built.
  3. The third parameter is the value of the PROJECTROOT.
507* 21+   503  535a
#------------------------------------------------------------------
#---
#--- ALLPROSE
#--- Copyright (C) Ralf Hemmecke (ralf@hemmecke.de)
#--- http://www.hemmecke.de/aldor
#---
#------------------------------------------------------------------

commandline check 508a
global variables 298a
compute dependencies 509a
output dependencies to stdout 510c

subroutines 511a
508acommandline check 508a  (507)
if (scalar(@ARGV) < 3) {
    print STDERR "missing list of files, library name, or PROJECTROOT\n";
    die ’Usage: dependencies.pl ASFILES.list LIBRARYNAME PROJECTROOT’;
}

Uses ASFILES 466, LIBRARYNAME 127, and PROJECTROOT 350.

Let us name the parameters given to the script.

508bglobal variables 298a+   (297 478b 507 539b)  484a  508c
$ASFILES       =$ARGV[0];
$LibraryToBuild=$ARGV[1];
$PROJECTROOT   =$ARGV[2];

Uses ASFILES 466 and PROJECTROOT 350.

The variable DEP is most important in this script. It collects the filenames and its dependencies. An entry $DEP{A}{B}=1 means that the file A depends on B.

508cglobal variables 298a+   (297 478b 507 539b)  508b  508d
%DEP=();

Defines:
DEP, used in chunks 509a, 515, 521, 524, 527, and 533.

Files that will be used to build the library are collected in the following variable.

508dglobal variables 298a+   (297 478b 507 539b)  508c  511b
@FilesInLibrary=();

The following code chunk does the main work. It collects the entries found in the file given as the first parameter to the script, parses the corresponding files and extracts definitions and uses of constructor names, see page 512.

509acompute dependencies 509a  (507)
read constructor definitions and uses 509b
for $f (@FilesInLibrary) {&buildDependencies    ($f, $LibraryToBuild);}
for $f (@FilesInLibrary) {&addExtendDependencies($f, $LibraryToBuild);}
print to stderr the constructors that have been found 510a
@DependentFiles = keys %DEP; #We destructively modify %DEP in the loop.
for $f (@DependentFiles) {
    @circular = &saturateDependencies($f);
    if (scalar(@circular) > 0) {
        treat circular dependency error 510b
    }
}
for $f (@DependentFiles) {&minimalDependencies($f);}

Uses buildDependencies 516, DEP 508c, loop 360, minimalDependencies 527, and saturateDependencies 524.
509bread constructor definitions and uses 509b  (509a)
open(SF, $ASFILES);
while (<SF>) {
    chomp;
    if (/([^ ]+) (.*)/) {
        $LIB=$1;
        $file=$2;
        if ($LIB eq $LibraryToBuild) {push @FilesInLibrary, $file;}
        &extractConstructorDefinitionsAndUses($file, $LIB);
    } else {
        die "Error: dependencies.pl cannot interpret $_";
    }
}
close(SF);

Uses ASFILES 466, extractConstructorDefinitionsAndUses 513, and LIB 445.
510aprint to stderr the constructors that have been found 510a  (509a)
for $c (sort(keys %CATEGORIES)) {print STDERR "C $c $CATEGORIES{$c}\n";}
for $c (sort(keys %DOMAINS))    {print STDERR "D $c $DOMAINS{$c}\n";}
for $c (sort(keys %EXTENSIONS)) {print STDERR "E $c $EXTENSIONS{$c}\n";}

Uses CATEGORIES 511b, DOMAINS 511b, and EXTENSIONS 511b.
510btreat circular dependency error 510b  (509a)
print STDERR "\nWARNING(saturateDependencies): Circular dependency\n";
pop @circular; # The first and last elements are equal.
for $f (@circular) {
    @fuse = split(" ", $f);
    print STDERR "--> $fuse[1] ";
    for $c (sort(keys %{$USES{$f}})) {
        if (scalar(grep {$CATEGORIES{$c} eq $_} @circular) > 0) {
            @fdef = split(" ", $CATEGORIES{$c});
            print STDERR "uses $c defined in $fdef[1]\n";
        }
        if (scalar(grep {$DOMAINS{$c} eq $_} @circular) > 0) {
            @fdef = split(" ", $DOMAINS{$c});
            print STDERR "uses $c defined in $fdef[1]\n";
        }
        if (scalar(grep {$EXTENSIONS{$c} eq $_} @circular) > 0) {
            @fdef = split(" ", $EXTENSIONS{$c});
            print STDERR "uses $c extended in $fdef[1]\n";
        }
    }
}
die "";

Uses CATEGORIES 511b, DOMAINS 511b, EXTENSIONS 511b, saturateDependencies 524, and USES 512a.
510coutput dependencies to stdout 510c  (507)
print "# Generated via\n# ".join(" \\\n#   ", $0, @ARGV)."\n";
for $f (sort @FilesInLibrary) {&printDependencies($f, $LibraryToBuild);}

Uses printDependencies 533.
511asubroutines 511a  (507)
extract constructor definitions and uses 513
build dependencies 515
add extend dependencies 517
saturate dependencies 524
minimal dependencies 527
write dependencies in Makefile format to stdout 533