chiark / gitweb /
changelog: document last change
[sgt-puzzles.git] / mkfiles.pl
index 4aa7f20fe3f021efe9cf9c6a88a203c404c97464..8772dd762104425e93a62a55edea36a9a8092536 100755 (executable)
 #  - special-define objects (foo.o[PREPROCSYMBOL]) are not
 #    supported in the mac or vcproj makefiles.
 
+use warnings;
 use IO::Handle;
 use Cwd;
+use File::Basename;
+
+while ($#ARGV >= 0) {
+    if ($ARGV[0] eq "-U") {
+        # Convenience for Unix users: -U means that after we finish what
+        # we're doing here, we also run mkauto.sh and then 'configure'. So
+        # it's a one-stop shop for regenerating the actual end-product
+        # Unix makefile.
+        #
+        # Arguments supplied after -U go to configure.
+        $do_unix = 1;
+        shift @ARGV;
+        @confargs = @ARGV;
+        @ARGV = ();
+    } else {
+        die "unrecognised command-line argument '$ARGV[0]'\n";
+    }
+}
 
 @filestack = ();
 $in = new IO::Handle;
@@ -38,7 +57,8 @@ eval 'chdir "charset"; require "sbcsgen.pl"; chdir ".."';
 
 @srcdirs = ("./");
 
-$divert = undef; # ref to scalar in which text is currently being put
+$divert = undef; # ref to array of refs of scalars in which text is
+                 # currently being put
 $help = ""; # list of newline-free lines of help text
 $project_name = "project"; # this is a good enough default
 %makefiles = (); # maps makefile types to output makefile pathnames
