38 Compute Dependencies Between Aldor Source Files
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.
- 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.
- The second parameter is the name of a library that should be built.
- 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⟩
504a⟨commandline 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.
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.
Files that will be used to build the library are collected in the following variable.
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.
505a⟨compute 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.
505b⟨read 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.
506b⟨treat 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.
507a⟨output dependencies to stdout 507a⟩≡ (503)
print "# Generated via\n# ".join(" \\\n# ", $0, @ARGV)."\n";
for $f (sort @FilesInLibrary) {&printDependencies($f, $LibraryToBuild);}
Uses printDependencies 530.
507b⟨subroutines 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⟩