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>