#!/usr/bin/perl ############################################################################## # Copyright (C) 2007, 2008 Paulo Cesar Pereira de Andrade. All Rights Reserved. # # This is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # Authors: # Paulo Cesar Pereira de Andrade ############################################################################## use Cwd; use File::Basename; use Getopt::Std; use strict; my %filenames; my %options; ############################################################################## # Check for command line options # TODO add possibly risky option of not creating dependency of libc and # gcc header files, and possibly others; the X Protocol for example # isn't expected to change, but some structures, usually extensions still can... Getopt::Std::getopts("p:n:ish?", \%options); if ($options{'h'} or $options{'?'}) { print("Usage:\n", File::Basename::basename($0), " [options ...]\n", " -p path Use given path as root build dir [default: .]\n", " -n name Name for new dependency file [default: name of base directory]", " -i Install mode. Traces new files.\n", " -s Silent mode.\n", " -h, -? Prints this message and quits.\n"); exit(0); } ############################################################################## # Check root build dir $options{'p'} = Cwd::realpath(".") unless $options{'p'}; $options{'n'} = File::Basename::basename($options{'p'}) unless $options{'n'}; my $depfile = "$options{p}/$options{n}.deps"; my $instfile = "$options{p}/$options{n}.files"; $ENV{TMP} = "/tmp" unless ($ENV{TMP} ne ""); my $stracefile = "$ENV{TMP}/$options{n}.strace.$$"; ############################################################################## # From xorg-build.pl ############################################################################## sub git_config { my ($option) = @_; $option = `git-config --global --get $option`; $option =~ s/^\s+//; $option =~ s/\s+$//; return $option; }; my $x_builddir = git_config("xorg-git.build-dir"); $x_builddir = "$ENV{HOME}/anongit.freedesktop.org/build" unless ($x_builddir); my $x_depsdir = git_config("xorg-git.deps-dir"); $x_depsdir = "/usr/local/xorg/deps" unless ($x_depsdir); my $x_destdir = git_config("xorg-git.dest-dir"); $x_destdir = "/usr/local/xorg" unless ($x_destdir); ############################################################################## # End From xorg-build.pl ############################################################################## ############################################################################## my $buildtree = $options{'p'}; my $strace = "/usr/bin/strace"; my $arguments = "-o$stracefile -q -s256 -etrace=execve,open -f"; # Verify program and arguments to run and trace execution my $make = join(" ", @ARGV); if ($make eq "") { $make = "make" . ($options{'i'} ? " install" : ""); } # Strace build print(" $strace $arguments $make\n"); # trace it! and print output so it can be logged open(STRACE, "$strace $arguments $make|"); while() { print($_); } close(STRACE); die("Strace exit code $? ($!)") if ($?); ############################################################################## # Build dependency file based on opens and execs during build open(STRACE, "<$stracefile") or die("Cannot read $stracefile ($!)\n"); while () { chomp; # If did open or exec file file. # Also check for files opened to write, like gcc temp files # And also don't generate dependencies on directories if (m/^\d+\s+(\w+)\("([^"]+)".*\) = \d+$/) { my $syscall = $1; my $filename = $2; # Only care about fully specified pathnames next unless ($filename =~ m/^\//); $filename = Cwd::realpath($filename); # Don't care about files inside build tree or temp dir next if ($filename =~ m/^$buildtree/ or $filename =~ m/^$ENV{TMP}/ or $filename =~ m/^\/tmp\// or $filename =~ m/\.cache$/); # Also don't care about anything not in builddir or destdir # XXX FIXME This doesn't catch install outside destdir... next if ($filename !~ m/^$x_builddir/ and $filename !~ m/^$x_destdir/); # Install mode if ($options{'i'}) { if ($syscall eq "open") { # Only log new files next unless (m/O_WRONLY|O_RDWR/); # Only care about files next if (m/O_DIRECTORY/); $filenames{$filename} = 0; } else { $filenames{$filename} = 1; } } # Build mode else { # Don't generate dependency on new files or directory checks if ($syscall eq "open") { next if (m/O_WRONLY|O_RDWR|O_DIRECTORY/); } $filenames{$filename} = 1; } } } close(STRACE); `rm -f $stracefile`; ############################################################################## # Write dependency and file list open(DEP, ">>$depfile") or die("Cannot append to $depfile ($!)."); open(LST, ">>$instfile") or die("Cannot open $instfile for writing ($!)."); foreach (keys %filenames) { # For now don't cache rename or something like link/unlink # So, just check if file exists... If some file is missed # xorg-deps.pl should flag it if (-f $_) { if ($filenames{$_} == 0) { print(LST "$_\n"); } # Add install dependency else { print(DEP "$_\n"); } } } close(LST); close(DEP);