Annotation of embedaddon/sudo/mkdep.pl, revision 1.1.1.4
1.1 misho 1: #!/usr/bin/env perl
1.1.1.4 ! misho 2: #
! 3: # Copyright (c) 2011-2013 Todd C. Miller <Todd.Miller@courtesan.com>
! 4: #
! 5: # Permission to use, copy, modify, and distribute this software for any
! 6: # purpose with or without fee is hereby granted, provided that the above
! 7: # copyright notice and this permission notice appear in all copies.
! 8: #
! 9: # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: #
1.1 misho 17:
18: use File::Temp qw/ :mktemp /;
19: use Fcntl;
20: use warnings;
21:
22: die "usage: $0 Makefile ...\n" unless $#ARGV >= 0;
23:
24: my @incpaths;
25: my %dir_vars;
26: my %implicit;
1.1.1.2 misho 27: my %generated;
1.1 misho 28:
29: # Read in MANIFEST fail if present
30: my %manifest;
31: if (open(MANIFEST, "<MANIFEST")) {
32: while (<MANIFEST>) {
33: chomp;
34: next unless /([^\/]+\.[cly])$/;
35: $manifest{$1} = $_;
36: }
37: }
38:
39: foreach (@ARGV) {
40: mkdep($_);
41: }
42:
43: sub mkdep {
44: my $file = $_[0];
45: $file =~ s:^\./+::; # strip off leading ./
46:
47: my $makefile;
48: if (open(MF, "<$file")) {
49: local $/; # enable "slurp" mode
50: $makefile = <MF>;
51: } else {
52: warn "$0: $file: $!\n";
53: return undef;
54: }
55: close(MF);
56:
57: # New makefile, minus the autogenerated dependencies
58: my $separator = "# Autogenerated dependencies, do not modify";
59: my $new_makefile = $makefile;
60: $new_makefile =~ s/${separator}.*$//s;
61: $new_makefile .= "$separator\n";
62:
63: # Old makefile, join lines with continuation characters
64: $makefile =~ s/\\\n//mg;
65:
66: # Expand some configure bits
1.1.1.2 misho 67: $makefile =~ s:\@DEV\@::g;
1.1 misho 68: $makefile =~ s:\@COMMON_OBJS\@:aix.lo:;
1.1.1.4 ! misho 69: $makefile =~ s:\@SUDO_OBJS\@:openbsd.o preload.o selinux.o sesh.o solaris.o sudo_noexec.lo:;
! 70: $makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo sssd.lo:;
1.1 misho 71: # XXX - fill in AUTH_OBJS from contents of the auth dir instead
1.1.1.2 misho 72: $makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:;
1.1.1.3 misho 73: $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 mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo utimes.lo globtest.o fnm_test.o:;
1.1 misho 74:
75: # Parse OBJS lines
76: my %objs;
77: while ($makefile =~ /^[A-Z0-9_]*OBJS\s*=\s*(.*)/mg) {
78: foreach (split/\s+/, $1) {
79: next if /^\$[\(\{].*[\)\}]$/; # skip included vars for now
80: $objs{$_} = 1;
81: }
82: }
83:
84: # Find include paths
85: @incpaths = ();
86: while ($makefile =~ /-I(\S+)/mg) {
87: push(@incpaths, $1) unless $1 eq ".";
88: }
89:
1.1.1.2 misho 90: # Check for generated files
91: if ($makefile =~ /GENERATED\s*=\s*(.+)$/m) {
92: foreach (split(/\s+/, $1)) {
93: $generated{$_} = 1;
94: }
95: }
96:
1.1 misho 97: # Values of srcdir, top_srcdir, top_builddir, incdir
98: %dir_vars = ();
99: $file =~ m:^(.*)/+[^/]+:;
100: $dir_vars{'srcdir'} = $1 || '.';
101: $dir_vars{'devdir'} = $dir_vars{'srcdir'};
102: $dir_vars{'authdir'} = $dir_vars{'srcdir'} . "/auth";
103: $dir_vars{'top_srcdir'} = '.';
104: #$dir_vars{'top_builddir'} = '.';
105: $dir_vars{'incdir'} = 'include';
106:
107: # Find implicit rules for generate .o and .lo files
108: %implicit = ();
109: while ($makefile =~ /^\.c\.(l?o):\s*\n\t+(.*)$/mg) {
110: $implicit{$1} = $2;
111: }
112:
113: # Find existing .o and .lo dependencies
114: my %old_deps;
115: while ($makefile =~ /^(\w+\.l?o):\s*(\S+\.c)/mg) {
116: $old_deps{$1} = $2;
117: }
118:
119: # Sort files so we do .lo files first
120: foreach my $obj (sort keys %objs) {
121: next unless $obj =~ /(\S+)\.(l?o)$/;
122: if ($2 eq "o" && exists($objs{"$1.lo"})) {
123: # If we have both .lo and .o files, make the .o depend on the .lo
124: $new_makefile .= sprintf("%s: %s.lo\n", $obj, $1);
125: } else {
126: # Use old depenencies when mapping objects to their source.
127: # If no old depenency, use the MANIFEST file to find the source.
128: my $src = $1 . '.c';
129: my $ext = $2;
130: if (exists $old_deps{$obj}) {
131: $src = $old_deps{$obj};
132: } elsif (exists $manifest{$src}) {
133: $src = $manifest{$src};
134: foreach (sort { length($b) <=> length($a) } keys %dir_vars) {
1.1.1.2 misho 135: next if $_ eq "devdir";
1.1 misho 136: last if $src =~ s:^\Q$dir_vars{$_}/\E:\$\($_\)/:;
137: }
138: } else {
139: warn "$file: unable to find source for $obj\n";
140: }
141: my $imp = $implicit{$ext};
142: $imp =~ s/\$</$src/g;
143:
144: my $deps = sprintf("%s: %s %s", $obj, $src,
145: join(' ', find_depends($src)));
146: if (length($deps) > 80) {
147: my $off = 0;
148: my $indent = length($obj) + 2;
149: while (length($deps) - $off > 80 - $indent) {
150: my $pos;
151: if ($off != 0) {
152: $new_makefile .= ' ' x $indent;
153: $pos = rindex($deps, ' ', $off + 80 - $indent - 2);
154: } else {
155: $pos = rindex($deps, ' ', $off + 78);
156: }
157: $new_makefile .= substr($deps, $off, $pos - $off) . " \\\n";
158: $off = $pos + 1;
159: }
160: $new_makefile .= ' ' x $indent;
161: $new_makefile .= substr($deps, $off) . "\n";
162: } else {
163: $new_makefile .= "$deps\n";
164: }
165: $new_makefile .= "\t$imp\n";
166: }
167: }
168:
1.1.1.2 misho 169: my $newfile = $file . ".new";
170: if (!open(MF, ">$newfile")) {
171: warn("cannot open $newfile: $!\n");
1.1 misho 172: } else {
1.1.1.2 misho 173: print MF $new_makefile || warn("cannot write $newfile: $!\n");
174: close(MF) || warn("cannot close $newfile: $!\n");;
175: rename($newfile, $file);
1.1 misho 176: }
177: }
178:
179: exit(0);
180:
181: sub find_depends {
182: my $src = $_[0];
183: my ($deps, $code, @headers);
184:
185: if ($src !~ /\//) {
186: # XXX - want build dir not src dir
187: $src = "$dir_vars{'srcdir'}/$src";
188: }
189:
190: # resolve $(srcdir) etc.
191: foreach (keys %dir_vars) {
192: $src =~ s/\$[\(\{]$_[\)\}]/$dir_vars{$_}/g;
193: }
194:
195: # find open source file and find headers used by it
196: if (!open(FILE, "<$src")) {
197: warn "unable to open $src\n";
198: return "";
199: }
200: local $/; # enable "slurp" mode
201: $code = <FILE>;
202: close(FILE);
203:
204: # find all headers
205: while ($code =~ /^#\s*include\s+["<](\S+)[">]/mg) {
206: my ($hdr, $hdr_path) = find_header($1);
207: if (defined($hdr)) {
208: push(@headers, $hdr);
209: # Look for other includes in the .h file
210: push(@headers, find_depends($hdr_path));
211: }
212: }
213:
214: @headers;
215: }
216:
217: # find the path to a header file
218: # returns path or undef if not found
219: sub find_header {
220: my $hdr = $_[0];
221:
222: # Look for .h.in files in top_builddir and build dir
223: return ("\$(top_builddir\)/$hdr", "./${hdr}.in") if -r "./${hdr}.in";
224: return ("./$hdr", "$dir_vars{'srcdir'}/${hdr}.in") if -r "$dir_vars{'srcdir'}/${hdr}.in";
225:
1.1.1.2 misho 226: if (exists $generated{$hdr}) {
227: my $hdr_path = $dir_vars{'devdir'} . '/' . $hdr;
228: return ('$(devdir)/' . $hdr, $hdr_path) if -r $hdr_path;
229: }
1.1 misho 230: foreach my $inc (@incpaths) {
231: my $hdr_path = "$inc/$hdr";
232: # resolve variables in include path
233: foreach (keys %dir_vars) {
1.1.1.2 misho 234: next if $_ eq "devdir";
1.1 misho 235: $hdr_path =~ s/\$[\(\{]$_[\)\}]/$dir_vars{$_}/g;
236: }
237: return ("$inc/$hdr", $hdr_path) if -r $hdr_path;
238: }
239:
240: undef;
241: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>