X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/0d2f7508bde40050b73db12208f62d6295fc49a7..05f3d08eedc39846a14b06a0c4826351bfd93a4b:/mkfiles.pl diff --git a/mkfiles.pl b/mkfiles.pl index 9ab5223..52c9a74 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -17,16 +17,19 @@ # - special-define objects (foo.o[PREPROCSYMBOL]) are not # supported in the mac or vcproj makefiles. -use FileHandle; +use IO::Handle; use Cwd; -open IN, "Recipe" or do { +@filestack = (); +$in = new IO::Handle; +open $in, "Recipe" or do { # We want to deal correctly with being run from one of the # subdirs in the source tree. So if we can't find Recipe here, # try one level up. chdir ".."; - open IN, "Recipe" or die "unable to open Recipe file\n"; + open $in, "Recipe" or die "unable to open Recipe file\n"; }; +push @filestack, $in; # HACK: One of the source files in `charset' is auto-generated by # sbcsgen.pl. We need to generate that _now_, before attempting @@ -45,13 +48,20 @@ $project_name = "project"; # this is a good enough default @allobjs = (); # all object file names -while () { +readinput: while (1) { + while (not defined ($_ = <$in>)) { + close $in; + last readinput if 0 == scalar @filestack; + $in = pop @filestack; + } + + chomp; + split; + # Skip comments (unless the comments belong, for example because # they're part of a diversion). next if /^\s*#/ and !defined $divert; - chomp; - split; if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = \$help; next; } if ($_[0] eq "!end") { $divert = undef; next; } if ($_[0] eq "!name") { $project_name = $_[1]; next; } @@ -59,13 +69,27 @@ while () { if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;} if ($_[0] eq "!specialobj" and &mfval($_[1])) { $specialobj{$_[1]}->{$_[2]} = 1; next;} if ($_[0] eq "!begin") { - if (&mfval($_[1])) { + if ($_[1] =~ /^>(.*)/) { + $divert = \$auxfiles{$1}; + } elsif (&mfval($_[1])) { $divert = \$makefile_extra{$_[1]}; - } else { - $divert = \$dummy; } next; } + if ($_[0] eq "!include") { + @newfiles = (); + for ($i = 1; $i <= $#_; $i++) { + push @newfiles, (sort glob $_[$i]); + } + for ($i = $#newfiles; $i >= 0; $i--) { + $file = $newfiles[$i]; + $f = new IO::Handle; + open $f, "<$file" or die "unable to open include file '$file'\n"; + push @filestack, $f; + } + $in = $filestack[$#filestack]; + next; + } # If we're gathering help text, keep doing so. if (defined $divert) { ${$divert} .= "$_\n"; next; } # Ignore blank lines. @@ -80,6 +104,11 @@ while () { $prog = undef; die "$.: unexpected + line\n" if !defined $lastlistref; } elsif ($_[1] eq "=") { + $groups{$_[0]} = []; + $listref = $groups{$_[0]}; + $prog = undef; + shift @objs; # eat the group name + } elsif ($_[1] eq "+=") { $groups{$_[0]} = [] if !defined $groups{$_[0]}; $listref = $groups{$_[0]}; $prog = undef; @@ -89,7 +118,7 @@ while () { $prog = $_[0]; shift @objs; # eat the program name } else { - die "$.: unrecognised line type\n"; + die "$.: unrecognised line type: '$_'\n"; } shift @objs; # eat the +, the = or the : @@ -101,8 +130,28 @@ while () { $i eq "[X]" or $i eq "[U]" or $i eq "[MX]") and defined $prog) { $type = substr($i,1,(length $i)-2); } else { - push @$listref, $i; - push @allobjs, $i; + if ($i =~ /\?$/) { + # Object files with a trailing question mark are optional: + # the build can proceed fine without them, so we only use + # them if their primary source files are present. + $i =~ s/\?$//; + $i = undef unless defined &finddep($i); + } elsif ($i =~ /\|/) { + # Object file descriptions containing a vertical bar are + # lists of choices: we use the _first_ one whose primary + # source file is present. + @options = split /\|/, $i; + $j = undef; + foreach $k (@options) { + $j=$k, last if defined &finddep($k); + } + die "no alternative found for $i\n" unless defined $j; + $i = $j; + } + if (defined $i) { + push @$listref, $i; + push @allobjs, $i; + } } } if ($prog and $type) { @@ -113,7 +162,11 @@ while () { $lastlistref = $listref; } -close IN; +foreach $aux (sort keys %auxfiles) { + open AUX, ">$aux"; + print AUX $auxfiles{$aux}; + close AUX; +} # Find object file names with predefines (in square brackets after # the module name), and decide on actual object names for them. @@ -159,23 +212,8 @@ foreach $i (@prognames) { $programs{$i} = [@list]; foreach $jj (@list) { $j = $srcname{$jj}; - # Dependencies for "x" start with "x.c" or "x.m" (depending on - # which one exists). - # Dependencies for "x.res" start with "x.rc". - # Dependencies for "x.rsrc" start with "x.r". - # Both types of file are pushed on the list of files to scan. - # Libraries (.lib) don't have dependencies at all. - if ($j =~ /^(.*)\.res$/) { - $file = "$1.rc"; - $depends{$jj} = [$file]; - push @scanlist, $file; - } elsif ($j =~ /^(.*)\.rsrc$/) { - $file = "$1.r"; - $depends{$jj} = [$file]; - push @scanlist, $file; - } elsif ($j !~ /\./) { - $file = "$j.c"; - $file = "$j.m" unless &findfile($file); + $file = &finddep($j); + if (defined $file) { $depends{$jj} = [$file]; push @scanlist, $file; } @@ -282,6 +320,32 @@ sub findfile { return $findfilecache{$name}; } +sub finddep { + my $j = shift @_; + my $file; + # Find the first dependency of an object. + + # Dependencies for "x" start with "x.c" or "x.m" (depending on + # which one exists). + # Dependencies for "x.res" start with "x.rc". + # Dependencies for "x.rsrc" start with "x.r". + # Both types of file are pushed on the list of files to scan. + # Libraries (.lib) don't have dependencies at all. + if ($j =~ /^(.*)\.res$/) { + $file = "$1.rc"; + } elsif ($j =~ /^(.*)\.rsrc$/) { + $file = "$1.r"; + } elsif ($j !~ /\./) { + $file = "$j.c"; + $file = "$j.m" unless &findfile($file); + } else { + # For everything else, we assume it's its own dependency. + $file = $j; + } + $file = undef unless &findfile($file); + return $file; +} + sub objects { my ($prog, $otmpl, $rtmpl, $ltmpl, $prefix, $dirsep) = @_; my @ret; @@ -350,6 +414,8 @@ sub deps { ($x = $otmpl) =~ s/X/$i/; } @deps = @{$depends{$ii}}; + # Skip things which are their own dependency. + next if grep { $_ eq $i } @deps; @deps = map { $_ = &findfile($_); s/\//$dirsep/g; @@ -423,12 +489,13 @@ if (defined $makefiles{'cygwin'}) { "# RCINC = --include-dir c:\\cygwin\\include\\\n". "\n". &splitline("CFLAGS = -mno-cygwin -Wall -O2 -D_WINDOWS -DDEBUG -DWIN32S_COMPAT". - " -D_NO_OLDNAMES -DNO_MULTIMON " . + " -D_NO_OLDNAMES -DNO_MULTIMON -DNO_HTMLHELP " . (join " ", map {"-I$dirpfx$_"} @srcdirs)) . "\n". "LDFLAGS = -mno-cygwin -s\n". &splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1". - " --define WINVER=0x0400 --define MINGW32_FIX=1")."\n". + " --define WINVER=0x0400 --define MINGW32_FIX=1 " . + (join " ", map {"--include $dirpfx$_"} @srcdirs) )."\n". "\n"; print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C")); print "\n\n"; @@ -622,7 +689,7 @@ if (defined $makefiles{'vc'}) { "\n"; if ($d->{obj} =~ /\.res$/) { print "\trc \$(FWHACK) \$(RCFL) -r -DWIN32 -D_WIN32 ". - "-DWINVER=0x0400 ".$d->{deps}->[0]."\n"; + "-DWINVER=0x0400 -fo".$d->{obj}." ".$d->{deps}->[0]."\n"; } else { $deflist = join "", map { " /D$_" } @{$d->{defs}}; print "\tcl \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist".