diff options
author | Todd C. Miller <Todd.Miller@courtesan.com> | 2011-05-25 09:02:25 -0400 |
---|---|---|
committer | Todd C. Miller <Todd.Miller@courtesan.com> | 2011-05-25 09:02:25 -0400 |
commit | 8d9c8b6b92d2e8fd19d724a8eb4482e6a060788d (patch) | |
tree | 36dd97aebc3f0e6ba343fc298775222de7822649 /mkdep.pl | |
parent | f6233f1489957bece8a21271f159dce3fc56632f (diff) | |
download | sudo-8d9c8b6b92d2e8fd19d724a8eb4482e6a060788d.tar.gz |
Auto-generate Makefile dependencies with a perl script.
Diffstat (limited to 'mkdep.pl')
-rwxr-xr-x | mkdep.pl | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/mkdep.pl b/mkdep.pl new file mode 100755 index 000000000..9219d9df2 --- /dev/null +++ b/mkdep.pl @@ -0,0 +1,184 @@ +#!/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 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 + push(@objs, $_); + } + } + + # 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 @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); + + # 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; +} |