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 24 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.
503* 21+   499  532a
#------------------------------------------------------------------
#---
#--- ALLPROSE
#--- Copyright (C) Ralf Hemmecke (ralf@hemmecke.de)
#--- http://www.hemmecke.de/aldor
#---
#------------------------------------------------------------------

commandline check 504a
global variables 294a
compute dependencies 505a
output dependencies to stdout 507a

subroutines 507b
504acommandline check 504a  (503)
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 462, LIBRARYNAME 124, and PROJECTROOT 346.

Let us name the parameters given to the script.

504bglobal variables 294a+   (293 474b 503 536b)  480a  504c
$ASFILES       =$ARGV[0];
$LibraryToBuild=$ARGV[1];
$PROJECTROOT   =$ARGV[2];

Uses ASFILES 462 and PROJECTROOT 346.

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.

504cglobal variables 294a+   (293 474b 503 536b)  504b  504d
%DEP=();

Defines:
DEP, used in chunks 505a, 512, 518, 521, 524, and 530.

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

504dglobal variables 294a+   (293 474b 503 536b)  504c  508a
@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 509.

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

Uses buildDependencies 513, DEP 504c, loop 356, minimalDependencies 524, and saturateDependencies 521.
505bread constructor definitions and uses 505b  (505a)
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 462, extractConstructorDefinitionsAndUses 510, and LIB 441b.
506aprint to stderr the constructors that have been found 506a  (505a)
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 508a, DOMAINS 508a, and EXTENSIONS 508a.
506btreat circular dependency error 506b  (505a)
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 508a, DOMAINS 508a, EXTENSIONS 508a, saturateDependencies 521, and USES 508b.
507aoutput dependencies to stdout 507a  (503)
print "# Generated via\n# ".join(" \\\n#   ", $0, @ARGV)."\n";
for $f (sort @FilesInLibrary) {&printDependencies($f, $LibraryToBuild);}

Uses printDependencies 530.
507bsubroutines 507b  (503)
extract constructor definitions and uses 510
build dependencies 512
add extend dependencies 514
saturate dependencies 521
minimal dependencies 524
write dependencies in Makefile format to stdout 530