ocaml/tools/camldep

92 lines
2.0 KiB
Perl
Executable File

#!/usr/local/bin/perl
# To scan a Caml Light source file, find all references to external modules
# (open Foo or Foo.bar), and output the dependencies on standard output.
#
# Usage: camldep [-I path] <file> ...
while ($#ARGV >= 0) {
$_ = shift(@ARGV);
if (/^-I(.*)$/) {
$dir = $1 ? $1 : shift(@ARGV);
$dir =~ s|/$||;
unshift(@path, $dir);
}
elsif (/(.*)\.mli$/ || /(.*)\.cmi$/) {
do scan_source ($_, "$1.cmi");
}
elsif (/(.*)\.ml$/ || /(.*)\.cmo$/) {
do scan_source ($_, "$1.cmo");
}
else {
die "Don't know what to do with $_";
}
}
sub scan_source {
local ($source_name, $target_name) = @_;
$modname = $target_name;
$modname =~ s|^.*/||;
$modname =~ s|\.z[io]$||;
undef(%imports);
open(SRC, $source_name) || return;
while(<SRC>) {
if (m/\bopen\s*([A-Z][a-zA-Z0-9_]*)\b/) {
$imports{$1} = 1;
}
while(m/\b([A-Z][a-zA-Z0-9_]*)\./) {
$imports{$1} = 1;
$_ = $';
}
}
close(SRC);
undef(@deps);
if ($target_name =~ m/(.*)\.cmo$/ && -r ($source_name . "i")) {
push(@deps, "$1.cmi");
}
foreach $modl (keys(%imports)) {
$modl = do lowercase($modl);
next if ($modl eq $modname);
if ($dep = do find_path ("$modl.mli")) {
$dep =~ s/\.mli$/.cmi/;
push(@deps, $dep);
}
elsif ($dep = do find_path ("$modl.ml")) {
$dep =~ s/\.ml$/.cmo/;
push(@deps, $dep);
}
}
if ($#deps >= 0) {
print "$target_name: ";
$col = length($target_name) + 2;
foreach $dep (@deps) {
next if $dep eq $target_name;
$col += length($dep) + 1;
if ($col >= 77) {
print "\\\n ";
$col = length($dep) + 5;
}
print $dep, " ";
}
print "\n";
}
}
sub find_path {
local ($filename) = @_;
return $filename if (-r $filename);
foreach $dir (@path) {
return "$dir/$filename" if (-r "$dir/$filename");
}
return 0;
}
sub lowercase {
local ($_) = @_;
m/^(.)(.*)$/;
$hd = $1;
$tl = $2;
$hd =~ tr/A-Z/a-z/;
return $hd . $tl;
}