@@ -49,30 +69,51 @@ $project_name = "project"; # this is a good enough default
 @allobjs = (); # all object file names
 
 readinput: while (1) {
+  $in = $filestack[$#filestack];
   while (not defined ($_ = <$in>)) {
-    close $in;
+    close $filestack[$#filestack];
+    pop @filestack;
     last readinput if 0 == scalar @filestack;
-    $in = pop @filestack;
+    $in = $filestack[$#filestack];
   }
-
   chomp;
-  split;
+  @_ = split;
 
-  # Skip comments (unless the comments belong, for example because
-  # they're part of a diversion).
-  next if /^\s*#/ and !defined $divert;
+  # If we're gathering help text, keep doing so.
+  if (defined $divert) {
+      if ((defined $_[0]) && $_[0] eq "!end") {
+         $divert = undef;
+      } else {
+          for my $ref (@$divert) {
+              ${$ref} .= "$_\n";
+          }
+      }
+      next;
+  }
+  # Skip comments and blank lines.
+  next if /^\s*#/ or scalar @_ == 0;
 
-  if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = \$help; next; }
-  if ($_[0] eq "!end") { $divert = undef; next; }
+  if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = [\$help]; next; }
   if ($_[0] eq "!name") { $project_name = $_[1]; next; }
   if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; }
   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 "!cflags" and &mfval($_[1])) {
+      ($rest = $_) =~ s/^\s*\S+\s+\S+\s+\S+\s*//; # find rest of input line
+      $rest = 1 if $rest eq "";
+      $cflags{$_[1]}->{$_[2]} = $rest;
+      next;
+  }
   if ($_[0] eq "!begin") {
-      if ($_[1] =~ /^>(.*)/) {
-         $divert = \$auxfiles{$1};
-      } elsif (&mfval($_[1])) {
-         $divert = \$makefile_extra{$_[1]};
+      my @args = @_;
+      shift @args;
+      $divert = [];
+      for my $component (@args) {
+          if ($component =~ /^>(.*)/) {
+              push @$divert, \$auxfiles{$1};
+          } elsif ($component =~ /^([^_]*)(_.*)?$/ and &mfval($1)) {
+              push @$divert, \$makefile_extra{$component};
+          }
       }
       next;
   }
@@ -87,13 +128,8 @@ readinput: while (1) {
          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.
-  next if scalar @_ == 0;
 
   # Now we have an ordinary line. See if it's an = line, a : line
   # or a + line.
@@ -206,7 +242,7 @@ foreach $i (@allobjs) {
 foreach $i (@prognames) {
   ($prog, $type) = split ",", $i;
   # Strip duplicate object names.
-  $prev = undef;
+  $prev = '';
   @list = grep { $status = ($prev ne $_); $prev=$_; $status }
           sort @{$programs{$i}};
   $programs{$i} = [@list];
@@ -238,7 +274,6 @@ foreach $i (@prognames) {
 while (scalar @scanlist > 0) {
   $file = shift @scanlist;
   next if defined $further{$file}; # skip if we've already done it
-  $resource = ($file =~ /\.rc$/ ? 1 : 0);
   $further{$file} = [];
   $dirfile = &findfile($file);
   open IN, "$dirfile" or die "unable to open source file $file\n";
@@ -267,7 +302,7 @@ foreach $i (keys %depends) {
   while (scalar @scanlist > 0) {
     $file = shift @scanlist;
     foreach $j (@{$further{$file}}) {
-      if ($dep{$j} != 1) {
+      if (!$dep{$j}) {
         $dep{$j} = 1;
         push @{$depends{$i}}, $j;
         push @scanlist, $j;
@@ -284,7 +319,7 @@ sub mfval($) {
     # Returns true if the argument is a known makefile type. Otherwise,
     # prints a warning and returns false;
     if (grep { $type eq $_ }
-       ("vc","vcproj","cygwin","borland","lcc","gtk","mpw","osx")) {
+       ("vc","vcproj","cygwin","borland","lcc","gtk","am","mpw","nestedvm","osx","wce","gnustep","emcc","clangcl")) {
            return 1;
        }
     warn "$.:unknown makefile type '$type'\n";
@@ -296,7 +331,8 @@ sub mfval($) {
 sub dirpfx {
     my ($path) = shift @_;
     my ($sep) = shift @_;
-    my $ret = "", $i;
+    my $ret = "";
+    my $i;
     while (($i = index $path, $sep) >= 0) {
        $path = substr $path, ($i + length $sep);
        $ret .= "..$sep";
@@ -350,6 +386,7 @@ sub objects {
   my ($prog, $otmpl, $rtmpl, $ltmpl, $prefix, $dirsep) = @_;
   my @ret;
   my ($i, $x, $y);
+  ($otmpl, $rtmpl, $ltmpl) = map { defined $_ ? $_ : "" } ($otmpl, $rtmpl, $ltmpl);
   @ret = ();
   foreach $ii (@{$programs{$prog}}) {
     $i = $objname{$ii};
@@ -384,7 +421,8 @@ sub special {
 
 sub splitline {
   my ($line, $width, $splitchar) = @_;
-  my ($result, $len);
+  my $result = "";
+  my $len;
   $len = (defined $width ? $width : 76);
   $splitchar = (defined $splitchar ? $splitchar : '\\');
   while (length $line > $len) {
@@ -400,7 +438,8 @@ sub splitline {
 sub deps {
   my ($otmpl, $rtmpl, $prefix, $dirsep, $depchar, $splitchar) = @_;
   my ($i, $x, $y);
-  my @deps, @ret;
+  my @deps;
+  my @ret;
   @ret = ();
   $depchar ||= ':';
   foreach $ii (sort keys %depends) {
@@ -414,6 +453,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;
@@ -458,8 +499,155 @@ sub manpages {
   return ();
 }
 
+$orig_dir = cwd;
+
 # Now we're ready to output the actual Makefiles.
 
+if (defined $makefiles{'clangcl'}) {
+    $mftyp = 'clangcl';
+    $dirpfx = &dirpfx($makefiles{'clangcl'}, "/");
+
+    ##-- Makefile for cross-compiling using clang-cl, lld-link, and
+    ##   MinGW's windres for resource compilation.
+    #
+    # This makefile allows a complete Linux-based cross-compile, but
+    # using the real Visual Studio header files and libraries. In
+    # order to run it, you will need:
+    #
+    #  - MinGW windres on your PATH.
+    #     * On Ubuntu as of 16.04, you can apt-get install
+    #       binutils-mingw-w64-x86-64 and binutils-mingw-w64-i686
+    #       which will provide (respectively) 64- and 32-bit versions,
+    #       under the names to which RCCMD is defined below.
+    #  - clang-cl and lld-link on your PATH.
+    #     * I built these from the up-to-date LLVM project trunk git
+    #       repositories, as of 2017-02-05.
+    #  - case-mashed copies of the Visual Studio include directories.
+    #     * On a real VS installation, run vcvars32.bat and look at
+    #       the resulting value of %INCLUDE%. Take a full copy of each
+    #       of those directories, and inside the copy, for each
+    #       include file that has an uppercase letter in its name,
+    #       make a lowercased symlink to it. Additionally, one of the
+    #       directories will contain files called driverspecs.h and
+    #       specstrings.h, and those will need symlinks called
+    #       DriverSpecs.h and SpecStrings.h.
+    #     * Now, on Linux, define the environment variable INCLUDE to
+    #       be a list, separated by *semicolons* (in the Windows
+    #       style), of those directories, but before all of them you
+    #       must also include lib/clang/5.0.0/include from the clang
+    #       installation area (which contains in particular a
+    #       clang-compatible stdarg.h overriding the Visual Studio
+    #       one).
+    #  - similarly case-mashed copies of the library directories.
+    #     * Again, on a real VS installation, run vcvars32 or
+    #       vcvarsx86_amd64 (as appropriate), look at %LIB%, make a
+    #       copy of each directory, and provide symlinks within that
+    #       directory so that all the files can be opened as
+    #       lowercase.
+    #     * Then set LIB to be a semicolon-separated list of those
+    #       directories (but you'll need to change which set of
+    #       directories depending on whether you want to do a 32-bit
+    #       or 64-bit build).
+    #  - for a 64-bit build, set 'Platform=x64' in the environment as
+    #    well, or else on the make command line.
+    #     * This is a variable understood only by this makefile - none
+    #       of the tools we invoke will know it - but it's consistent
+    #       with the way the VS scripts like vcvarsx86_amd64.bat set
+    #       things up, and since the environment has to change
+    #       _anyway_ between 32- and 64-bit builds (different set of
+    #       paths in $LIB) it's reasonable to have the choice of
+    #       compilation target driven by another environment variable
+    #       set in parallel with that one.
+    #  - for older versions of the VS libraries you may also have to
+    #    set EXTRA_console and/or EXTRA_windows to the name of an
+    #    object file manually extracted from one of those libraries.
+    #     * This is because old VS seems to manage its startup code by
+    #       having libcmt.lib contain lots of *crt0.obj objects, one
+    #       for each possible user entry point (main, WinMain and the
+    #       wide-char versions of both), of which the linker arranges
+    #       to include the right one by special-case code. But lld
+    #       only seems to mimic half of that code - it does include
+    #       the right crt0 object, but it doesn't also deliberately
+    #       _avoid_ including the _wrong_ ones, and since all those
+    #       objects define a common set of global symbols for other
+    #       parts of the library to use, lld may well select an
+    #       arbitrary one of them the first time it sees a reference
+    #       to one of those global symbols, and then later also select
+    #       the _right_ one for the application's entry point, causing
+    #       a multiple-definitions crash.
+    #     * So the workaround is to explicitly include the right
+    #       *crt0.obj file on the linker command line before lld even
+    #       begins searching libraries. Hence, for a console
+    #       application, you might extract crt0.obj from the library
+    #       in question and set EXTRA_console=crt0.obj, and for a GUI
+    #       application, do the same with wincrt0.obj. Then this
+    #       makefile will include the right one of those objects
+    #       alongside the matching /subsystem linker option.
+
+    open OUT, ">$makefiles{'clangcl'}"; select OUT;
+    print
+    "# Makefile for cross-compiling $project_name using clang-cl, lld-link,\n".
+    "# and MinGW's windres, using GNU make on Linux.\n".
+    "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+    "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
+    print $help;
+    print
+    "\n".
+    "CCCMD = clang-cl\n".
+    "ifeq (\$(Platform),x64)\n".
+    "CCTARGET = x86_64-pc-windows-msvc18.0.0\n".
+    "RCCMD = x86_64-w64-mingw32-windres\n".
+    "else\n".
+    "CCTARGET = i386-pc-windows-msvc18.0.0\n".
+    "RCCMD = i686-w64-mingw32-windres\n".
+    "endif\n".
+    "CC = \$(CCCMD) --target=\$(CCTARGET)\n".
+    &splitline("RC = \$(RCCMD) --preprocessor=\$(CCCMD) ".
+               "--preprocessor-arg=/TC --preprocessor-arg=/E")."\n".
+    "LD = lld-link\n".
+    "\n".
+    "# C compilation flags\n".
+    &splitline("CFLAGS = /nologo /W3 /O1 " .
+               (join " ", map {"-I$dirpfx$_"} @srcdirs) .
+               " /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401 ".
+               "/D_CRT_SECURE_NO_WARNINGS")."\n".
+    "LFLAGS = /incremental:no /dynamicbase /nxcompat\n".
+    &splitline("RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs).
+               " -DWIN32 -D_WIN32 -DWINVER=0x0400 --define MINGW32_FIX=1")."\n".
+    "\n".
+    "\n";
+    print &splitline("all:" . join "", map { " \$(BUILDDIR)$_.exe" } &progrealnames("G:C"));
+    print "\n\n";
+    foreach $p (&prognames("G:C")) {
+       ($prog, $type) = split ",", $p;
+       $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", undef);
+       print &splitline("\$(BUILDDIR)$prog.exe: " . $objstr), "\n";
+
+       $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", "X.lib");
+       $subsys = ($type eq "G") ? "windows" : "console";
+       print &splitline("\t\$(LD) \$(LFLAGS) \$(XLFLAGS) ".
+                         "/out:\$(BUILDDIR)$prog.exe ".
+                         "/lldmap:\$(BUILDDIR)$prog.map ".
+                         "/subsystem:$subsys\$(SUBSYSVER) ".
+                         "\$(EXTRA_$subsys) $objstr")."\n\n";
+    }
+    foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", $dirpfx, "/", "vc")) {
+        print &splitline(sprintf("%s: %s", $d->{obj},
+                                 join " ", @{$d->{deps}})), "\n";
+        if ($d->{obj} =~ /\.res$/) {
+            print "\t\$(RC) \$(RCFLAGS) ".$d->{deps}->[0]." -o ".$d->{obj}."\n\n";
+       } else {
+           $deflist = join "", map { " /D$_" } @{$d->{defs}};
+            print "\t\$(CC) /Fo\$(BUILDDIR)".$d->{obj}." \$(COMPAT) \$(CFLAGS) \$(XFLAGS)$deflist /c \$<\n\n";
+        }
+    }
+    print "\nclean:\n".
+        &splitline("\trm -f \$(BUILDDIR)*.obj \$(BUILDDIR)*.exe ".
+                   "\$(BUILDDIR)*.res \$(BUILDDIR)*.map ".
+                   "\$(BUILDDIR)*.exe.manifest")."\n";
+    select STDOUT; close OUT;
+}
+
 if (defined $makefiles{'cygwin'}) {
     $mftyp = 'cygwin';
     $dirpfx = &dirpfx($makefiles{'cygwin'}, "/");
@@ -487,7 +675,7 @@ 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".
@@ -519,7 +707,7 @@ if (defined $makefiles{'cygwin'}) {
       }
     }
     print "\n";
-    print $makefile_extra{'cygwin'};
+    print $makefile_extra{'cygwin'} || "";
     print "\nclean:\n".
     "\trm -f *.o *.exe *.res.o *.map\n".
     "\n";
@@ -570,7 +758,7 @@ if (defined $makefiles{'borland'}) {
     print "\n\n";
     foreach $p (&prognames("G:C")) {
       ($prog, $type) = split ",", $p;
-      $objstr = &objects($p, "X.obj", "X.res", undef);
+      $objstr =  &objects($p, "X.obj", "X.res", undef);
       print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n";
       my $ap = ($type eq "G") ? "-aa" : "-ap";
       print "\tilink32 $ap -Gn -L\$(BCB)\\lib \@$prog.rsp\n\n";
@@ -619,7 +807,7 @@ if (defined $makefiles{'borland'}) {
       }
     }
     print "\n";
-    print $makefile_extra{'borland'};
+    print $makefile_extra{'borland'} || "";
     print "\nclean:\n".
     "\t-del *.obj\n".
     "\t-del *.exe\n".
@@ -652,7 +840,7 @@ if (defined $makefiles{'vc'}) {
       "MAKEFILE = Makefile.vc\n".
       "\n".
       "# C compilation flags\n".
-      "CFLAGS = /nologo /W3 /O1 /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401\n".
+      "CFLAGS = /nologo /W3 /O1 /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401 /I.\n".
       "LFLAGS = /incremental:no /fixed\n".
       "\n";
     print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
@@ -695,7 +883,115 @@ if (defined $makefiles{'vc'}) {
        }
     }
     print "\n";
-    print $makefile_extra{'vc'};
+    print $makefile_extra{'vc'} || "";
+    print "\nclean: tidy\n".
+      "\t-del *.exe\n\n".
+      "tidy:\n".
+      "\t-del *.obj\n".
+      "\t-del *.res\n".
+      "\t-del *.pch\n".
+      "\t-del *.aps\n".
+      "\t-del *.ilk\n".
+      "\t-del *.pdb\n".
+      "\t-del *.rsp\n".
+      "\t-del *.dsp\n".
+      "\t-del *.dsw\n".
+      "\t-del *.ncb\n".
+      "\t-del *.opt\n".
+      "\t-del *.plg\n".
+      "\t-del *.map\n".
+      "\t-del *.idb\n".
+      "\t-del debug.log\n";
+    select STDOUT; close OUT;
+}
+
+if (defined $makefiles{'wce'}) {
+    $mftyp = 'wce';
+    $dirpfx = &dirpfx($makefiles{'wce'}, "\\");
+
+    ##-- eMbedded Visual C PocketPC makefile
+    open OUT, ">$makefiles{'wce'}"; select OUT;
+    print
+      "# Makefile for $project_name on PocketPC using eMbedded Visual C.\n".
+      "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+      "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
+    print $help;
+    print
+      "\n".
+      "# If you rename this file to `Makefile', you should change this line,\n".
+      "# so that the .rsp files still depend on the correct makefile.\n".
+      "MAKEFILE = Makefile.wce\n".
+      "\n".
+      "# This makefile expects the environment to have been set up by one\n".
+      "# of the PocketPC batch files wcearmv4.bat and wceemulator.bat. No\n".
+      "# other build targets are currently supported, because they would\n".
+      "# need a section in this if statement.\n".
+      "!if \"\$(TARGETCPU)\" == \"emulator\"\n".
+      "PLATFORM_DEFS=/D \"_i386_\" /D \"i_386_\" /D \"_X86_\" /D \"x86\"\n".
+      "CC=cl\n".
+      "BASELIBS=commctrl.lib coredll.lib corelibc.lib aygshell.lib\n".
+      "MACHINE=IX86\n".
+      "!else\n".
+      "PLATFORM_DEFS=/D \"ARM\" /D \"_ARM_\" /D \"ARMV4\"\n".
+      "CC=clarm\n".
+      "BASELIBS=commctrl.lib coredll.lib aygshell.lib\n".
+      "MACHINE=ARM\n".
+      "!endif\n".
+      "\n".
+      "# C compilation flags\n".
+      "CFLAGS = /nologo /W3 /O1 /MC /D _WIN32_WCE=420 /D \"WIN32_PLATFORM_PSPC=400\" /D UNDER_CE=420 \\\n".
+      "         \$(PLATFORM_DEFS) \\\n".
+      "         /D \"UNICODE\" /D \"_UNICODE\" /D \"NDEBUG\" /D \"NO_HTMLHELP\"\n".
+      "\n".
+      "LFLAGS = /nologo /incremental:no \\\n".
+      "         /base:0x00010000 /stack:0x10000,0x1000 /entry:WinMainCRTStartup \\\n".
+      "         /nodefaultlib:libc.lib /nodefaultlib:libcmt.lib /nodefaultlib:msvcrt.lib /nodefaultlib:OLDNAMES.lib \\\n".
+      "         /subsystem:windowsce,4.20 /align:4096 /MACHINE:\$(MACHINE)\n".
+      "\n".
+      "RCFL = /d UNDER_CE=420 /d _WIN32_WCE=420 /d \"WIN32_PLATFORM_PSPC=400\" \\\n".
+      "       \$(PLATFORM_DEFS) \\\n".
+      "       /d \"NDEBUG\" /d \"UNICODE\" /d \"_UNICODE\"\n".
+      "\n";
+    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G"));
+    print "\n\n";
+    foreach $p (&prognames("G")) {
+       ($prog, $type) = split ",", $p;
+       $objstr = &objects($p, "X.obj", "X.res", undef);
+       print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n";
+       print "\tlink \$(LFLAGS) -out:$prog.exe -map:$prog.map \@$prog.rsp\n\n";
+    }
+    foreach $p (&prognames("G")) {
+       ($prog, $type) = split ",", $p;
+       print $prog, ".rsp: \$(MAKEFILE)\n";
+       $objstr = &objects($p, "X.obj", "X.res", undef);
+       @objlist = split " ", $objstr;
+       @objlines = ("");
+       foreach $i (@objlist) {
+           if (length($objlines[$#objlines] . " $i") > 50) {
+               push @objlines, "";
+           }
+           $objlines[$#objlines] .= " $i";
+       }
+       print "\techo \$(BASELIBS) > $prog.rsp\n";
+       for ($i=0; $i<=$#objlines; $i++) {
+           print "\techo$objlines[$i] >> $prog.rsp\n";
+       }
+       print "\n";
+    }
+    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) {
+       print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
+         "\n";
+       if ($d->{obj} =~ /\.res$/) {
+           print "\trc \$(FWHACK) \$(RCFL) -r -fo".
+             $d->{obj}." ".$d->{deps}->[0]."\n";
+       } else {
+           $deflist = join "", map { " /D$_" } @{$d->{defs}};
+           print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist".
+             " /c ".$d->{deps}->[0]." /Fo$d->{obj}\n";
+       }
+    }
+    print "\n";
+    print $makefile_extra{'wce'} || "";
     print "\nclean: tidy\n".
       "\t-del *.exe\n\n".
       "tidy:\n".
@@ -720,8 +1016,6 @@ if (defined $makefiles{'vc'}) {
 if (defined $makefiles{'vcproj'}) {
     $mftyp = 'vcproj';
 
-    $orig_dir = cwd;
-
     ##-- MSVC 6 Workspace and projects
     #
     # Note: All files created in this section are written in binary
@@ -990,7 +1284,7 @@ if (defined $makefiles{'gtk'}) {
     "\n".
     "# You can define this path to point at your tools if you need to\n".
     "# TOOLPATH = /opt/gcc/bin\n".
-    "CC = \$(TOOLPATH)cc\n".
+    "CC := \$(TOOLPATH)\$(CC)\n".
     "# You can manually set this to `gtk-config' or `pkg-config gtk+-1.2'\n".
     "# (depending on what works on your system) if you want to enforce\n".
     "# building with GTK 1.2, or you can set it to `pkg-config gtk+-2.0'\n".
@@ -998,11 +1292,11 @@ if (defined $makefiles{'gtk'}) {
     "# to 1.2 if it isn't found.\n".
     "GTK_CONFIG = sh -c 'pkg-config gtk+-2.0 \$\$0 2>/dev/null || gtk-config \$\$0'\n".
     "\n".
-    &splitline("CFLAGS = -O2 -Wall -Werror -g " .
+    &splitline("CFLAGS := -O2 -Wall -Werror -ansi  -g " .
               (join " ", map {"-I$dirpfx$_"} @srcdirs) .
-              " `\$(GTK_CONFIG) --cflags`")."\n".
-    "XLDFLAGS = `\$(GTK_CONFIG) --libs`\n".
-    "ULDFLAGS =#\n".
+              " `\$(GTK_CONFIG) --cflags` \$(CFLAGS)")."\n".
+    "XLIBS = `\$(GTK_CONFIG) --libs` -lm\n".
+    "ULIBS = -lm#\n".
     "INSTALL=install\n",
     "INSTALL_PROGRAM=\$(INSTALL)\n",
     "INSTALL_DATA=\$(INSTALL)\n",
@@ -1013,15 +1307,16 @@ if (defined $makefiles{'gtk'}) {
     "mandir=\$(prefix)/man\n",
     "man1dir=\$(mandir)/man1\n",
     "\n";
-    print &splitline("all:" . join "", map { " $_" } &progrealnames("X:U"));
+    print &splitline("all:" . join "", map { " \$(BINPREFIX)$_" }
+                     &progrealnames("X:U"));
     print "\n\n";
     foreach $p (&prognames("X:U")) {
       ($prog, $type) = split ",", $p;
       $objstr = &objects($p, "X.o", undef, undef);
-      print &splitline($prog . ": " . $objstr), "\n";
+      print &splitline("\$(BINPREFIX)" . $prog . ": " . $objstr), "\n";
       $libstr = &objects($p, undef, undef, "-lX");
-      print &splitline("\t\$(CC)" . $mw . " \$(${type}LDFLAGS) -o \$@ " .
-                       $objstr . " $libstr", 69), "\n\n";
+      print &splitline("\t\$(CC) -o \$@ $objstr $libstr \$(XLFLAGS) \$(${type}LIBS)", 69),
+         "\n\n";
     }
     foreach $d (&deps("X.o", undef, $dirpfx, "/")) {
       print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
@@ -1031,9 +1326,127 @@ if (defined $makefiles{'gtk'}) {
          " -c \$< -o \$\@\n";
     }
     print "\n";
-    print $makefile_extra{'gtk'};
+    print $makefile_extra{'gtk'} || "";
     print "\nclean:\n".
-    "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U")) . "\n";
+    "\trm -f *.o". (join "", map { " \$(BINPREFIX)$_" } &progrealnames("X:U")) . "\n";
+    select STDOUT; close OUT;
+}
+
+if (defined $makefiles{'am'}) {
+    $mftyp = 'am';
+    die "Makefile.am in a subdirectory is not supported\n"
+        if &dirpfx($makefiles{'am'}, "/") ne "";
+
+    ##-- Unix/autoconf Makefile.am
+    open OUT, ">$makefiles{'am'}"; select OUT;
+    print
+    "# Makefile.am for $project_name under Unix with Autoconf/Automake.\n".
+    "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+    "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n\n";
+
+    print $makefile_extra{'am_begin'} || "";
+
+    # All programs go in noinstprogs by default. If you want them
+    # installed anywhere else, you have to also add them to
+    # bin_PROGRAMS using '!begin am'. (Automake doesn't seem to mind
+    # having a program name in _both_ of bin_PROGRAMS and
+    # noinst_PROGRAMS.)
+    @noinstprogs = ();
+    foreach $p (&prognames("X:U")) {
+        ($prog, $type) = split ",", $p;
+        push @noinstprogs, $prog;
+    }
+    print &splitline(join " ", "noinst_PROGRAMS", "=", @noinstprogs), "\n";
+
+    %objtosrc = ();
+    %amspeciallibs = ();
+    %amlibobjname = ();
+    %allsources = ();
+    foreach $d (&deps("X", undef, "", "/", "am")) {
+        my $obj = $d->{obj};
+        my $use_archive = 0;
+        
+        if (defined $d->{defs}) {
+            # This file needs to go in an archive, so that we can
+            # change the preprocess flags to include some -Ds
+            $use_archive = 1;
+            $archivecppflags{$obj} = [map { " -D$_" } @{$d->{defs}}];
+        }
+        if (defined $cflags{'am'} && $cflags{'am'}->{$obj}) {
+            # This file needs to go in an archive, so that we can
+            # change the compile flags as specified in Recipe
+            $use_archive = 1;
+            $archivecflags{$obj} = [$cflags{'am'}->{$obj}];
+        }
+        if ($use_archive) {
+            $amspeciallibs{$obj} = "lib${obj}.a";
+            $amlibobjname{$obj} = "lib${obj}_a-" .
+                basename($d->{deps}->[0], ".c", ".m") .
+                ".\$(OBJEXT)";
+        }
+        $objtosrc{$obj} = $d->{deps};
+        map { $allsources{$_} = 1 } @{$d->{deps}};
+    }
+
+    # 2014-02-22: as of automake-1.14 we begin to get complained at if
+    # we don't use this option
+    print "AUTOMAKE_OPTIONS = subdir-objects\n\n";
+
+    # Complete list of source and header files. Not used by the
+    # auto-generated parts of this makefile, but Recipe might like to
+    # have it available as a variable so that mandatory-rebuild things
+    # (version.o) can conveniently be made to depend on it.
+    print &splitline(join " ", "allsources", "=",
+                     sort {$a cmp $b} keys %allsources), "\n\n";
+
+    @amcppflags = map {"-I\$(srcdir)/$_"} @srcdirs;
+    print &splitline(join " ", "AM_CPPFLAGS", "=", @amcppflags, "\n");
+
+    @amcflags = ("\$(GTK_CFLAGS)", "\$(WARNINGOPTS)");
+    print &splitline(join " ", "AM_CFLAGS", "=", @amcflags), "\n";
+
+    %amlibsused = ();
+    foreach $p (&prognames("X:U")) {
+        ($prog, $type) = split ",", $p;
+        @progsources = ("${prog}_SOURCES", "=");
+        %sourcefiles = ();
+        @ldadd = ();
+        $objstr = &objects($p, "X", undef, undef);
+        foreach $obj (split / /,$objstr) {
+            if ($amspeciallibs{$obj}) {
+                $amlibsused{$obj} = 1;
+                push @ldadd, $amlibobjname{$obj};
+            } else {
+                map { $sourcefiles{$_} = 1 } @{$objtosrc{$obj}};
+            }
+        }
+        push @progsources, sort { $a cmp $b } keys %sourcefiles;
+        print &splitline(join " ", @progsources), "\n";
+        if ($type eq "X") {
+            push @ldadd, "\$(GTK_LIBS)";
+        }
+        push @ldadd, "-lm";
+        print &splitline(join " ", "${prog}_LDADD", "=", @ldadd), "\n";
+        print "\n";
+    }
+
+    foreach $obj (sort { $a cmp $b } keys %amlibsused) {
+        print &splitline(join " ", "lib${obj}_a_SOURCES", "=",
+                         @{$objtosrc{$obj}}), "\n";
+        print &splitline(join " ", "lib${obj}_a_CPPFLAGS", "=",
+                         @amcflags, @{$archivecppflags{$obj}}), "\n"
+                             if $archivecppflags{$obj};
+        print &splitline(join " ", "lib${obj}_a_CFLAGS", "=",
+                         @amcflags, @{$archivecflags{$obj}}), "\n"
+                             if $archivecflags{$obj};
+    }
+    print &splitline(join " ", "noinst_LIBRARIES", "=",
+                     sort { $a cmp $b }
+                      map { $amspeciallibs{$_} }
+                     keys %amlibsused),
+                     "\n\n";
+
+    print $makefile_extra{'am'} || "";
     select STDOUT; close OUT;
 }
 
@@ -1229,7 +1642,7 @@ if (defined $makefiles{'lcc'}) {
       }
     }
     print "\n";
-    print $makefile_extra{'lcc'};
+    print $makefile_extra{'lcc'} || "";
     print "\nclean:\n".
     "\t-del *.obj\n".
     "\t-del *.exe\n".
@@ -1238,9 +1651,63 @@ if (defined $makefiles{'lcc'}) {
     select STDOUT; close OUT;
 }
 
+if (defined $makefiles{'nestedvm'}) {
+    $mftyp = 'nestedvm';
+    $dirpfx = &dirpfx($makefiles{'nestedvm'}, "/");
+
+    ##-- NestedVM makefile
+    open OUT, ">$makefiles{'nestedvm'}"; select OUT;
+    print
+    "# Makefile for $project_name under NestedVM.\n".
+    "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+    "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
+    # gcc command line option is -D not /D
+    ($_ = $help) =~ s/=\/D/=-D/gs;
+    print $_;
+    print
+    "\n".
+    "# This path points at the nestedvm root directory\n".
+    "NESTEDVM = /opt/nestedvm\n".
+    "# You can define this path to point at your tools if you need to\n".
+    "TOOLPATH = \$(NESTEDVM)/upstream/install/bin\n".
+    "CC = \$(TOOLPATH)/mips-unknown-elf-gcc\n".
+    "\n".
+    &splitline("CFLAGS = -O2 -Wall -Werror -DSLOW_SYSTEM -g " .
+              (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n".
+    "\n";
+    print &splitline("all:" . join "", map { " $_.jar" } &progrealnames("X"));
+    print "\n\n";
+    foreach $p (&prognames("X")) {
+      ($prog, $type) = split ",", $p;
+      $objstr = &objects($p, "X.o", undef, undef);
+      $objstr =~ s/gtk\.o/nestedvm\.o/g;
+      print &splitline($prog . ".mips: " . $objstr), "\n";
+      $libstr = &objects($p, undef, undef, "-lX");
+      print &splitline("\t\$(CC) \$(${type}LDFLAGS) -o \$@ " .
+                       $objstr . " $libstr -lm", 69), "\n\n";
+    }
+    foreach $d (&deps("X.o", undef, $dirpfx, "/")) {
+      $oobjs = $d->{obj};
+      $ddeps= join " ", @{$d->{deps}};
+      $oobjs =~ s/gtk/nestedvm/g;
+      $ddeps =~ s/gtk/nestedvm/g;
+      print &splitline(sprintf("%s: %s", $oobjs, $ddeps)),
+          "\n";
+      $deflist = join "", map { " -D$_" } @{$d->{defs}};
+      print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" .
+         " -c \$< -o \$\@\n";
+    }
+    print "\n";
+    print $makefile_extra{'nestedvm'} || "";
+    print "\nclean:\n".
+    "\trm -rf *.o *.mips *.class *.html *.jar org applet.manifest\n";
+    select STDOUT; close OUT;
+}
+
 if (defined $makefiles{'osx'}) {
     $mftyp = 'osx';
     $dirpfx = &dirpfx($makefiles{'osx'}, "/");
+    @osxarchs = ('i386');
 
     ##-- Mac OS X makefile
     open OUT, ">$makefiles{'osx'}"; select OUT;
@@ -1253,20 +1720,20 @@ if (defined $makefiles{'osx'}) {
     print $_;
     print
     "CC = \$(TOOLPATH)gcc\n".
+    "LIPO = \$(TOOLPATH)lipo\n".
     "\n".
     &splitline("CFLAGS = -O2 -Wall -Werror -g " .
               (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n".
     "LDFLAGS = -framework Cocoa\n".
     &splitline("all:" . join "", map { " $_" } &progrealnames("MX:U")) .
-    "\n" .
-    $makefile_extra{'osx'} .
-    "\n".
+    "\n";
+    print $makefile_extra{'osx'} || "";
+    print "\n".
     ".SUFFIXES: .o .c .m\n".
     "\n";
     print "\n\n";
     foreach $p (&prognames("MX")) {
       ($prog, $type) = split ",", $p;
-      $objstr = &objects($p, "X.o", undef, undef);
       $icon = &special($p, ".icns");
       $infoplist = &special($p, "info.plist");
       print "${prog}.app:\n\tmkdir -p \$\@\n";
@@ -1284,34 +1751,202 @@ if (defined $makefiles{'osx'}) {
       }
       $targets .= " \$(${prog}_extra)";
       print &splitline("${prog}: $targets", 69) . "\n\n";
-      print &splitline("${prog}.app/Contents/MacOS/$prog: ".
-                      "${prog}.app/Contents/MacOS " . $objstr), "\n";
       $libstr = &objects($p, undef, undef, "-lX");
-      print &splitline("\t\$(CC)" . $mw . " \$(LDFLAGS) -o \$@ " .
+      $archbins = "";
+      foreach $arch (@osxarchs) {
+       $objstr = &objects($p, "X.${arch}.o", undef, undef);
+       print &splitline("${prog}.${arch}.bin: " . $objstr), "\n";
+       print &splitline("\t\$(CC) -arch ${arch} -mmacosx-version-min=10.4 \$(LDFLAGS) -o \$@ " .
                        $objstr . " $libstr", 69), "\n\n";
+       $archbins .= " ${prog}.${arch}.bin";
+      }
+      print &splitline("${prog}.app/Contents/MacOS/$prog: ".
+                      "${prog}.app/Contents/MacOS" . $archbins), "\n";
+      print &splitline("\t\$(LIPO) -create $archbins -output \$@", 69), "\n\n";
     }
     foreach $p (&prognames("U")) {
       ($prog, $type) = split ",", $p;
+      $libstr = &objects($p, undef, undef, "-lX");
+      $archbins = "";
+      foreach $arch (@osxarchs) {
+       $objstr = &objects($p, "X.${arch}.o", undef, undef);
+       print &splitline("${prog}.${arch}: " . $objstr), "\n";
+       print &splitline("\t\$(CC) -arch ${arch} -mmacosx-version-min=10.4 \$(ULDFLAGS) -o \$@ " .
+                       $objstr . " $libstr", 69), "\n\n";
+       $archbins .= " ${prog}.${arch}";
+      }
+      print &splitline("${prog}:" . $archbins), "\n";
+      print &splitline("\t\$(LIPO) -create $archbins -output \$@", 69), "\n\n";
+    }
+    foreach $arch (@osxarchs) {
+      foreach $d (&deps("X.${arch}.o", undef, $dirpfx, "/")) {
+        print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
+            "\n";
+        $deflist = join "", map { " -D$_" } @{$d->{defs}};
+        if ($d->{deps}->[0] =~ /\.m$/) {
+         print "\t\$(CC) -arch $arch -mmacosx-version-min=10.4 -x objective-c \$(COMPAT) \$(FWHACK) \$(CFLAGS)".
+             " \$(XFLAGS)$deflist -c \$< -o \$\@\n";
+        } else {
+         print "\t\$(CC) -arch $arch -mmacosx-version-min=10.4 \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" .
+             " -c \$< -o \$\@\n";
+        }
+      }
+    }
+    print "\nclean:\n".
+    "\trm -f *.o *.dmg". (join "", map { my $a=$_; (" $a", map { " ${a}.$_" } @osxarchs) } &progrealnames("U")) . "\n".
+    "\trm -rf *.app\n";
+    select STDOUT; close OUT;
+}
+
+if (defined $makefiles{'gnustep'}) {
+    $mftyp = 'gnustep';
+    $dirpfx = &dirpfx($makefiles{'gnustep'}, "/");
+
+    ##-- GNUstep makefile (use with 'gs_make -f Makefile.gnustep')
+
+    # This is a pretty evil way to do things. In an ideal world, I'd
+    # use the approved GNUstep makefile mechanism which just defines a
+    # variable or two saying what source files go into what binary and
+    # then includes application.make. Unfortunately, that has the
+    # automake-ish limitation that it doesn't let you choose different
+    # command lines for each object, so I can't arrange for all those
+    # files with -DTHIS and -DTHAT to Just Work.
+    #
+    # A simple if ugly fix would be to have mkfiles.pl construct a
+    # directory full of stub C files of the form '#define thing',
+    # '#include "real_source_file"', and then reference those in this
+    # makefile. That would also make it easy to build a proper
+    # automake makefile.
+    open OUT, ">$makefiles{'gnustep'}"; select OUT;
+    print
+    "# Makefile for $project_name under GNUstep.\n".
+    "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+    "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
+    # gcc command line option is -D not /D
+    ($_ = $help) =~ s/=\/D/=-D/gs;
+    print $_;
+    print
+    "NEEDS_GUI=yes\n".
+    "include \$(GNUSTEP_MAKEFILES)/common.make\n".
+    "include \$(GNUSTEP_MAKEFILES)/rules.make\n".
+    "include \$(GNUSTEP_MAKEFILES)/Instance/rules.make\n".
+    "\n".
+    &splitline("all::" . join "", map { " $_" } &progrealnames("MX:U")) .
+    "\n";
+    print $makefile_extra{'gnustep'} || "";
+    print "\n".
+    ".SUFFIXES: .o .c .m\n".
+    "\n";
+    print "\n\n";
+    foreach $p (&prognames("MX")) {
+      ($prog, $type) = split ",", $p;
+      $icon = &special($p, ".icns");
+      $infoplist = &special($p, "info.plist");
+      print "${prog}.app:\n\tmkdir -p \$\@\n";
+      $targets = "${prog}.app ${prog}.app/$prog";
+      if (defined $icon) {
+       print "${prog}.app/Resources: ${prog}.app\n\tmkdir -p \$\@\n";
+       print "${prog}.app/Resources/${prog}.icns: ${prog}.app/Resources $icon\n\tcp $icon \$\@\n";
+       $targets .= " ${prog}.app/Resources/${prog}.icns";
+      }
+      if (defined $infoplist) {
+       print "${prog}.app/Info.plist: ${prog}.app $infoplist\n\tcp $infoplist \$\@\n";
+       $targets .= " ${prog}.app/Info.plist";
+      }
+      $targets .= " \$(${prog}_extra)";
+      print &splitline("${prog}: $targets", 69) . "\n\n";
+      $libstr = &objects($p, undef, undef, "-lX");
       $objstr = &objects($p, "X.o", undef, undef);
-      print &splitline($prog . ": " . $objstr), "\n";
+      print &splitline("${prog}.app/$prog: " . $objstr), "\n";
+      print &splitline("\t\$(CC) \$(ALL_LDFLAGS) -o \$@ " . $objstr . " \$(ALL_LIB_DIRS) $libstr \$(ALL_LIBS)", 69), "\n\n";
+    }
+    foreach $p (&prognames("U")) {
+      ($prog, $type) = split ",", $p;
       $libstr = &objects($p, undef, undef, "-lX");
-      print &splitline("\t\$(CC)" . $mw . " \$(ULDFLAGS) -o \$@ " .
-                      $objstr . " $libstr", 69), "\n\n";
+      $objstr = &objects($p, "X.o", undef, undef);
+      print &splitline("${prog}: " . $objstr), "\n";
+      print &splitline("\t\$(CC) \$(ULDFLAGS) -o \$@ " . $objstr . " $libstr", 69), "\n\n";
     }
     foreach $d (&deps("X.o", undef, $dirpfx, "/")) {
       print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
-          "\n";
+      "\n";
       $deflist = join "", map { " -D$_" } @{$d->{defs}};
       if ($d->{deps}->[0] =~ /\.m$/) {
-       print "\t\$(CC) -x objective-c \$(COMPAT) \$(FWHACK) \$(CFLAGS)".
-           " \$(XFLAGS)$deflist -c \$< -o \$\@\n";
+        print "\t\$(CC) -DGNUSTEP \$(ALL_OBJCFLAGS) \$(COMPAT) \$(FWHACK) \$(OBJCFLAGS)".
+                " \$(XFLAGS)$deflist -c \$< -o \$\@\n";
       } else {
-       print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" .
-           " -c \$< -o \$\@\n";
+        print "\t\$(CC) \$(ALL_CFLAGS) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" .
+              " -c \$< -o \$\@\n";
       }
     }
-    print "\nclean:\n".
-    "\trm -f *.o *.dmg". (join "", map { " $_" } &progrealnames("U")) . "\n".
+    print "\nclean::\n".
+    "\trm -f *.o ". (join " ", &progrealnames("U")) . "\n".
     "\trm -rf *.app\n";
     select STDOUT; close OUT;
 }
+
+if (defined $makefiles{'emcc'}) {
+    $mftyp = 'emcc';
+    $dirpfx = &dirpfx($makefiles{'emcc'}, "/");
+
+    ##-- Makefile for building Javascript puzzles via Emscripten
+
+    open OUT, ">$makefiles{'emcc'}"; select OUT;
+    print
+    "# Makefile for $project_name using Emscripten. Requires GNU make.\n".
+    "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+    "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
+    # emcc command line option is -D not /D
+    ($_ = $help) =~ s/=\/D/=-D/gs;
+    print $_;
+    print
+    "\n".
+    "# This can be set on the command line to point at the emcc command,\n".
+    "# if it is not on your PATH.\n".
+    "EMCC = emcc\n".
+    "\n".
+    &splitline("CFLAGS = -DSLOW_SYSTEM " .
+              (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n".
+    "\n";
+    $output_js_files = join "", map { " \$(OUTPREFIX)$_.js" } &progrealnames("X");
+    print &splitline("all:" . $output_js_files);
+    print "\n\n";
+    foreach $p (&prognames("X")) {
+      ($prog, $type) = split ",", $p;
+      $objstr = &objects($p, "X.o", undef, undef);
+      $objstr =~ s/gtk\.o/emcc\.o/g;
+      print &splitline("\$(OUTPREFIX)" . $prog . ".js: " . $objstr . " emccpre.js emcclib.js emccx.json"), "\n";
+      print "\t\$(EMCC) -o \$(OUTPREFIX)".$prog.".js ".
+          "-O2 ".
+          "-s ASM_JS=1 ".
+          "--pre-js emccpre.js ".
+          "--js-library emcclib.js ".
+          "-s EXPORTED_FUNCTIONS=\"`sed 's://.*::' emccx.json | tr -d ' \\n'`\" " . $objstr . "\n\n";
+    }
+    foreach $d (&deps("X.o", undef, $dirpfx, "/")) {
+      $oobjs = $d->{obj};
+      $ddeps= join " ", @{$d->{deps}};
+      $oobjs =~ s/gtk/emcc/g;
+      $ddeps =~ s/gtk/emcc/g;
+      print &splitline(sprintf("%s: %s", $oobjs, $ddeps)),
+          "\n";
+      $deflist = join "", map { " -D$_" } @{$d->{defs}};
+      print "\t\$(EMCC) \$(CFLAGS) \$(XFLAGS)$deflist" .
+         " -c \$< -o \$\@\n";
+    }
+    print "\n";
+    print $makefile_extra{'emcc'} || "";
+    print "\nclean:\n".
+    "\trm -rf *.o $output_js_files\n";
+    select STDOUT; close OUT;
+}
+
+# All done, so do the Unix postprocessing if asked to.
+
+if ($do_unix) {
+    chdir $orig_dir;
+    system "./mkauto.sh";
+    die "mkfiles.pl: mkauto.sh returned $?\n" if $? > 0;
+    system "./configure", @confargs;
+    die "mkfiles.pl: configure returned $?\n" if $? > 0;
+}