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 ⊲ 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.
- 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.
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⟩
508a⟨commandline 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.
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 512.
509a⟨compute 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.
509b⟨read 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.
510b⟨treat 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.
510c⟨output dependencies to stdout 510c⟩≡ (507)
print "# Generated via\n# ".join(" \\\n# ", $0, @ARGV)."\n";
for $f (sort @FilesInLibrary) {&printDependencies($f, $LibraryToBuild);}
Uses printDependencies 533.
511a⟨subroutines 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⟩