]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - mkfiles.pl
first pass
[PuTTY.git] / mkfiles.pl
index 788183211759552dd49df39bd4665bb743654685..ae15ac488d66caec8b68db0c021c490058b4d2d9 100755 (executable)
 #    are hardwired, and also the libraries are fixed. This is
 #    mainly because I was too scared to go anywhere near it.
 #  - sbcsgen.pl is still run at startup.
+#
+# FIXME: no attempt made to handle !forceobj in the project files.
 
+use warnings;
 use FileHandle;
+use File::Basename;
 use Cwd;
+use Digest::SHA qw(sha512_hex);
+
+if ($#ARGV >= 0 and ($ARGV[0] eq "-u" or $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' in
+    # the Unix subdirectory. So it's a one-stop shop for regenerating
+    # the actual end-product Unix makefile.
+    #
+    # Arguments supplied after -u go to configure.
+    #
+    # -U is identical, but runs 'configure' at the _top_ level, for
+    # people who habitually do that.
+    $do_unix = ($ARGV[0] eq "-U" ? 2 : 1);
+    shift @ARGV;
+    @confargs = @ARGV;
+}
 
 open IN, "Recipe" or do {
     # We want to deal correctly with being run from one of the
@@ -25,9 +45,10 @@ open IN, "Recipe" or do {
 };
 
 # HACK: One of the source files in `charset' is auto-generated by
-# sbcsgen.pl. We need to generate that _now_, before attempting
-# dependency analysis.
-eval 'chdir "charset"; require "sbcsgen.pl"; chdir ".."';
+# sbcsgen.pl, and licence.h is likewise generated by licence.pl. We
+# need to generate those _now_, before attempting dependency analysis.
+eval 'chdir "charset"; require "./sbcsgen.pl"; chdir ".."; select STDOUT;';
+eval 'require "./licence.pl"; select STDOUT;';
 
 @srcdirs = ("./");
 
@@ -40,23 +61,50 @@ $project_name = "project"; # this is a good enough default
 %groups = (); # maps group name to listref of objects/resources
 
 while (<IN>) {
-  # Skip comments (unless the comments belong, for example because
-  # they're part of a diversion).
-  next if /^\s*#/ and !defined $divert;
-
   chomp;
-  split;
+  @_ = split;
+
+  # If we're gathering help text, keep doing so.
+  if (defined $divert) {
+      if ((defined $_[0]) && $_[0] eq "!end") {
+         $divert = undef;
+      } else {
+         ${$divert} .= "$_\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 "!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
+      if ($rest eq "") {
+          # Make sure this file doesn't get lumped together with any
+          # other file's cflags.
+          $rest = "F" . $_[2];
+      } else {
+          # Give this file a specific set of cflags, but permit it to
+          # go together with other files using the same set.
+          $rest = "C" . $rest;
+      }
+      $cflags{$_[1]}->{$_[2]} = $rest;
+      next;
+  }
+  if ($_[0] eq "!forceobj") { $forceobj{$_[1]} = 1; next; }
   if ($_[0] eq "!begin") {
-      if (&mfval($_[1])) {
+      if ($_[1] =~ /^>(.*)/) {
+         $divert = \$auxfiles{$1};
+      } elsif (&mfval($_[1])) {
           $sect = $_[2] ? $_[2] : "end";
          $divert = \($makefile_extra{$_[1]}->{$sect});
       } else {
+         $dummy = '';
          $divert = \$dummy;
       }
       next;
@@ -92,9 +140,10 @@ while (<IN>) {
     $i = shift @objs;
     if ($groups{$i}) {
       foreach $j (@{$groups{$i}}) { unshift @objs, $j; }
-    } elsif (($i eq "[G]" or $i eq "[C]" or $i eq "[M]" or
-              $i eq "[X]" or $i eq "[U]" or $i eq "[MX]") and defined $prog) {
+    } elsif (($i =~ /^\[([A-Z]*)\]$/) and defined $prog) {
       $type = substr($i,1,(length $i)-2);
+      die "unrecognised program type for $prog [$type]\n"
+          if ! grep { $type eq $_ } qw(G C X U MX XT UT);
     } else {
       push @$listref, $i;
     }
@@ -109,6 +158,12 @@ while (<IN>) {
 
 close IN;
 
+foreach $aux (sort keys %auxfiles) {
+    open AUX, ">$aux";
+    print AUX $auxfiles{$aux};
+    close AUX;
+}
+
 # Now retrieve the complete list of objects and resource files, and
 # construct dependency data for them. While we're here, expand the
 # object list for each program, and complain if its type isn't set.
@@ -118,7 +173,7 @@ close IN;
 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];
@@ -163,12 +218,13 @@ foreach $i (@prognames) {
 # file name into a listref containing further source file names.
 
 %further = ();
+%allsourcefiles = (); # this is wanted by some makefiles
 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);
+  $allsourcefiles{$dirfile} = 1;
   open IN, "$dirfile" or die "unable to open source file $file\n";
   while (<IN>) {
     chomp;
@@ -195,7 +251,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;
@@ -212,19 +268,26 @@ 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")) {
-           return 1;
-       }
+       ("vc","vcproj","cygwin","borland","lcc","devcppproj","gtk","unix",
+         "am","osx","vstudio10","vstudio12","clangcl")) {
+        return 1;
+    }
     warn "$.:unknown makefile type '$type'\n";
     return 0;
 }
 
 # Utility routines while writing out the Makefiles.
 
+sub def {
+    my ($x) = shift @_;
+    return (defined $x) ? $x : "";
+}
+
 sub dirpfx {
     my ($path) = shift @_;
     my ($sep) = shift @_;
-    my $ret = "", $i;
+    my $ret = "";
+    my $i;
 
     while (($i = index $path, $sep) >= 0 ||
           ($j = index $path, "/") >= 0) {
@@ -240,14 +303,17 @@ sub dirpfx {
 
 sub findfile {
   my ($name) = @_;
-  my $dir;
+  my $dir = '';
   my $i;
   my $outdir = undef;
   unless (defined $findfilecache{$name}) {
     $i = 0;
     foreach $dir (@srcdirs) {
-      $outdir = $dir, $i++ if -f "$dir$name";
-      $outdir=~s/^\.\///;
+      if (-f "$dir$name") {
+        $outdir = $dir;
+        $i++;
+        $outdir =~ s/^\.\///;
+      }
     }
     die "multiple instances of source file $name\n" if $i > 1;
     $findfilecache{$name} = (defined $outdir ? $outdir . $name : undef);
@@ -259,6 +325,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 $i (@{$programs{$prog}}) {
     $x = "";
@@ -280,6 +347,7 @@ sub special {
   my ($prog, $suffix) = @_;
   my @ret;
   my ($i, $x, $y);
+  ($otmpl, $rtmpl, $ltmpl) = map { defined $_ ? $_ : "" } ($otmpl, $rtmpl, $ltmpl);
   @ret = ();
   foreach $i (@{$programs{$prog}}) {
     if (substr($i, (length $i) - (length $suffix)) eq $suffix) {
@@ -291,12 +359,14 @@ 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) {
     $line =~ /^(.{0,$len})\s(.*)$/ or $line =~ /^(.{$len,}?\s(.*)$/;
-    $result .= $1 . " ${splitchar}\n\t\t";
+    $result .= $1;
+    $result .= " ${splitchar}\n\t\t" if $2 ne '';
     $line = $2;
     $len = 60;
   }
@@ -306,7 +376,8 @@ sub splitline {
 sub deps {
   my ($otmpl, $rtmpl, $prefix, $dirsep, $mftyp, $depchar, $splitchar) = @_;
   my ($i, $x, $y);
-  my @deps, @ret;
+  my @deps;
+  my @ret;
   @ret = ();
   $depchar ||= ':';
   foreach $i (sort keys %depends) {
@@ -324,7 +395,7 @@ sub deps {
       s/\//$dirsep/g;
       $_ = $prefix . $_;
     } @deps;
-    push @ret, {obj => $x, deps => [@deps]};
+    push @ret, {obj => $x, obj_orig => $i, deps => [@deps]};
   }
   return @ret;
 }
@@ -363,25 +434,150 @@ sub manpages {
   return ();
 }
 
+$orig_dir = cwd;
+
 # Now we're ready to output the actual Makefiles.
 
+if (defined $makefiles{'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.
+
+    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=0x500 /DWINVER=0x500 ".
+               "/D_CRT_SECURE_NO_WARNINGS")."\n".
+    "LFLAGS = /incremental:no /dynamicbase /nxcompat\n".
+    &splitline("RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs).
+               " -DWIN32 -D_WIN32 -DWINVER=0x0400")."\n".
+    "\n".
+    &def($makefile_extra{'clangcl'}->{'vars'}) .
+    "\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.o", undef);
+       print &splitline("\$(BUILDDIR)$prog.exe: " . $objstr), "\n";
+
+       $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", "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) $objstr")."\n\n";
+    }
+    foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", $dirpfx, "/", "vc")) {
+        $extradeps = $forceobj{$d->{obj_orig}} ? ["*.c","*.h","*.rc"] : [];
+        print &splitline(sprintf("%s: %s", $d->{obj},
+                                 join " ", @$extradeps, @{$d->{deps}})), "\n";
+        if ($d->{obj} =~ /\.res\.o$/) {
+            print "\t\$(RC) \$(RCFLAGS) ".$d->{deps}->[0]." -o ".$d->{obj}."\n\n";
+       } else {
+            print "\t\$(CC) /Fo\$(BUILDDIR) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) /c \$<\n\n";
+        }
+    }
+    print "\n";
+    print &def($makefile_extra{'clangcl'}->{'end'});
+    print "\nclean:\n".
+        &splitline("\trm -f \$(BUILDDIR)*.obj \$(BUILDDIR)*.exe ".
+                   "\$(BUILDDIR)*.res.o \$(BUILDDIR)*.map ".
+                   "\$(BUILDDIR)*.exe.manifest")."\n";
+    select STDOUT; close OUT;
+}
+
 if (defined $makefiles{'cygwin'}) {
     $dirpfx = &dirpfx($makefiles{'cygwin'}, "/");
 
-    ##-- CygWin makefile
+    ##-- MinGW/CygWin makefile (called 'cygwin' for historical reasons)
     open OUT, ">$makefiles{'cygwin'}"; select OUT;
     print
-    "# Makefile for $project_name under cygwin.\n".
+    "# Makefile for $project_name under MinGW, Cygwin, or Winelib.\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;
+    ($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
     print $_;
     print
     "\n".
     "# You can define this path to point at your tools if you need to\n".
     "# TOOLPATH = c:\\cygwin\\bin\\ # or similar, if you're running Windows\n".
     "# TOOLPATH = /pkg/mingw32msvc/i386-mingw32msvc/bin/\n".
+    "# TOOLPATH = i686-w64-mingw32-\n".
     "CC = \$(TOOLPATH)gcc\n".
     "RC = \$(TOOLPATH)windres\n".
     "# Uncomment the following two lines to compile under Winelib\n".
@@ -390,15 +586,15 @@ if (defined $makefiles{'cygwin'}) {
     "# You may also need to tell windres where to find include files:\n".
     "# RCINC = --include-dir c:\\cygwin\\include\\\n".
     "\n".
-    &splitline("CFLAGS = -mno-cygwin -Wall -O2 -D_WINDOWS -DDEBUG -DWIN32S_COMPAT".
-      " -D_NO_OLDNAMES -DNO_MULTIMON " .
+    &splitline("CFLAGS = -Wall -O2 -D_WINDOWS -DDEBUG -DWIN32S_COMPAT".
+      " -D_NO_OLDNAMES " .
               (join " ", map {"-I$dirpfx$_"} @srcdirs)) .
               "\n".
-    "LDFLAGS = -mno-cygwin -s\n".
-    &splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1".
-      " --define WINVER=0x0400")."\n".
+    "LDFLAGS = -s\n".
+    &splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1 ".
+      "--define WINVER=0x0400 ".(join " ", map {"-I$dirpfx$_"} @srcdirs))."\n".
     "\n".
-    $makefile_extra{'cygwin'}->{'vars'} .
+    &def($makefile_extra{'cygwin'}->{'vars'}) .
     "\n".
     ".SUFFIXES:\n".
     "\n";
@@ -415,19 +611,24 @@ if (defined $makefiles{'cygwin'}) {
                        $objstr . " $libstr", 69), "\n\n";
     }
     foreach $d (&deps("X.o", "X.res.o", $dirpfx, "/", "cygwin")) {
-      print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
-        "\n";
+      if ($forceobj{$d->{obj_orig}}) {
+        printf ("%s: FORCE\n", $d->{obj});
+      } else {
+        print &splitline(sprintf("%s: %s", $d->{obj},
+                         join " ", @{$d->{deps}})), "\n";
+      }
       if ($d->{obj} =~ /\.res\.o$/) {
-         print "\t\$(RC) \$(RCFL) \$(RCFLAGS) ".$d->{deps}->[0]." ".$d->{obj}."\n\n";
+         print "\t\$(RC) \$(RCFL) \$(RCFLAGS) ".$d->{deps}->[0]." -o ".$d->{obj}."\n\n";
       } else {
-         print "\t\$(CC) \$(COMPAT) \$(XFLAGS) \$(CFLAGS) -c ".$d->{deps}->[0]."\n\n";
+         print "\t\$(CC) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) -c ".$d->{deps}->[0]."\n\n";
       }
     }
     print "\n";
-    print $makefile_extra{'cygwin'}->{'end'};
+    print &def($makefile_extra{'cygwin'}->{'end'});
     print "\nclean:\n".
-    "\trm -f *.o *.exe *.res.o *.map\n".
-    "\n";
+    "\trm -f *.o *.exe *.res.o *.so *.map\n".
+    "\n".
+    "FORCE:\n";
     select STDOUT; close OUT;
 
 }
@@ -454,7 +655,7 @@ if (defined $makefiles{'borland'}) {
     "#\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";
     # bcc32 command line option is -D not /D
-    ($_ = $help) =~ s/=\/D/=-D/gs;
+    ($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
     print $_;
     print
     "\n".
@@ -463,29 +664,31 @@ if (defined $makefiles{'borland'}) {
     "MAKEFILE = Makefile.bor\n".
     "\n".
     "# C compilation flags\n".
-    "CFLAGS = -D_WINDOWS -DWINVER=0x0401\n".
+    "CFLAGS = -D_WINDOWS -DWINVER=0x0500\n".
+    "# Resource compilation flags\n".
+    "RCFLAGS = -DNO_WINRESRC_H -DWIN32 -D_WIN32 -DWINVER=0x0401\n".
     "\n".
     "# Get include directory for resource compiler\n".
     "!if !\$d(BCB)\n".
     "BCB = \$(MAKEDIR)\\..\n".
     "!endif\n".
     "\n".
-    $makefile_extra{'borland'}->{'vars'} .
+    &def($makefile_extra{'borland'}->{'vars'}) .
     "\n".
     ".c.obj:\n".
     &splitline("\tbcc32 -w-aus -w-ccc -w-par -w-pia \$(COMPAT)".
-              " \$(XFLAGS) \$(CFLAGS) ".
+              " \$(CFLAGS) \$(XFLAGS) ".
               (join " ", map {"-I$dirpfx$_"} @srcdirs) .
               " /c \$*.c",69)."\n".
     ".rc.res:\n".
     &splitline("\tbrcc32 \$(RCFL) -i \$(BCB)\\include -r".
-      " -DNO_WINRESRC_H -DWIN32 -D_WIN32 -DWINVER=0x0401 \$*.rc",69)."\n".
+      " \$(RCFLAGS) \$*.rc",69)."\n".
     "\n";
     print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
     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";
@@ -519,11 +722,15 @@ if (defined $makefiles{'borland'}) {
       print "\n";
     }
     foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "borland")) {
-      print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
-        "\n";
+      if ($forceobj{$d->{obj_orig}}) {
+        printf("%s: FORCE\n", $d->{obj});
+      } else {
+        print &splitline(sprintf("%s: %s", $d->{obj},
+                                 join " ", @{$d->{deps}})), "\n";
+      }
     }
     print "\n";
-    print $makefile_extra{'borland'}->{'end'};
+    print &def($makefile_extra{'borland'}->{'end'});
     print "\nclean:\n".
     "\t-del *.obj\n".
     "\t-del *.exe\n".
@@ -534,7 +741,10 @@ if (defined $makefiles{'borland'}) {
     "\t-del *.pdb\n".
     "\t-del *.rsp\n".
     "\t-del *.tds\n".
-    "\t-del *.\$\$\$\$\$\$\n";
+    "\t-del *.\$\$\$\$\$\$\n".
+    "\n".
+    "FORCE:\n".
+    "\t-rem dummy command\n";
     select STDOUT; close OUT;
 }
 
@@ -557,76 +767,90 @@ if (defined $makefiles{'vc'}) {
       "# C compilation flags\n".
       "CFLAGS = /nologo /W3 /O1 " .
       (join " ", map {"-I$dirpfx$_"} @srcdirs) .
-      " /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401\n".
-      "LFLAGS = /incremental:no /fixed\n".
+      " /D_WINDOWS /D_WIN32_WINDOWS=0x500 /DWINVER=0x500 /D_CRT_SECURE_NO_WARNINGS\n".
+      "LFLAGS = /incremental:no /dynamicbase /nxcompat\n".
+      "RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs).
+      " -DWIN32 -D_WIN32 -DWINVER=0x0400\n".
       "\n".
-      $makefile_extra{'vc'}->{'vars'} .
+      &def($makefile_extra{'vc'}->{'vars'}) .
       "\n".
       "\n";
-    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
+    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, "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:C")) {
-       ($prog, $type) = split ",", $p;
-       print $prog, ".rsp: \$(MAKEFILE)\n";
-       $objstr = &objects($p, "X.obj", "X.res", "X.lib");
+       $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";
+        $inlinefilename = "link_$prog";
+        print "\ttype <<$inlinefilename\n";
        @objlist = split " ", $objstr;
        @objlines = ("");
        foreach $i (@objlist) {
-           if (length($objlines[$#objlines] . " $i") > 50) {
+           if (length($objlines[$#objlines] . " $i") > 72) {
                push @objlines, "";
            }
            $objlines[$#objlines] .= " $i";
        }
-       $subsys = ($type eq "G") ? "windows" : "console";
-       print "\techo /nologo /subsystem:$subsys > $prog.rsp\n";
        for ($i=0; $i<=$#objlines; $i++) {
-           print "\techo$objlines[$i] >> $prog.rsp\n";
+           print "$objlines[$i]\n";
        }
-       print "\n";
+       print "<<\n";
+       print "\tlink \$(LFLAGS) \$(XLFLAGS) -out:\$(BUILDDIR)$prog.exe -map:\$(BUILDDIR)$prog.map -nologo -subsystem:$subsys\$(SUBSYSVER) \@$inlinefilename\n\n";
     }
-    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "vc")) {
-       print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
-         "\n";
-        if ($d->{obj} =~ /.obj$/) {
-           print "\tcl \$(COMPAT) \$(XFLAGS) \$(CFLAGS) /c ".$d->{deps}->[0],"\n\n";
-       } else {
-           print "\trc \$(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 ".$d->{deps}->[0],"\n\n";
+    foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", $dirpfx, "\\", "vc")) {
+        $extradeps = $forceobj{$d->{obj_orig}} ? ["*.c","*.h","*.rc"] : [];
+        print &splitline(sprintf("%s: %s", $d->{obj},
+                                 join " ", @$extradeps, @{$d->{deps}})), "\n";
+        if ($d->{obj} =~ /.res$/) {
+           print "\trc /Fo@{[$d->{obj}]} \$(RCFL) -r \$(RCFLAGS) ".$d->{deps}->[0],"\n\n";
        }
     }
     print "\n";
-    print $makefile_extra{'vc'}->{'end'};
+    foreach $real_srcdir ("", @srcdirs) {
+        $srcdir = $real_srcdir;
+        if ($srcdir ne "") {
+            $srcdir =~ s!/!\\!g;
+            $srcdir = $dirpfx . $srcdir;
+            $srcdir =~ s!\\\.\\!\\!;
+            $srcdir = "{$srcdir}";
+        }
+        # The double colon at the end of the line makes this a
+        # 'batch-mode inference rule', which means that nmake will
+        # aggregate multiple invocations of the rule and issue just
+        # one cl command with multiple source-file arguments. That
+        # noticeably speeds up builds, since starting up the cl
+        # process is a noticeable overhead and now has to be done far
+        # fewer times.
+        print "${srcdir}.c.obj::\n\tcl /Fo\$(BUILDDIR) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) /c \$<\n\n";
+    }
+    print &def($makefile_extra{'vc'}->{'end'});
     print "\nclean: tidy\n".
-      "\t-del *.exe\n\n".
+      "\t-del \$(BUILDDIR)*.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";
+      "\t-del \$(BUILDDIR)*.obj\n".
+      "\t-del \$(BUILDDIR)*.res\n".
+      "\t-del \$(BUILDDIR)*.pch\n".
+      "\t-del \$(BUILDDIR)*.aps\n".
+      "\t-del \$(BUILDDIR)*.ilk\n".
+      "\t-del \$(BUILDDIR)*.pdb\n".
+      "\t-del \$(BUILDDIR)*.rsp\n".
+      "\t-del \$(BUILDDIR)*.dsp\n".
+      "\t-del \$(BUILDDIR)*.dsw\n".
+      "\t-del \$(BUILDDIR)*.ncb\n".
+      "\t-del \$(BUILDDIR)*.opt\n".
+      "\t-del \$(BUILDDIR)*.plg\n".
+      "\t-del \$(BUILDDIR)*.map\n".
+      "\t-del \$(BUILDDIR)*.idb\n".
+      "\t-del \$(BUILDDIR)debug.log\n";
     select STDOUT; close OUT;
 }
 
 if (defined $makefiles{'vcproj'}) {
     $dirpfx = &dirpfx($makefiles{'vcproj'}, "\\");
 
-    $orig_dir = cwd;
-
     ##-- MSVC 6 Workspace and projects
     #
     # Note: All files created in this section are written in binary
@@ -646,7 +870,7 @@ if (defined $makefiles{'vcproj'}) {
     # Get names of all Windows projects (GUI and console)
     my @prognames = &prognames("G:C");
     foreach $progname (@prognames) {
-       create_project(\%all_object_deps, $progname);
+      create_vc_project(\%all_object_deps, $progname);
     }
     # Create the workspace file
     open OUT, ">$project_name.dsw"; binmode OUT; select OUT;
@@ -688,7 +912,7 @@ if (defined $makefiles{'vcproj'}) {
     select STDOUT; close OUT;
     chdir $orig_dir;
 
-    sub create_project {
+    sub create_vc_project {
        my ($all_object_deps, $progname) = @_;
        # Construct program's dependency info
        %seen_objects = ();
@@ -886,6 +1110,360 @@ if (defined $makefiles{'vcproj'}) {
     }
 }
 
+if (defined $makefiles{'vstudio10'} || defined $makefiles{'vstudio12'}) {
+
+    ##-- Visual Studio 2010+ Solution and Projects
+
+    if (defined $makefiles{'vstudio10'}) {
+        create_vs_solution('vstudio10', "2010", "11.00", "v100");
+    }
+
+    if (defined $makefiles{'vstudio12'}) {
+        create_vs_solution('vstudio12', "2012", "12.00", "v110");
+    }
+
+    sub create_vs_solution {
+        my ($makefilename, $name, $version, $toolsver) = @_;
+
+        $dirpfx = &dirpfx($makefiles{$makefilename}, "\\");
+
+        @deps = &deps("X.obj", "X.res", $dirpfx, "\\", $makefilename);
+        %all_object_deps = map {$_->{obj} => $_->{deps}} @deps;
+
+        my @prognames = &prognames("G:C");
+
+        # Create the solution file.
+        mkdir $makefiles{$makefilename}
+           if(! -f $makefiles{$makefilename});
+        chdir $makefiles{$makefilename};
+
+        open OUT, ">$project_name.sln"; select OUT;
+
+        print
+            "Microsoft Visual Studio Solution File, Format Version $version\n" .
+            "# Visual Studio $name\n";
+
+        my %projguids = ();
+        foreach $progname (@prognames) {
+            ($windows_project, $type) = split ",", $progname;
+
+            $projguids{$windows_project} = $guid =
+                &invent_guid("project:$progname");
+        
+            print
+                "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"$windows_project\", \"$windows_project\\$windows_project.vcxproj\", \"{$guid}\"\n" .
+                "EndProject\n";
+        }
+
+        print
+            "Global\n" .
+            "    GlobalSection(SolutionConfigurationPlatforms) = preSolution\n" .
+            "        Debug|Win32 = Debug|Win32\n" .
+            "        Release|Win32 = Release|Win32\n" .
+            "    EndGlobalSection\n" .
+            "    GlobalSection(ProjectConfigurationPlatforms) = postSolution\n" ;
+
+        foreach my $projguid (values %projguids) {
+            print
+                "        {$projguid}.Debug|Win32.ActiveCfg = Debug|Win32\n" .
+                "        {$projguid}.Debug|Win32.Build.0 = Debug|Win32\n" .
+                "        {$projguid}.Release|Win32.ActiveCfg = Release|Win32\n" .
+                "        {$projguid}.Release|Win32.Build.0 = Release|Win32\n";
+        }
+
+        print
+            "    EndGlobalSection\n" .
+            "    GlobalSection(SolutionProperties) = preSolution\n" .
+            "        HideSolutionNode = FALSE\n" .
+            "    EndGlobalSection\n" .
+            "EndGlobal\n";
+
+        select STDOUT; close OUT;
+
+        foreach $progname (@prognames) {
+            ($windows_project, $type) = split ",", $progname;
+            create_vs_project(\%all_object_deps, $windows_project, $type, $projguids{$windows_project}, $toolsver);
+        }
+    
+        chdir $orig_dir;
+    }
+
+    sub create_vs_project {
+        my ($all_object_deps, $windows_project, $type, $projguid, $toolsver) = @_;
+
+        # Break down the project's dependency information into the appropriate
+        # groups.
+        %seen_objects = ();
+        %lib_files = ();
+        %source_files = ();
+        %header_files = ();
+        %resource_files = ();
+        %icon_files = ();
+
+        @object_files = split " ", &objects($progname, "X.obj", "X.res", "X.lib");
+        foreach $object_file (@object_files) {
+            next if defined $seen_objects{$object_file};
+            $seen_objects{$object_file} = 1;
+
+            if($object_file =~ /\.lib$/io) {
+                $lib_files{$object_file} = 1;
+                next;
+            }
+
+            $object_deps = $all_object_deps{$object_file};
+            foreach $object_dep (@$object_deps) {
+                if($object_dep eq $object_deps->[0]) {
+                    if($object_dep =~ /\.c$/io) {
+                        $source_files{$object_dep} = 1;
+                    } elsif($object_dep =~ /\.rc$/io) {
+                        $resource_files{$object_dep} = 1;
+                    }
+                } elsif ($object_dep =~ /\.[ch]$/io) {
+                    $header_files{$object_dep} = 1;
+                } elsif ($object_dep =~ /\.ico$/io) {
+                    $icon_files{$object_dep} = 1;
+                }
+            }
+        }
+
+        $libs = join ";", sort keys %lib_files;
+        @source_files = sort keys %source_files;
+        @header_files = sort keys %header_files;
+        @resources = sort keys %resource_files;
+        @icons = sort keys %icon_files;
+        $subsystem = ($type eq "G") ? "Windows" : "Console";
+
+        mkdir $windows_project
+            if(! -d $windows_project);
+        chdir $windows_project;
+        open OUT, ">$windows_project.vcxproj"; select OUT;
+        open FILTERS, ">$windows_project.vcxproj.filters";
+
+        # The bulk of the project file is just boilerplate stuff, so we
+        # can mostly just dump it out here. Note, buried in the ClCompile
+        # item definition, that we use a debug information format of
+        # ProgramDatabase, which disables the edit-and-continue support
+        # that breaks most of the project builds.
+        print
+            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" .
+            "<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" .
+            "  <ItemGroup Label=\"ProjectConfigurations\">\n" .
+            "    <ProjectConfiguration Include=\"Debug|Win32\">\n" .
+            "      <Configuration>Debug</Configuration>\n" .
+            "      <Platform>Win32</Platform>\n" .
+            "    </ProjectConfiguration>\n" .
+            "    <ProjectConfiguration Include=\"Release|Win32\">\n" .
+            "      <Configuration>Release</Configuration>\n" .
+            "      <Platform>Win32</Platform>\n" .
+            "    </ProjectConfiguration>\n" .
+            "  </ItemGroup>\n" .
+            "  <PropertyGroup Label=\"Globals\">\n" .
+            "    <SccProjectName />\n" .
+            "    <SccLocalPath />\n" .
+            "    <ProjectGuid>{$projguid}</ProjectGuid>\n" .
+            "  </PropertyGroup>\n" .
+            "  <Import Project=\"\$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n" .
+            "  <PropertyGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n" .
+            "    <ConfigurationType>Application</ConfigurationType>\n" .
+            "    <UseOfMfc>false</UseOfMfc>\n" .
+            "    <CharacterSet>MultiByte</CharacterSet>\n" .
+            "    <PlatformToolset>$toolsver</PlatformToolset>\n" .
+            "  </PropertyGroup>\n" .
+            "  <PropertyGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n" .
+            "    <ConfigurationType>Application</ConfigurationType>\n" .
+            "    <UseOfMfc>false</UseOfMfc>\n" .
+            "    <CharacterSet>MultiByte</CharacterSet>\n" .
+            "    <PlatformToolset>$toolsver</PlatformToolset>\n" .
+            "  </PropertyGroup>\n" .
+            "  <Import Project=\"\$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n" .
+            "  <ImportGroup Label=\"ExtensionTargets\">\n" .
+            "  </ImportGroup>\n" .
+            "  <ImportGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Debug|Win32'\" Label=\"PropertySheets\">\n" .
+            "    <Import Project=\"\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props\" Condition=\"exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n" .
+            "  </ImportGroup>\n" .
+            "  <ImportGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Release|Win32'\" Label=\"PropertySheets\">\n" .
+            "    <Import Project=\"\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props\" Condition=\"exists('\$(UserRootDir)\\Microsoft.Cpp.\$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n" .
+            "  </ImportGroup>\n" .
+            "  <PropertyGroup Label=\"UserMacros\" />\n" .
+            "  <PropertyGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Release|Win32'\">\n" .
+            "    <OutDir>.\\Release\\</OutDir>\n" .
+            "    <IntDir>.\\Release\\</IntDir>\n" .
+            "    <LinkIncremental>false</LinkIncremental>\n" .
+            "  </PropertyGroup>\n" .
+            "  <PropertyGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Debug|Win32'\">\n" .
+            "    <OutDir>.\\Debug\\</OutDir>\n" .
+            "    <IntDir>.\\Debug\\</IntDir>\n" .
+            "    <LinkIncremental>true</LinkIncremental>\n" .
+            "  </PropertyGroup>\n" .
+            "  <ItemDefinitionGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Release|Win32'\">\n" .
+            "    <ClCompile>\n" .
+            "      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n" .
+            "      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n" .
+            "      <StringPooling>true</StringPooling>\n" .
+            "      <FunctionLevelLinking>true</FunctionLevelLinking>\n" .
+            "      <Optimization>MaxSpeed</Optimization>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <WarningLevel>Level3</WarningLevel>\n" .
+            "      <AdditionalIncludeDirectories>" . (join ";", map {"..\\..\\$dirpfx$_"} @srcdirs) . ";%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" .
+            "      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;POSIX;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" .
+            "      <AssemblerListingLocation>.\\Release\\</AssemblerListingLocation>\n" .
+            "      <PrecompiledHeaderOutputFile>.\\Release\\$windows_project.pch</PrecompiledHeaderOutputFile>\n" .
+            "      <ObjectFileName>.\\Release\\</ObjectFileName>\n" .
+            "      <ProgramDataBaseFileName>.\\Release\\</ProgramDataBaseFileName>\n" .
+            "    </ClCompile>\n" .
+            "    <Midl>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" .
+            "      <TypeLibraryName>.\\Release\\$windows_project.tlb</TypeLibraryName>\n" .
+            "      <MkTypLibCompatible>true</MkTypLibCompatible>\n" .
+            "      <TargetEnvironment>Win32</TargetEnvironment>\n" .
+            "    </Midl>\n" .
+            "    <ResourceCompile>\n" .
+            "      <Culture>0x0809</Culture>\n" .
+            "      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" .
+            "    </ResourceCompile>\n" .
+            "    <Bscmake>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <OutputFile>.\\Release\\$windows_project.bsc</OutputFile>\n" .
+            "    </Bscmake>\n" .
+            "    <Link>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <SubSystem>$subsystem</SubSystem>\n" .
+            "      <OutputFile>.\\Release\\$windows_project.exe</OutputFile>\n" .
+            "      <AdditionalDependencies>$libs;%(AdditionalDependencies)</AdditionalDependencies>\n" .
+            "    </Link>\n" .
+            "  </ItemDefinitionGroup>\n" .
+            "  <ItemDefinitionGroup Condition=\"'\$(Configuration)|\$(Platform)'=='Debug|Win32'\">\n" .
+            "    <ClCompile>\n" .
+            "      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n" .
+            "      <InlineFunctionExpansion>Default</InlineFunctionExpansion>\n" .
+            "      <FunctionLevelLinking>false</FunctionLevelLinking>\n" .
+            "      <Optimization>Disabled</Optimization>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <WarningLevel>Level3</WarningLevel>\n" .
+            "      <MinimalRebuild>true</MinimalRebuild>\n" .
+            "      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n" .
+            "      <AdditionalIncludeDirectories>" . (join ";", map {"..\\..\\$dirpfx$_"} @srcdirs) . ";%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" .
+            "      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;POSIX;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" .
+            "      <AssemblerListingLocation>.\\Debug\\</AssemblerListingLocation>\n" .
+            "      <PrecompiledHeaderOutputFile>.\\Debug\\$windows_project.pch</PrecompiledHeaderOutputFile>\n" .
+            "      <ObjectFileName>.\\Debug\\</ObjectFileName>\n" .
+            "      <ProgramDataBaseFileName>.\\Debug\\</ProgramDataBaseFileName>\n" .
+            "      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n" .
+            "    </ClCompile>\n" .
+            "    <Midl>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" .
+            "      <TypeLibraryName>.\\Debug\\$windows_project.tlb</TypeLibraryName>\n" .
+            "      <MkTypLibCompatible>true</MkTypLibCompatible>\n" .
+            "      <TargetEnvironment>Win32</TargetEnvironment>\n" .
+            "    </Midl>\n" .
+            "    <ResourceCompile>\n" .
+            "      <Culture>0x0809</Culture>\n" .
+            "      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" .
+            "    </ResourceCompile>\n" .
+            "    <Bscmake>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <OutputFile>.\\Debug\\$windows_project.bsc</OutputFile>\n" .
+            "    </Bscmake>\n" .
+            "    <Link>\n" .
+            "      <SuppressStartupBanner>true</SuppressStartupBanner>\n" .
+            "      <GenerateDebugInformation>true</GenerateDebugInformation>\n" .
+            "      <SubSystem>$subsystem</SubSystem>\n" .
+            "      <OutputFile>\$(TargetPath)</OutputFile>\n" .
+            "      <AdditionalDependencies>$libs;%(AdditionalDependencies)</AdditionalDependencies>\n" .
+            "    </Link>\n" .
+            "  </ItemDefinitionGroup>\n";
+
+        # The VC++ projects don't have physical structure to them, instead
+        # the files are organized by logical "filters" that are stored in
+        # a separate file, so different users can organize things differently.
+        # The filters file contains a copy of the ItemGroup elements from
+        # the main project file that list the included items, but tack
+        # on a filter name where needed.
+        print FILTERS
+            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" .
+            "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n";
+
+        print "  <ItemGroup>\n";
+        print FILTERS "  <ItemGroup>\n";
+        foreach $icon_file (@icons) {
+            $icon_file =~ s/..\\windows\\//;
+            print "    <CustomBuild Include=\"..\\..\\$icon_file\" />\n";
+            print FILTERS
+                "    <CustomBuild Include=\"..\\..\\$icon_file\">\n" .
+                "      <Filter>Resource Files</Filter>\n" .
+                "    </CustomBuild>\n";
+        }
+        print FILTERS "  </ItemGroup>\n";
+        print "  </ItemGroup>\n";
+
+        print "  <ItemGroup>\n";
+        print FILTERS "  <ItemGroup>\n";
+        foreach $resource_file (@resources) {
+            $resource_file =~ s/..\\windows\\//;
+            print
+                "    <ResourceCompile Include=\"..\\..\\$resource_file\">\n" .
+                "      <AdditionalIncludeDirectories Condition=\"'\$(Configuration)|\$(Platform)'=='Release|Win32'\">..\\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" .
+                "      <AdditionalIncludeDirectories Condition=\"'\$(Configuration)|\$(Platform)'=='Debug|Win32'\">..\\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n" .
+                "    </ResourceCompile>\n";
+            print FILTERS
+                "    <ResourceCompile Include=\"..\\..\\$resource_file\">\n" .
+                "      <Filter>Resource Files</Filter>\n" .
+                "    </ResourceCompile>\n";
+        }
+        print FILTERS "  </ItemGroup>\n";
+        print "  </ItemGroup>\n";
+
+        print "  <ItemGroup>\n";
+        print FILTERS "  <ItemGroup>\n";
+        foreach $source_file (@source_files) {
+            $source_file =~ s/..\\windows\\//;
+            print "    <ClCompile Include=\"..\\..\\$source_file\" />\n";
+            print FILTERS
+                "    <ClCompile Include=\"..\\..\\$source_file\">\n" .
+                "      <Filter>Source Files</Filter>\n" .
+                "    </ClCompile>";
+        }
+        print FILTERS "  </ItemGroup>\n";
+        print "  </ItemGroup>\n";
+
+        print "  <ItemGroup>\n";
+        print FILTERS "  <ItemGroup>\n";
+        foreach $header_file (@header_files) {
+            $header_file  =~ s/..\\windows\\//;
+            print "    <ClInclude Include=\"..\\..\\$header_file\" />\n";
+            print FILTERS
+                "    <ClInclude Include=\"..\\..\\$header_file\">\n" .
+                "      <Filter>Header Files</Filter>\n" .
+                "    </ClInclude>";
+        }
+        print FILTERS "  </ItemGroup>\n";
+        print "  </ItemGroup>\n";
+
+        print
+            "  <Import Project=\"\$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n" .
+            "</Project>";
+
+        print FILTERS
+            "  <ItemGroup>\n" .
+            "    <Filter Include=\"Source Files\">\n" .
+            "      <UniqueIdentifier>{" . &invent_guid("sources:$windows_project") . "}</UniqueIdentifier>\n" .
+            "    </Filter>\n" .
+            "    <Filter Include=\"Header Files\">\n" .
+            "      <UniqueIdentifier>{" . &invent_guid("headers:$windows_project") . "}</UniqueIdentifier>\n" .
+            "    </Filter>\n" .
+            "    <Filter Include=\"Resource Files\">\n" .
+            "      <UniqueIdentifier>{" . &invent_guid("resources:$windows_project") . "}</UniqueIdentifier>\n" .
+            "    </Filter>\n" .
+            "  </ItemGroup>\n" .
+            "</Project>";
+
+        select STDOUT; close OUT; close FILTERS;
+        chdir "..";
+    }
+}
+
 if (defined $makefiles{'gtk'}) {
     $dirpfx = &dirpfx($makefiles{'gtk'}, "/");
 
@@ -896,192 +1474,261 @@ if (defined $makefiles{'gtk'}) {
     "#\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;
+    ($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
     print $_;
     print
     "\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".
+    "# If necessary set the path to krb5-config here\n".
+    "KRB5CONFIG=krb5-config\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 x11'\n".
+    "# if you want to enforce 2.0. The default is to try 2.0 and fall back\n".
+    "# to 1.2 if it isn't found.\n".
+    "GTK_CONFIG = sh -c 'pkg-config gtk+-3.0 x11 \$\$0 2>/dev/null || pkg-config gtk+-2.0 x11 \$\$0 2>/dev/null || gtk-config \$\$0'\n".
+    "\n".
+    "-include Makefile.local\n".
+    "\n".
+    "unexport CFLAGS # work around a weird issue with krb5-config\n".
     "\n".
     &splitline("CFLAGS = -O2 -Wall -Werror -g " .
               (join " ", map {"-I$dirpfx$_"} @srcdirs) .
-              " `gtk-config --cflags`")."\n".
-    "XLDFLAGS = `gtk-config --libs`\n".
-    "ULDFLAGS =#\n".
-    "INSTALL=install\n",
-    "INSTALL_PROGRAM=\$(INSTALL)\n",
-    "INSTALL_DATA=\$(INSTALL)\n",
-    "prefix=/usr/local\n",
-    "exec_prefix=\$(prefix)\n",
-    "bindir=\$(exec_prefix)/bin\n",
-    "mandir=\$(prefix)/man\n",
-    "man1dir=\$(mandir)/man1\n",
+              " \$(shell \$(GTK_CONFIG) --cflags)").
+                " -D _FILE_OFFSET_BITS=64\n".
+    "XLDFLAGS = \$(LDFLAGS) \$(shell \$(GTK_CONFIG) --libs)\n".
+    "ULDFLAGS = \$(LDFLAGS)\n".
+    "ifeq (,\$(findstring NO_GSSAPI,\$(COMPAT)))\n".
+    "ifeq (,\$(findstring STATIC_GSSAPI,\$(COMPAT)))\n".
+    "XLDFLAGS+= -ldl\n".
+    "ULDFLAGS+= -ldl\n".
+    "else\n".
+    "CFLAGS+= -DNO_LIBDL \$(shell \$(KRB5CONFIG) --cflags gssapi)\n".
+    "XLDFLAGS+= \$(shell \$(KRB5CONFIG) --libs gssapi)\n".
+    "ULDFLAGS+= \$(shell \$(KRB5CONFIG) --libs gssapi)\n".
+    "endif\n".
+    "endif\n".
+    "INSTALL=install\n".
+    "INSTALL_PROGRAM=\$(INSTALL)\n".
+    "INSTALL_DATA=\$(INSTALL)\n".
+    "prefix=/usr/local\n".
+    "exec_prefix=\$(prefix)\n".
+    "bindir=\$(exec_prefix)/bin\n".
+    "mandir=\$(prefix)/man\n".
+    "man1dir=\$(mandir)/man1\n".
     "\n".
-    $makefile_extra{'gtk'}->{'vars'} .
+    &def($makefile_extra{'gtk'}->{'vars'}) .
     "\n".
     ".SUFFIXES:\n".
     "\n".
     "\n";
-    print &splitline("all:" . join "", map { " $_" } &progrealnames("X:U"));
+    print &splitline("all:" . join "", map { " $_" }
+                     &progrealnames("X:XT:U:UT"));
     print "\n\n";
-    foreach $p (&prognames("X:U")) {
+    foreach $p (&prognames("X:XT:U:UT")) {
       ($prog, $type) = split ",", $p;
+      ($ldflags = $type) =~ s/T$//;
       $objstr = &objects($p, "X.o", undef, undef);
       print &splitline($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 . " \$(${ldflags}LDFLAGS) $libstr", 69), "\n\n";
     }
     foreach $d (&deps("X.o", undef, $dirpfx, "/", "gtk")) {
-      print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
-          "\n";
-      print &splitline("\t\$(CC) \$(COMPAT) \$(XFLAGS) \$(CFLAGS) -c $d->{deps}->[0]\n");
+      if ($forceobj{$d->{obj_orig}}) {
+        printf("%s: FORCE\n", $d->{obj});
+      } else {
+        print &splitline(sprintf("%s: %s", $d->{obj},
+                                 join " ", @{$d->{deps}})), "\n";
+      }
+      print &splitline("\t\$(CC) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) -c $d->{deps}->[0]\n");
     }
     print "\n";
-    print $makefile_extra{'gtk'}->{'end'};
+    print &def($makefile_extra{'gtk'}->{'end'});
     print "\nclean:\n".
-    "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U")) . "\n";
+    "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:XT:U:UT")) . "\n";
+    print "\nFORCE:\n";
     select STDOUT; close OUT;
 }
 
-if (defined $makefiles{'mpw'}) {
-    ##-- MPW Makefile
-    open OUT, ">$makefiles{'mpw'}"; select OUT;
+if (defined $makefiles{'unix'}) {
+    $dirpfx = &dirpfx($makefiles{'unix'}, "/");
+
+    ##-- GTK-free pure-Unix makefile for non-GUI apps only
+    open OUT, ">$makefiles{'unix'}"; select OUT;
     print
-    "# Makefile for $project_name under MPW.\n#\n".
-    "# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
+    "# Makefile for $project_name under Unix.\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";
-    # MPW command line option is -d not /D
-    ($_ = $help) =~ s/=\/D/=-d /gs;
+    # gcc command line option is -D not /D
+    ($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
     print $_;
-    print "\n\n".
-    "ROptions     = `Echo \"{VER}\" | StreamEdit -e \"1,\$ replace /=(\xc5)\xa81\xb0/ 'STR=\xb6\xb6\xb6\xb6\xb6\"' \xa81 '\xb6\xb6\xb6\xb6\xb6\"'\"`".
-    "\n".
-    "C_68K = {C}\n".
-    "C_CFM68K = {C}\n".
-    "C_PPC = {PPCC}\n".
-    "C_Carbon = {PPCC}\n".
-    "\n".
-    "# -w 35 disables \"unused parameter\" warnings\n".
-    "COptions     = -i : -i :: -i ::charset -w 35 -w err -proto strict -ansi on \xb6\n".
-    "         -notOnce\n".
-    "COptions_68K = {COptions} -model far -opt time\n".
-    "# Enabling \"-opt space\" for CFM-68K gives me undefined references to\n".
-    "# _\$LDIVT and _\$LMODT.\n".
-    "COptions_CFM68K = {COptions} -model cfmSeg -opt time\n".
-    "COptions_PPC = {COptions} -opt size -traceback\n".
-    "COptions_Carbon = {COptions} -opt size -traceback -d TARGET_API_MAC_CARBON\n".
+    print
     "\n".
-    "Link_68K = ILink\n".
-    "Link_CFM68K = ILink\n".
-    "Link_PPC = PPCLink\n".
-    "Link_Carbon = PPCLink\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".
     "\n".
-    "LinkOptions = -c 'pTTY'\n".
-    "LinkOptions_68K = {LinkOptions} -br 68k -model far -compact\n".
-    "LinkOptions_CFM68K = {LinkOptions} -br 020 -model cfmseg -compact\n".
-    "LinkOptions_PPC = {LinkOptions}\n".
-    "LinkOptions_Carbon = -m __appstart -w {LinkOptions}\n".
+    "-include Makefile.local\n".
     "\n".
-    "Libs_68K =        \"{CLibraries}StdCLib.far.o\" \xb6\n".
-    "          \"{Libraries}MacRuntime.o\" \xb6\n".
-    "          \"{Libraries}MathLib.far.o\" \xb6\n".
-    "          \"{Libraries}IntEnv.far.o\" \xb6\n".
-    "          \"{Libraries}Interface.o\" \xb6\n".
-    "          \"{Libraries}Navigation.far.o\" \xb6\n".
-    "          \"{Libraries}OpenTransport.o\" \xb6\n".
-    "          \"{Libraries}OpenTransportApp.o\" \xb6\n".
-    "          \"{Libraries}OpenTptInet.o\" \xb6\n".
-    "          \"{Libraries}UnicodeConverterLib.far.o\"\n".
+    "unexport CFLAGS # work around a weird issue with krb5-config\n".
     "\n".
-    "Libs_CFM =        \"{SharedLibraries}InterfaceLib\" \xb6\n".
-    "          \"{SharedLibraries}StdCLib\" \xb6\n".
-    "          \"{SharedLibraries}AppearanceLib\" \xb6\n".
-    "                  -weaklib AppearanceLib \xb6\n".
-    "          \"{SharedLibraries}NavigationLib\" \xb6\n".
-    "                  -weaklib NavigationLib \xb6\n".
-    "          \"{SharedLibraries}TextCommon\" \xb6\n".
-    "                  -weaklib TextCommon \xb6\n".
-    "          \"{SharedLibraries}UnicodeConverter\" \xb6\n".
-    "                  -weaklib UnicodeConverter\n".
+    &splitline("CFLAGS = -O2 -Wall -Werror -g " .
+              (join " ", map {"-I$dirpfx$_"} @srcdirs)).
+                " -D _FILE_OFFSET_BITS=64\n".
+    "ULDFLAGS = \$(LDFLAGS)\n".
+    "INSTALL=install\n".
+    "INSTALL_PROGRAM=\$(INSTALL)\n".
+    "INSTALL_DATA=\$(INSTALL)\n".
+    "prefix=/usr/local\n".
+    "exec_prefix=\$(prefix)\n".
+    "bindir=\$(exec_prefix)/bin\n".
+    "mandir=\$(prefix)/man\n".
+    "man1dir=\$(mandir)/man1\n".
     "\n".
-    "Libs_CFM68K =     {Libs_CFM} \xb6\n".
-    "          \"{CFM68KLibraries}NuMacRuntime.o\"\n".
+    &def($makefile_extra{'unix'}->{'vars'}) .
     "\n".
-    "Libs_PPC =        {Libs_CFM} \xb6\n".
-    "          \"{SharedLibraries}ControlsLib\" \xb6\n".
-    "                  -weaklib ControlsLib \xb6\n".
-    "          \"{SharedLibraries}WindowsLib\" \xb6\n".
-    "                  -weaklib WindowsLib \xb6\n".
-    "          \"{SharedLibraries}OpenTransportLib\" \xb6\n".
-    "                  -weaklib OTClientLib \xb6\n".
-    "                  -weaklib OTClientUtilLib \xb6\n".
-    "          \"{SharedLibraries}OpenTptInternetLib\" \xb6\n".
-    "                  -weaklib OTInetClientLib \xb6\n".
-    "          \"{PPCLibraries}StdCRuntime.o\" \xb6\n".
-    "          \"{PPCLibraries}PPCCRuntime.o\" \xb6\n".
-    "          \"{PPCLibraries}CarbonAccessors.o\" \xb6\n".
-    "          \"{PPCLibraries}OpenTransportAppPPC.o\" \xb6\n".
-    "          \"{PPCLibraries}OpenTptInetPPC.o\"\n".
+    ".SUFFIXES:\n".
     "\n".
-    "Libs_Carbon =     \"{PPCLibraries}CarbonStdCLib.o\" \xb6\n".
-    "          \"{PPCLibraries}StdCRuntime.o\" \xb6\n".
-    "          \"{PPCLibraries}PPCCRuntime.o\" \xb6\n".
-    "          \"{SharedLibraries}CarbonLib\" \xb6\n".
-    "          \"{SharedLibraries}StdCLib\"\n".
     "\n";
-    print &splitline("all \xc4 " . join(" ", &progrealnames("M")), undef, "\xb6");
+    print &splitline("all:" . join "", map { " $_" } &progrealnames("U:UT"));
     print "\n\n";
-    foreach $p (&prognames("M")) {
+    foreach $p (&prognames("U:UT")) {
       ($prog, $type) = split ",", $p;
+      $objstr = &objects($p, "X.o", undef, undef);
+      print &splitline($prog . ": " . $objstr), "\n";
+      $libstr = &objects($p, undef, undef, "-lX");
+      print &splitline("\t\$(CC) -o \$@ " .
+                       $objstr . " \$(${type}LDFLAGS) $libstr", 69), "\n\n";
+    }
+    foreach $d (&deps("X.o", undef, $dirpfx, "/", "unix")) {
+      if ($forceobj{$d->{obj_orig}}) {
+        printf("%s: FORCE\n", $d->{obj});
+      } else {
+        print &splitline(sprintf("%s: %s", $d->{obj},
+                                 join " ", @{$d->{deps}})), "\n";
+      }
+      print &splitline("\t\$(CC) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) -c $d->{deps}->[0]\n");
+    }
+    print "\n";
+    print &def($makefile_extra{'unix'}->{'end'});
+    print "\nclean:\n".
+    "\trm -f *.o". (join "", map { " $_" } &progrealnames("U:UT")) . "\n";
+    print "\nFORCE:\n";
+    select STDOUT; close OUT;
+}
 
-      print &splitline("$prog \xc4 $prog.68k $prog.ppc $prog.carbon",
-                  undef, "\xb6"), "\n\n";
+if (defined $makefiles{'am'}) {
+    die "Makefile.am in a subdirectory is not supported\n"
+        if &dirpfx($makefiles{'am'}, "/") ne "";
 
-      $rsrc = &objects($p, "", "X.rsrc", undef);
+    ##-- 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";
 
-      foreach $arch (qw(68K CFM68K PPC Carbon)) {
-          $objstr = &objects($p, "X.\L$arch\E.o", "", undef);
-          print &splitline("$prog.\L$arch\E \xc4 $objstr $rsrc", undef, "\xb6");
-          print "\n";
-          print &splitline("\tDuplicate -y $rsrc {Targ}", 69, "\xb6"), "\n";
-          print &splitline("\t{Link_$arch} -o {Targ} -fragname $prog " .
-                      "{LinkOptions_$arch} " .
-                      $objstr . " {Libs_$arch}", 69, "\xb6"), "\n";
-          print &splitline("\tSetFile -a BMi {Targ}", 69, "\xb6"), "\n\n";
-      }
+    # 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.
+    @sources = ("allsources", "=",
+                sort grep {$_ ne "empty.h"} keys %allsourcefiles);
+    print &splitline(join " ", @sources), "\n\n";
+
+    @cliprogs = ("bin_PROGRAMS", "=");
+    foreach $p (&prognames("U")) {
+      ($prog, $type) = split ",", $p;
+      push @cliprogs, $prog;
+    }
+    @allprogs = @cliprogs;
+    foreach $p (&prognames("X")) {
+      ($prog, $type) = split ",", $p;
+      push @allprogs, $prog;
+    }
+    print "if HAVE_GTK\n";
+    print &splitline(join " ", @allprogs), "\n";
+    print "else\n";
+    print &splitline(join " ", @cliprogs), "\n";
+    print "endif\n\n";
 
+    @noinstcliprogs = ("noinst_PROGRAMS", "=");
+    foreach $p (&prognames("UT")) {
+      ($prog, $type) = split ",", $p;
+      push @noinstcliprogs, $prog;
     }
-    foreach $d (&deps("", "X.rsrc", "::", ":", "mpw")) {
-      next unless $d->{obj};
-      print &splitline(sprintf("%s \xc4 %s", $d->{obj}, join " ", @{$d->{deps}}),
-                  undef, "\xb6"), "\n";
-      print "\tRez ", $d->{deps}->[0], " -o {Targ} {ROptions}\n\n";
+    @noinstallprogs = @noinstcliprogs;
+    foreach $p (&prognames("XT")) {
+      ($prog, $type) = split ",", $p;
+      push @noinstallprogs, $prog;
     }
-    foreach $arch (qw(68K CFM68K)) {
-        foreach $d (&deps("X.\L$arch\E.o", "", "::", ":", "mpw")) {
-        next unless $d->{obj};
-       print &splitline(sprintf("%s \xc4 %s", $d->{obj},
-                                join " ", @{$d->{deps}}),
-                        undef, "\xb6"), "\n";
-        print "\t{C_$arch} ", $d->{deps}->[0],
-              " -o {Targ} {COptions_$arch}\n\n";
-         }
+    print "if HAVE_GTK\n";
+    print &splitline(join " ", @noinstallprogs), "\n";
+    print "else\n";
+    print &splitline(join " ", @noinstcliprogs), "\n";
+    print "endif\n\n";
+
+    %objtosrc = ();
+    foreach $d (&deps("X", undef, "", "/", "am")) {
+      $objtosrc{$d->{obj}} = $d->{deps}->[0];
     }
-    foreach $arch (qw(PPC Carbon)) {
-        foreach $d (&deps("X.\L$arch\E.o", "", "::", ":", "mpw")) {
-        next unless $d->{obj};
-       print &splitline(sprintf("%s \xc4 %s", $d->{obj},
-                                join " ", @{$d->{deps}}),
-                        undef, "\xb6"), "\n";
-        # The odd stuff here seems to stop afpd getting confused.
-        print "\techo -n > {Targ}\n";
-        print "\tsetfile -t XCOF {Targ}\n";
-        print "\t{C_$arch} ", $d->{deps}->[0],
-              " -o {Targ} {COptions_$arch}\n\n";
-         }
+
+    print &splitline(join " ", "AM_CPPFLAGS", "=",
+                     map {"-I\$(srcdir)/$_"} @srcdirs), "\n";
+
+    @amcflags = ("\$(COMPAT)", "\$(XFLAGS)", "\$(WARNINGOPTS)");
+    print "if HAVE_GTK\n";
+    print &splitline(join " ", "AM_CFLAGS", "=",
+                     "\$(GTK_CFLAGS)", @amcflags), "\n";
+    print "else\n";
+    print &splitline(join " ", "AM_CFLAGS", "=", @amcflags), "\n";
+    print "endif\n\n";
+
+    %amspeciallibs = ();
+    foreach $obj (sort { $a cmp $b } keys %{$cflags{'am'}}) {
+      my $flags = $cflags{'am'}->{$obj};
+      $flags = "" if $flags !~ s/^C//;
+      print "lib${obj}_a_SOURCES = ", $objtosrc{$obj}, "\n";
+      print &splitline(join " ", "lib${obj}_a_CFLAGS", "=", @amcflags,
+                       $flags), "\n";
+      $amspeciallibs{$obj} = "lib${obj}.a";
     }
+    print &splitline(join " ", "noinst_LIBRARIES", "=",
+                     sort { $a cmp $b } values %amspeciallibs), "\n\n";
+
+    foreach $p (&prognames("X:XT:U:UT")) {
+      ($prog, $type) = split ",", $p;
+      print "if HAVE_GTK\n" if $type eq "X" || $type eq "XT";
+      @progsources = ("${prog}_SOURCES", "=");
+      %sourcefiles = ();
+      @ldadd = ();
+      $objstr = &objects($p, "X", undef, undef);
+      foreach $obj (split / /,$objstr) {
+        if ($amspeciallibs{$obj}) {
+          push @ldadd, $amspeciallibs{$obj};
+        } else {
+          $sourcefiles{$objtosrc{$obj}} = 1;
+        }
+      }
+      push @progsources, sort { $a cmp $b } keys %sourcefiles;
+      print &splitline(join " ", @progsources), "\n";
+      if ($type eq "X" || $type eq "XT") {
+        push @ldadd, "\$(GTK_LIBS)";
+      }
+      if (@ldadd) {
+        print &splitline(join " ", "${prog}_LDADD", "=", @ldadd), "\n";
+      }
+      print "endif\n" if $type eq "X" || $type eq "XT";
+      print "\n";
+    }
+    print &def($makefile_extra{'am'}->{'end'});
     select STDOUT; close OUT;
 }
 
@@ -1095,7 +1742,7 @@ if (defined $makefiles{'lcc'}) {
     "#\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";
     # lcc command line option is -D not /D
-    ($_ = $help) =~ s/=\/D/=-D/gs;
+    ($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
     print $_;
     print
     "\n".
@@ -1107,10 +1754,12 @@ if (defined $makefiles{'lcc'}) {
     "CFLAGS = -D_WINDOWS " .
       (join " ", map {"-I$dirpfx$_"} @srcdirs) .
       "\n".
+    "# Resource compilation flags\n".
+    "RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs)."\n".
     "\n".
     "# Get include directory for resource compiler\n".
     "\n".
-    $makefile_extra{'lcc'}->{'vars'} .
+    &def($makefile_extra{'lcc'}->{'vars'}) .
     "\n";
     print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
     print "\n\n";
@@ -1118,7 +1767,7 @@ if (defined $makefiles{'lcc'}) {
       ($prog, $type) = split ",", $p;
       $objstr = &objects($p, "X.obj", "X.res", undef);
       print &splitline("$prog.exe: " . $objstr ), "\n";
-      $subsystemtype = undef;
+      $subsystemtype = '';
       if ($type eq "G") { $subsystemtype = "-subsystem  windows"; }
       my $libss = "shell32.lib wsock32.lib ws2_32.lib winspool.lib winmm.lib imm32.lib";
       print &splitline("\tlcclnk $subsystemtype -o $prog.exe $objstr $libss");
@@ -1126,21 +1775,28 @@ if (defined $makefiles{'lcc'}) {
     }
 
     foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "lcc")) {
-      print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
-        "\n";
+      if ($forceobj{$d->{obj_orig}}) {
+         printf("%s: FORCE\n", $d->{obj});
+      } else {
+         print &splitline(sprintf("%s: %s", $d->{obj},
+                          join " ", @{$d->{deps}})), "\n";
+      }
       if ($d->{obj} =~ /\.obj$/) {
          print &splitline("\tlcc -O -p6 \$(COMPAT)".
-                          " \$(XFLAGS) \$(CFLAGS) ".$d->{deps}->[0],69)."\n";
+                          " \$(CFLAGS) \$(XFLAGS) ".$d->{deps}->[0],69)."\n";
       } else {
-         print &splitline("\tlrc \$(RCFL) -r ".$d->{deps}->[0],69)."\n";
+          print &splitline("\tlrc \$(RCFL) -r \$(RCFLAGS) ".
+                           $d->{deps}->[0],69)."\n";
       }
     }
     print "\n";
-    print $makefile_extra{'lcc'}->{'end'};
+    print &def($makefile_extra{'lcc'}->{'end'});
     print "\nclean:\n".
     "\t-del *.obj\n".
     "\t-del *.exe\n".
-    "\t-del *.res\n";
+    "\t-del *.res\n".
+    "\n".
+    "FORCE:\n";
 
     select STDOUT; close OUT;
 }
@@ -1155,7 +1811,7 @@ if (defined $makefiles{'osx'}) {
     "#\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;
+    ($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
     print $_;
     print
     "CC = \$(TOOLPATH)gcc\n".
@@ -1165,9 +1821,9 @@ if (defined $makefiles{'osx'}) {
     "MLDFLAGS = -framework Cocoa\n".
     "ULDFLAGS =\n".
     "\n" .
-    $makefile_extra{'osx'}->{'vars'} .
+    &def($makefile_extra{'osx'}->{'vars'}) .
     "\n" .
-    &splitline("all:" . join "", map { " $_" } &progrealnames("MX:U")) .
+    &splitline("all:" . join "", map { " $_" } &progrealnames("MX:U:UT")) .
     "\n";
     foreach $p (&prognames("MX")) {
       ($prog, $type) = split ",", $p;
@@ -1192,30 +1848,313 @@ if (defined $makefiles{'osx'}) {
       print &splitline("${prog}.app/Contents/MacOS/$prog: ".
                       "${prog}.app/Contents/MacOS " . $objstr), "\n";
       $libstr = &objects($p, undef, undef, "-lX");
-      print &splitline("\t\$(CC)" . $mw . " \$(MLDFLAGS) -o \$@ " .
+      print &splitline("\t\$(CC) \$(MLDFLAGS) -o \$@ " .
                        $objstr . " $libstr", 69), "\n\n";
     }
-    foreach $p (&prognames("U")) {
+    foreach $p (&prognames("U:UT")) {
       ($prog, $type) = split ",", $p;
       $objstr = &objects($p, "X.o", undef, undef);
       print &splitline($prog . ": " . $objstr), "\n";
       $libstr = &objects($p, undef, undef, "-lX");
-      print &splitline("\t\$(CC)" . $mw . " \$(ULDFLAGS) -o \$@ " .
+      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";
+    foreach $d (&deps("X.o", undef, $dirpfx, "/", "osx")) {
+      if ($forceobj{$d->{obj_orig}}) {
+         printf("%s: FORCE\n", $d->{obj});
+      } else {
+         print &splitline(sprintf("%s: %s", $d->{obj},
+                                  join " ", @{$d->{deps}})), "\n";
+      }
       $firstdep = $d->{deps}->[0];
       if ($firstdep =~ /\.c$/) {
-         print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) -c \$<\n";
+         print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS) -c \$<\n";
       } elsif ($firstdep =~ /\.m$/) {
-         print "\t\$(CC) -x objective-c \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) -c \$<\n";
+         print "\t\$(CC) -x objective-c \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS) -c \$<\n";
       }
     }
-    print "\n".$makefile_extra{'osx'}->{'end'};
+    print "\n".&def($makefile_extra{'osx'}->{'end'});
     print "\nclean:\n".
-    "\trm -f *.o *.dmg". (join "", map { " $_" } &progrealnames("U")) . "\n";
-    "\trm -rf *.app\n";
+    "\trm -f *.o *.dmg". (join "", map { " $_" } &progrealnames("U:UT")) . "\n".
+    "\trm -rf *.app\n".
+    "\n".
+    "FORCE:\n";
     select STDOUT; close OUT;
 }
+
+if (defined $makefiles{'devcppproj'}) {
+    $dirpfx = &dirpfx($makefiles{'devcppproj'}, "\\");
+    $orig_dir = cwd;
+
+    ##-- Dev-C++ 5 projects
+    #
+    # Note: All files created in this section are written in binary
+    # mode to prevent any posibility of misinterpreted line endings.
+    # I don't know if Dev-C++ is as touchy as MSVC with LF-only line
+    # endings. But however, CRLF line endings are the common way on
+    # Win32 machines where Dev-C++ is running.
+    # Hence, in order for mkfiles.pl to generate CRLF project files
+    # even when run from Unix, I make sure all files are binary and
+    # explicitly write the CRLFs.
+    #
+    # Create directories if necessary
+    mkdir $makefiles{'devcppproj'}
+        if(! -d $makefiles{'devcppproj'});
+    chdir $makefiles{'devcppproj'};
+    @deps = &deps("X.obj", "X.res", $dirpfx, "\\", "devcppproj");
+    %all_object_deps = map {$_->{obj} => $_->{deps}} @deps;
+    # Make dir names FAT/NTFS compatible
+    my @srcdirs = @srcdirs;
+    for ($i=0; $i<@srcdirs; $i++) {
+      $srcdirs[$i] =~ s/\//\\/g;
+      $srcdirs[$i] =~ s/\\$//;
+    }
+    # Create the project files
+    # Get names of all Windows projects (GUI and console)
+    my @prognames = &prognames("G:C");
+    foreach $progname (@prognames) {
+      create_devcpp_project(\%all_object_deps, $progname);
+    }
+
+    chdir $orig_dir;
+
+    sub create_devcpp_project {
+      my ($all_object_deps, $progname) = @_;
+      # Construct program's dependency info (Taken from 'vcproj', seems to work right here, too.)
+      %seen_objects = ();
+      %lib_files = ();
+      %source_files = ();
+      %header_files = ();
+      %resource_files = ();
+      @object_files = split " ", &objects($progname, "X.obj", "X.res", "X.lib");
+      foreach $object_file (@object_files) {
+      next if defined $seen_objects{$object_file};
+      $seen_objects{$object_file} = 1;
+      if($object_file =~ /\.lib$/io) {
+    $lib_files{$object_file} = 1;
+    next;
+      }
+      $object_deps = $all_object_deps{$object_file};
+      foreach $object_dep (@$object_deps) {
+    if($object_dep =~ /\.c$/io) {
+        $source_files{$object_dep} = 1;
+        next;
+    }
+    if($object_dep =~ /\.h$/io) {
+        $header_files{$object_dep} = 1;
+        next;
+    }
+    if($object_dep =~ /\.(rc|ico)$/io) {
+        $resource_files{$object_dep} = 1;
+        next;
+    }
+      }
+      }
+      $libs = join " ", sort keys %lib_files;
+      @source_files = sort keys %source_files;
+      @header_files = sort keys %header_files;
+      @resources = sort keys %resource_files;
+  ($windows_project, $type) = split ",", $progname;
+      mkdir $windows_project
+      if(! -d $windows_project);
+      chdir $windows_project;
+
+  $subsys = ($type eq "G") ? "0" : "1";  # 0 = Win32 GUI, 1 = Win32 Console
+      open OUT, ">$windows_project.dev"; binmode OUT; select OUT;
+      print
+      "# DEV-C++ 5 Project File - $windows_project.dev\r\n".
+      "# ** DO NOT EDIT **\r\n".
+      "\r\n".
+      # No difference between DEBUG and RELEASE here as in 'vcproj', because
+      # Dev-C++ does not support mutiple compilation profiles in one single project.
+      # (At least I can say this for Dev-C++ 5 Beta)
+      "[Project]\r\n".
+      "FileName=$windows_project.dev\r\n".
+      "Name=$windows_project\r\n".
+      "Ver=1\r\n".
+      "IsCpp=1\r\n".
+      "Type=$subsys\r\n".
+      # Multimon is disabled here, as Dev-C++ (Version 5 Beta) does not have multimon.h
+      "Compiler=-W -D__GNUWIN32__ -DWIN32 -DNDEBUG -D_WINDOWS -DNO_MULTIMON -D_MBCS_\@\@_\r\n".
+      "CppCompiler=-W -D__GNUWIN32__ -DWIN32 -DNDEBUG -D_WINDOWS -DNO_MULTIMON -D_MBCS_\@\@_\r\n".
+      "Includes=" . (join ";", map {"..\\..\\$dirpfx$_"} @srcdirs) . "\r\n".
+      "Linker=-ladvapi32 -lcomctl32 -lcomdlg32 -lgdi32 -limm32 -lshell32 -luser32 -lwinmm -lwinspool_\@\@_\r\n".
+      "Libs=\r\n".
+      "UnitCount=" . (@source_files + @header_files + @resources) . "\r\n".
+      "Folders=\"Header Files\",\"Resource Files\",\"Source Files\"\r\n".
+      "ObjFiles=\r\n".
+      "PrivateResource=${windows_project}_private.rc\r\n".
+      "ResourceIncludes=..\\..\\..\\WINDOWS\r\n".
+      "MakeIncludes=\r\n".
+      "Icon=\r\n". # It's ok to leave this blank.
+      "ExeOutput=\r\n".
+      "ObjectOutput=\r\n".
+      "OverrideOutput=0\r\n".
+      "OverrideOutputName=$windows_project.exe\r\n".
+      "HostApplication=\r\n".
+      "CommandLine=\r\n".
+      "UseCustomMakefile=0\r\n".
+      "CustomMakefile=\r\n".
+      "IncludeVersionInfo=0\r\n".
+      "SupportXPThemes=0\r\n".
+      "CompilerSet=0\r\n".
+      "CompilerSettings=0000000000000000000000\r\n".
+      "\r\n";
+      $unit_count = 1;
+      foreach $source_file (@source_files) {
+      print
+        "[Unit$unit_count]\r\n".
+        "FileName=..\\..\\$source_file\r\n".
+        "Folder=Source Files\r\n".
+        "Compile=1\r\n".
+        "CompileCpp=0\r\n".
+        "Link=1\r\n".
+        "Priority=1000\r\n".
+        "OverrideBuildCmd=0\r\n".
+        "BuildCmd=\r\n".
+        "\r\n";
+      $unit_count++;
+  }
+      foreach $header_file (@header_files) {
+      print
+        "[Unit$unit_count]\r\n".
+        "FileName=..\\..\\$header_file\r\n".
+        "Folder=Header Files\r\n".
+        "Compile=1\r\n".
+        "CompileCpp=1\r\n". # Dev-C++ want's to compile all header files with both compilers C and C++. It does not hurt.
+        "Link=1\r\n".
+        "Priority=1000\r\n".
+        "OverrideBuildCmd=0\r\n".
+        "BuildCmd=\r\n".
+        "\r\n";
+      $unit_count++;
+  }
+      foreach $resource_file (@resources) {
+      if ($resource_file =~ /.*\.(ico|cur|bmp|dlg|rc2|rct|bin|rgs|gif|jpg|jpeg|jpe)/io) { # Default filter as in 'vcproj'
+        $Compile = "0";    # Don't compile images and other binary resource files
+        $CompileCpp = "0";
+      } else {
+        $Compile = "1";
+        $CompileCpp = "1"; # Dev-C++ want's to compile all .rc files with both compilers C and C++. It does not hurt.
+      }
+      print
+        "[Unit$unit_count]\r\n".
+        "FileName=..\\..\\$resource_file\r\n".
+        "Folder=Resource Files\r\n".
+        "Compile=$Compile\r\n".
+        "CompileCpp=$CompileCpp\r\n".
+        "Link=0\r\n".
+        "Priority=1000\r\n".
+        "OverrideBuildCmd=0\r\n".
+        "BuildCmd=\r\n".
+        "\r\n";
+      $unit_count++;
+  }
+      #Note: By default, [VersionInfo] is not used.
+      print
+      "[VersionInfo]\r\n".
+      "Major=0\r\n".
+      "Minor=0\r\n".
+      "Release=1\r\n".
+      "Build=1\r\n".
+      "LanguageID=1033\r\n".
+      "CharsetID=1252\r\n".
+      "CompanyName=\r\n".
+      "FileVersion=0.1\r\n".
+      "FileDescription=\r\n".
+      "InternalName=\r\n".
+      "LegalCopyright=\r\n".
+      "LegalTrademarks=\r\n".
+      "OriginalFilename=$windows_project.exe\r\n".
+      "ProductName=$windows_project\r\n".
+      "ProductVersion=0.1\r\n".
+      "AutoIncBuildNr=0\r\n";
+      select STDOUT; close OUT;
+      chdir "..";
+    }
+}
+
+# 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;
+    if ($do_unix == 1) {
+        chdir ($targetdir = "unix")
+            or die "$targetdir: chdir: $!\n";
+    }
+    system "./configure", @confargs;
+    die "mkfiles.pl: configure returned $?\n" if $? > 0;
+}
+
+sub invent_guid($) {
+    my ($name) = @_;
+
+    # Invent a GUID for use in Visual Studio project files. We need
+    # a few of these for every executable file we build.
+    #
+    # In order to avoid having to use the non-core Perl module
+    # Data::GUID, and also arrange for GUIDs to be stable, we generate
+    # our GUIDs by hashing a pile of fixed (but originally randomly
+    # generated) data with the filename for which we need an id.
+    #
+    # Hashing _just_ the filenames would clearly be cheating (it's
+    # quite conceivable that someone might hash the same string for
+    # another reason and so generate a colliding GUID), but hashing a
+    # whole SHA-512 data block of random gibberish as well should make
+    # these GUIDs pseudo-random enough to not collide with anyone
+    # else's.
+
+    my $randdata = pack "N*",
+    0xD4AB035F,0x76998BA0,0x2DCCB0BD,0x6D3FA320,0x53638051,0xFE312F35,
+    0xDE1CECC0,0x784DF852,0x6C9F4589,0x54B7AC23,0x14E7A1C4,0xF9BF04DF,
+    0x19C08B6D,0x3FB69EF1,0xB2DA9043,0xDB5362F3,0x25718DB6,0x733560DA,
+    0xFEF871B0,0xFECF7A0C,0x67D19C95,0xB492E911,0xF5D562A3,0xFCE1D478,
+    0x02C50434,0xF7326B7E,0x93D39872,0xCF0D0269,0x9EF24C0F,0x827689AD,
+    0x88BD20BC,0x74EA6AFE,0x29223682,0xB9AB9287,0x7EA7CE4F,0xCF81B379,
+    0x9AE4A954,0x81C7AD97,0x2FF2F031,0xC51DA3C2,0xD311CCE7,0x0A31EB8B,
+    0x1AB04242,0xAF53B714,0xFC574D40,0x8CB4ED01,0x29FEB16F,0x4904D7ED,
+    0xF5C5F5E1,0xF138A4C2,0xA9D881CE,0xCEA65187,0x4421BA97,0x0EE8428E,
+    0x9556E384,0x6D0484C9,0x561BD84B,0xD9516A40,0x6B4FD33F,0xDDFFE4C8,
+    0x3D5DF8A5,0xFE6B7D99,0x3443371B,0xF4E30A3E,0xE62B9FDA,0x6BAA75DB,
+    0x9EF3C2C7,0x6815CA42,0xE6536076,0xF851E6E2,0x39D16E69,0xBCDF3BB6,
+    0x50EFFA41,0x378CDF2A,0xB5EC0D0C,0x1E94C433,0xE818241A,0x2689EB1F,
+    0xB649CEF9,0xD7344D46,0x59C1BB13,0x27511FDF,0x7DAD1768,0xB355E29E,
+    0xDFAE550C,0x2433005B,0x09DE10B0,0xAA00BA6B,0xC144ED2D,0x8513D007,
+    0xB0315232,0x7A10DAB6,0x1D97654E,0xF048214D,0xE3059E75,0x83C225D1,
+    0xFC7AB177,0x83F2B553,0x79F7A0AF,0x1C94582C,0xF5E4AF4B,0xFB39C865,
+    0x58ABEB27,0xAAB28058,0x52C15A89,0x0EBE9741,0x343F4D26,0xF941202A,
+    0xA32FD32F,0xDCC055B8,0x64281BF3,0x468BD7BA,0x0CEE09D3,0xBB5FD2B6,
+    0xA528D412,0xA6A6967E,0xEAAF5DAE,0xDE7B2FAE,0xCA36887B,0x0DE196EB,
+    0x74B95EF0,0x9EB8B7C2,0x020BFC83,0x1445086F,0xBF4B61B2,0x89AFACEC,
+    0x80A5CD69,0xC790F744,0x435A6998,0x8DE7AC48,0x32F31BC9,0x8F760D3D,
+    0xF02A74CB,0xD7B47E20,0x9EC91035,0x70FDE74D,0x9B531362,0x9D81739A,
+    0x59ADC2EB,0x511555B5,0xCA84B8D5,0x3EC325FF,0x2E442A4C,0x82AF30D9,
+    0xBFD3EC87,0x90C59E07,0x1C6DC991,0x2D16B822,0x7EA44EB5,0x3A655A39,
+    0xAB640886,0x09311821,0x777801D9,0x489DBE61,0xA1FFEC65,0x978B49B1,
+    0x7DB700CD,0x263CF3D6,0xF977E89F,0xBA0B3D01,0x6C6CED19,0x1BE6F23A,
+    0x19E0ED98,0x8E71A499,0x70BA3271,0x3FB7EE98,0xABA46848,0x2B797959,
+    0x72C6DE59,0xE08B795C,0x02936C39,0x02185CCB,0xD6F3CE18,0xD0157A40,
+    0x833DEC3F,0x319B00C4,0x97B59513,0x900B81FD,0x9A022379,0x16E44E1A,
+    0x0C4CC540,0xCA98E7F9,0xF9431A26,0x290BCFAC,0x406B82C0,0xBC1C4585,
+    0x55C54528,0x811EBB77,0xD4EDD4F3,0xA70DC02E,0x8AD5C0D1,0x28D64EF4,
+    0xBEFF5C69,0x99852C4A,0xB4BBFF7B,0x069230AC,0xA3E141FA,0x4E99FB0E,
+    0xBC154DAA,0x323C7F15,0x86E0247E,0x2EEA3054,0xC9CA1D32,0x8964A006,
+    0xC93978AC,0xF9B2C159,0x03F2079E,0xB051D284,0x4A7EA9A9,0xF001DA1F,
+    0xD47A0DAA,0xCF7B6B73,0xF18293B2,0x84303E34,0xF8BC76C4,0xAFBEE24F,
+    0xB589CA80,0x77B5BF86,0x21B9FD5B,0x1A5071DF,0xA3863110,0x0E50CA61,
+    0x939151A5,0xD2A59021,0x83A9CDCE,0xCEC69767,0xC906BB16,0x3EE1FF4D,
+    0x1321EAE4,0x0BF940D6,0x52471E61,0x8A087056,0x66E54293,0xF84AAB9B,
+    0x08835EF1,0x8F12B77A,0xD86935A5,0x200281D7,0xCD3C37C9,0x30ABEC05,
+    0x7067E8A0,0x608C4838,0xC9F51CDE,0xA6D318DE,0x41C05B2A,0x694CCE0E,
+    0xC7842451,0xA3194393,0xFBDC2C84,0xA6D2B577,0xC91E7924,0x01EDA708,
+    0x22FBB61E,0x662F9B7B,0xDE3150C3,0x2397058C;
+    my $digest = sha512_hex($name . "\0" . $randdata);
+    return sprintf("%s-%s-%04x-%04x-%s",
+                   substr($digest,0,8),
+                   substr($digest,8,4),
+                   0x4000 | (0xFFF & hex(substr($digest,12,4))),
+                   0x8000 | (0x3FFF & hex(substr($digest,16,4))),
+                   substr($digest,20,12));
+}