2
0
mirror of https://github.com/sudo-project/sudo.git synced 2025-08-22 18:08:23 +00:00
sudo/mkdep.pl
Todd C. Miller f7cb73abdb Add dependency for siglist.lo in compat. This is a generated file so
"make depend" needs to depend on it.
2011-05-26 12:12:43 -04:00

190 lines
5.2 KiB
Perl
Executable File

#!/usr/bin/env perl
use File::Temp qw/ :mktemp /;
use Fcntl;
use warnings;
die "usage: $0 Makefile ...\n" unless $#ARGV >= 0;
my @incpaths;
my %dir_vars;
my %implicit;
foreach (@ARGV) {
mkdep($_);
}
sub mkdep {
my $file = $_[0];
my $makefile;
if (open(MF, "<$file")) {
local $/; # enable "slurp" mode
$makefile = <MF>;
} else {
warn "$0: $file: $!\n";
return undef;
}
close(MF);
# New makefile, minus the autogenerated dependencies
my $separator = "# Autogenerated dependencies, do not modify";
my $new_makefile = $makefile;
$new_makefile =~ s/${separator}.*$//s;
$new_makefile .= "$separator\n";
# Old makefile, join lines with continuation characters
$makefile =~ s/\\\n//mg;
# Expand some configure bits
$makefile =~ s:\@COMMON_OBJS\@:aix.lo:;
$makefile =~ s:\@SUDO_OBJS\@:preload.o selinux.o sesh.o sudo_noexec.lo:;
$makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo plugin_error.lo:;
# XXX - fill in AUTH_OBJS from contents of the auth dir instead
$makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo kerb4.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid.lo securid5.lo sia.lo:;
$makefile =~ s:\@LTLIBOBJS\@:closefrom.lo dlopen.lo fnmatch.lo getcwd.lo getgrouplist.lo getline.lo getprogname.lo glob.lo isblank.lo memrchr.lo mksiglist.lo mktemp.lo nanosleep.lo setenv.lo siglist.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo unsetenv.lo utimes.lo:;
# Parse OBJS lines
my %objs;
while ($makefile =~ /^[A-Z0-9_]*OBJS\s*=\s*(.*)/mg) {
foreach (split/\s+/, $1) {
next if /^\$[\(\{].*[\)\}]$/; # skip included vars for now
$objs{$_} = 1;
}
}
# Find include paths
@incpaths = ();
while ($makefile =~ /-I(\S+)/mg) {
push(@incpaths, $1) unless $1 eq ".";
}
# Values of srcdir, top_srcdir, top_builddir, incdir
%dir_vars = ();
$file =~ m:^(.*)/+[^/]+:;
$dir_vars{'srcdir'} = $1 || '.';
$dir_vars{'devdir'} = $dir_vars{'srcdir'};
$dir_vars{'authdir'} = $dir_vars{'srcdir'} . "/auth";
$dir_vars{'top_srcdir'} = '.';
#$dir_vars{'top_builddir'} = '.';
$dir_vars{'incdir'} = 'include';
# Find implicit rules for generate .o and .lo files
%implicit = ();
while ($makefile =~ /^\.c\.(l?o):\s*\n\t+(.*)$/mg) {
$implicit{$1} = $2;
}
# Find existing .o and .lo dependencies
my %srcs;
while ($makefile =~ /^(\w+\.l?o):\s*(\S+\.c)/mg) {
$srcs{$1} = $2;
}
# Do .lo files first
foreach my $obj (sort keys %objs) {
next unless $obj =~ /(\S+)\.(l?o)$/;
if ($2 eq "o" && exists($srcs{"$1.lo"})) {
# If we have both .lo and .o files, make the .o depend on the .lo
$new_makefile .= sprintf("%s: %s.lo\n", $obj, $1);
} else {
# XXX - search for the .c file if we don't know it
# XXX - use MANIFEST file for this
my $src = $srcs{$obj} || $1 . '.c';
my $ext = $2;
my $imp = $implicit{$ext};
$imp =~ s/\$</$src/g;
my $deps = sprintf("%s: %s %s", $obj, $src,
join(' ', find_depends($src)));
if (length($deps) > 80) {
my $off = 0;
my $indent = length($obj) + 2;
while (length($deps) - $off > 80 - $indent) {
my $pos;
if ($off != 0) {
$new_makefile .= ' ' x $indent;
$pos = rindex($deps, ' ', $off + 80 - $indent - 2);
} else {
$pos = rindex($deps, ' ', $off + 78);
}
$new_makefile .= substr($deps, $off, $pos - $off) . " \\\n";
$off = $pos + 1;
}
$new_makefile .= ' ' x $indent;
$new_makefile .= substr($deps, $off) . "\n";
} else {
$new_makefile .= "$deps\n";
}
$new_makefile .= "\t$imp\n";
}
}
rename($file, $file . ".old");
if (!open(MF, ">$file")) {
warn("cannot open $file: $!\n");
rename($file . ".old", $file);
} else {
print MF $new_makefile || warn("cannot write $file: $!\n");
close(MF);
}
}
exit(0);
sub find_depends {
my $src = $_[0];
my ($deps, $code, @headers);
if ($src !~ /\//) {
# XXX - want build dir not src dir
$src = "$dir_vars{'srcdir'}/$src";
}
# resolve $(srcdir) etc.
foreach (keys %dir_vars) {
$src =~ s/\$[\(\{]$_[\)\}]/$dir_vars{$_}/g;
}
# find open source file and find headers used by it
if (!open(FILE, "<$src")) {
warn "unable to open $src\n";
return "";
}
local $/; # enable "slurp" mode
$code = <FILE>;
close(FILE);
# find all headers
while ($code =~ /^#\s*include\s+["<](\S+)[">]/mg) {
my ($hdr, $hdr_path) = find_header($1);
if (defined($hdr)) {
push(@headers, $hdr);
# Look for other includes in the .h file
push(@headers, find_depends($hdr_path));
}
}
@headers;
}
# find the path to a header file
# returns path or undef if not found
sub find_header {
my $hdr = $_[0];
# Look for .h.in files in top_builddir and build dir
return ("\$(top_builddir\)/$hdr", "./${hdr}.in") if -r "./${hdr}.in";
return ("./$hdr", "$dir_vars{'srcdir'}/${hdr}.in") if -r "$dir_vars{'srcdir'}/${hdr}.in";
foreach my $inc (@incpaths) {
my $hdr_path = "$inc/$hdr";
# resolve variables in include path
foreach (keys %dir_vars) {
$hdr_path =~ s/\$[\(\{]$_[\)\}]/$dir_vars{$_}/g;
}
return ("$inc/$hdr", $hdr_path) if -r $hdr_path;
}
undef;
}