summaryrefslogtreecommitdiff
path: root/mkdep.pl
diff options
context:
space:
mode:
authorTodd C. Miller <Todd.Miller@courtesan.com>2011-05-25 09:02:25 -0400
committerTodd C. Miller <Todd.Miller@courtesan.com>2011-05-25 09:02:25 -0400
commit8d9c8b6b92d2e8fd19d724a8eb4482e6a060788d (patch)
tree36dd97aebc3f0e6ba343fc298775222de7822649 /mkdep.pl
parentf6233f1489957bece8a21271f159dce3fc56632f (diff)
downloadsudo-8d9c8b6b92d2e8fd19d724a8eb4482e6a060788d.tar.gz
Auto-generate Makefile dependencies with a perl script.
Diffstat (limited to 'mkdep.pl')
-rwxr-xr-xmkdep.pl184
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;
+}