#!@PERL@ # -*- perl -*- # @configure_input@ use strict; use DirHandle; use File::Basename; use File::Compare; use File::Copy; use File::stat; use FileHandle; use POSIX qw(O_RDWR O_CREAT SEEK_SET); ######################################################################## # # Command-line option handling # @ARGV == 4 or die "Usage: $0 \n"; my $generate_dir = shift; my $cache_dir = shift; my $commands = (join "\n", @ARGV) . "\n"; my $verbose = 0; ######################################################################## # # Update a cache entry # # Accepts one generated file name, source or header, as an argument. # If the corresponding cache file is textually identical, gives the # generated file the same timestamp. Otherwise, copies the generated # file into the cache. # # close enough for our purposes, and avoids making many system calls my $now = time; sub update_file ($) { my $gfile = shift; my $cfile = "$cache_dir/" . basename $gfile; my $gstat = stat $gfile; my $cstat = stat $cfile; if ($cstat && $gstat->size == $cstat->size && !compare $gfile, $cfile) { utime $now, $cstat->mtime, $gfile or die "Could not utime $gfile: $!\n"; } else { # MUST delete old file first to ensure correct resulting file name # on case-insensitive, case-preserving file systems (eg Cygwin, MacOSX) if (-f $cfile) { print "refresh-cache: removing $cfile\n" if ($verbose); # this rename hack required to circumvent a bug in the # case preservation of the cygwin file system rename $cfile, $cfile or die "Failed to rename $cfile: $!\n"; unlink $cfile or die "Could not remove $cfile: $!\n"; while (-f $cfile) { sleep 1; } } print "refresh-cache: copying $gfile -> $cfile\n" if ($verbose); copy $gfile, $cfile or die "Could not copy $gfile to $cfile: $!\n"; utime $now, $gstat->mtime, $cfile or die "Could not utime $cfile: $!\n"; } } ######################################################################## # # Update a cache entry's compilation command # # Accepts one generated source file name as an argument. Ensures # that the corresponding cached compilation commands match # $commands. If it already matches, no file is changed. # sub update_command ($) { my $gfile = shift; my $basename = basename $gfile, '.c'; my $commandfile = "$cache_dir/$basename.cmd"; my $handle; if (-f $commandfile) { $handle = new FileHandle $commandfile, O_RDONLY or die "Could not open $commandfile: $!\n"; my $content = join '', <$handle>; undef $handle; # we embed name of C file in the command file to ensure a case-sensitive # match, regardless of what the file system might be doing return if ($content eq "$basename.c\n$commands"); # MUST delete old file first to ensure correct resulting file name # on case-insensitive, case-preserving file systems (eg Cygwin, MacOSX) print "refresh-cache: removing $commandfile\n" if ($verbose); # this rename hack required to circumvent a bug in the # case preservation of the cygwin file system rename $commandfile, $commandfile or die "Failed to rename $commandfile: $!\n"; unlink $commandfile or die "Could not remove $commandfile: $!\n"; while (-f $commandfile) { sleep 1; } } $handle = new FileHandle $commandfile, O_WRONLY | O_CREAT | O_EXCL or die "Could not open $commandfile: $!\n"; $handle->print("$basename.c\n"); $handle->print($commands); undef $handle; } ######################################################################## # # The main event # my $dir = new DirHandle $generate_dir or die "Could not scan $generate_dir: $!\n"; my @gen_files = $dir->read; undef $dir; foreach (@gen_files) { my $file = "$generate_dir/$_"; #print "refresh-cache: considering $file\n" if ($verbose); /\.c$/ && update_command $file; /\.[ch]$/ && update_file $file; }