Allow mkfiles.pl to put multiple verbatim sections in a Makefile, and use
[u/mdw/putty] / mkfiles.pl
index 5269116..b48c0a7 100755 (executable)
@@ -51,15 +51,17 @@ while (<IN>) {
   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 "!begin") {
       if (&mfval($_[1])) {
-         $divert = \$makefile_extra{$_[1]};
+          $sect = $_[2] ? $_[2] : "end";
+         $divert = \($makefile_extra{$_[1]}->{$sect});
       } else {
          $divert = \$dummy;
       }
       next;
   }
-  # If we're gathering help text, keep doing so.
+  # If we're gathering help/verbatim text, keep doing so.
   if (defined $divert) { ${$divert} .= "$_\n"; next; }
   # Ignore blank lines.
   next if scalar @_ == 0;
@@ -91,8 +93,8 @@ while (<IN>) {
     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]") and defined $prog) {
-      $type = substr($i,1,1);
+              $i eq "[X]" or $i eq "[U]" or $i eq "[MX]") and defined $prog) {
+      $type = substr($i,1,(length $i)-2);
     } else {
       push @$listref, $i;
     }
@@ -121,7 +123,8 @@ foreach $i (@prognames) {
           sort @{$programs{$i}};
   $programs{$i} = [@list];
   foreach $j (@list) {
-    # Dependencies for "x" start with "x.c".
+    # Dependencies for "x" start with "x.c" or "x.m" (depending on
+    # which one exists).
     # Dependencies for "x.res" start with "x.rc".
     # Dependencies for "x.rsrc" start with "x.r".
     # Both types of file are pushed on the list of files to scan.
@@ -134,10 +137,9 @@ foreach $i (@prognames) {
       $file = "$1.r";
       $depends{$j} = [$file];
       push @scanlist, $file;
-    } elsif ($j =~ /\.lib$/) {
-      # libraries don't have dependencies
-    } else {
+    } elsif ($j !~ /\./) {
       $file = "$j.c";
+      $file = "$j.m" unless &findfile($file);
       $depends{$j} = [$file];
       push @scanlist, $file;
     }
@@ -151,9 +153,11 @@ foreach $i (@prognames) {
 # added back on to @scanlist to be scanned in turn (if not already
 # done).
 #
-# Resource scripts (.rc) can also include a file by means of a line
-# ending `ICON "filename"'. Files included by this method are not
-# added to @scanlist because they can never include further files.
+# Resource scripts (.rc) can also include a file by means of:
+#  - a line # ending `ICON "filename"';
+#  - a line ending `RT_MANIFEST "filename"'.
+# Files included by this method are not added to @scanlist because
+# they can never include further files.
 #
 # In this pass we write out a hash %further which maps a source
 # file name into a listref containing further source file names.
@@ -173,8 +177,8 @@ while (scalar @scanlist > 0) {
       push @scanlist, $1;
       next;
     };
-    /ICON\s+\"([^\"]+)\"\s*$/ and do {
-      push @{$further{$file}}, $1;
+    /(RT_MANIFEST|ICON)\s+\"([^\"]+)\"\s*$/ and do {
+      push @{$further{$file}}, $2;
       next;
     }
   }
@@ -208,7 +212,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")) {
+       ("vc","vcproj","cygwin","borland","lcc","gtk","mpw","osx")) {
            return 1;
        }
     warn "$.:unknown makefile type '$type'\n";
@@ -221,8 +225,14 @@ sub dirpfx {
     my ($path) = shift @_;
     my ($sep) = shift @_;
     my $ret = "", $i;
-    while (($i = index $path, $sep) >= 0) {
-       $path = substr $path, ($i + length $sep);
+
+    while (($i = index $path, $sep) >= 0 ||
+          ($j = index $path, "/") >= 0) {
+        if ($i >= 0 and ($j < 0 or $i < $j)) {
+           $path = substr $path, ($i + length $sep);
+       } else {
+           $path = substr $path, ($j + 1);
+       }
        $ret .= "..$sep";
     }
     return $ret;
@@ -230,14 +240,17 @@ sub dirpfx {
 
 sub findfile {
   my ($name) = @_;
-  my $dir, $i, $outdir = "";
+  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/^\.\///;
     }
     die "multiple instances of source file $name\n" if $i > 1;
-    $findfilecache{$name} = $outdir . $name;
+    $findfilecache{$name} = (defined $outdir ? $outdir . $name : undef);
   }
   return $findfilecache{$name};
 }
@@ -255,7 +268,7 @@ sub objects {
     } elsif ($i =~ /^(.*)\.lib/) {
       $y = $1;
       ($x = $ltmpl) =~ s/X/$y/;
-    } else {
+    } elsif ($i !~ /\./) {
       ($x = $otmpl) =~ s/X/$i/;
     }
     push @ret, $x if $x ne "";
@@ -263,6 +276,19 @@ sub objects {
   return join " ", @ret;
 }
 
+sub special {
+  my ($prog, $suffix) = @_;
+  my @ret;
+  my ($i, $x, $y);
+  @ret = ();
+  foreach $i (@{$programs{$prog}}) {
+    if (substr($i, (length $i) - (length $suffix)) eq $suffix) {
+      push @ret, $i;
+    }
+  }
+  return (scalar @ret) ? (join " ", @ret) : undef;
+}
+
 sub splitline {
   my ($line, $width, $splitchar) = @_;
   my ($result, $len);
@@ -278,12 +304,13 @@ sub splitline {
 }
 
 sub deps {
-  my ($otmpl, $rtmpl, $prefix, $dirsep, $depchar, $splitchar) = @_;
+  my ($otmpl, $rtmpl, $prefix, $dirsep, $mftyp, $depchar, $splitchar) = @_;
   my ($i, $x, $y);
   my @deps, @ret;
   @ret = ();
   $depchar ||= ':';
   foreach $i (sort keys %depends) {
+    next if $specialobj{$mftyp}->{$i};
     if ($i =~ /^(.*)\.(res|rsrc)/) {
       next if !defined $rtmpl;
       $y = $1;
@@ -309,7 +336,7 @@ sub prognames {
   @ret = ();
   foreach $n (@prognames) {
     ($prog, $type) = split ",", $n;
-    push @ret, $n if index($types, $type) >= 0;
+    push @ret, $n if index(":$types:", ":$type:") >= 0;
   }
   return @ret;
 }
@@ -321,7 +348,7 @@ sub progrealnames {
   @ret = ();
   foreach $n (@prognames) {
     ($prog, $type) = split ",", $n;
-    push @ret, $prog if index($types, $type) >= 0;
+    push @ret, $prog if index(":$types:", ":$type:") >= 0;
   }
   return @ret;
 }
@@ -330,7 +357,7 @@ sub manpages {
   my ($types,$suffix) = @_;
 
   # assume that all UNIX programs have a man page
-  if($suffix eq "1" && $types =~ /X/) {
+  if($suffix eq "1" && $types =~ /:X:/) {
     return map("$_.1", &progrealnames($types));
   }
   return ();
@@ -371,17 +398,13 @@ if (defined $makefiles{'cygwin'}) {
     &splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1".
       " --define WINVER=0x0400 --define MINGW32_FIX=1")."\n".
     "\n".
-    ".SUFFIXES:\n".
-    "\n".
-    "%.o: %.c\n".
-    "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) -c \$<\n".
+    $makefile_extra{'cygwin'}->{'vars'} .
     "\n".
-    "%.res.o: %.rc\n".
-    "\t\$(RC) \$(FWHACK) \$(RCFL) \$(RCFLAGS) \$< \$\@\n".
+    ".SUFFIXES:\n".
     "\n";
-    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
     print "\n\n";
-    foreach $p (&prognames("GC")) {
+    foreach $p (&prognames("G:C")) {
       ($prog, $type) = split ",", $p;
       $objstr = &objects($p, "X.o", "X.res.o", undef);
       print &splitline($prog . ".exe: " . $objstr), "\n";
@@ -391,12 +414,17 @@ if (defined $makefiles{'cygwin'}) {
                        "-Wl,-Map,$prog.map " .
                        $objstr . " $libstr", 69), "\n\n";
     }
-    foreach $d (&deps("X.o", "X.res.o", $dirpfx, "/")) {
+    foreach $d (&deps("X.o", "X.res.o", $dirpfx, "/", "cygwin")) {
       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";
+      } else {
+         print "\t\$(CC) \$(COMPAT) \$(XFLAGS) \$(CFLAGS) -c ".$d->{deps}->[0]."\n\n";
+      }
     }
     print "\n";
-    print $makefile_extra{'cygwin'};
+    print $makefile_extra{'cygwin'}->{'end'};
     print "\nclean:\n".
     "\trm -f *.o *.exe *.res.o *.map\n".
     "\n";
@@ -442,25 +470,27 @@ if (defined $makefiles{'borland'}) {
     "BCB = \$(MAKEDIR)\\..\n".
     "!endif\n".
     "\n".
+    $makefile_extra{'borland'}->{'vars'} .
+    "\n".
     ".c.obj:\n".
-    &splitline("\tbcc32 -w-aus -w-ccc -w-par -w-pia \$(COMPAT) \$(FWHACK)".
+    &splitline("\tbcc32 -w-aus -w-ccc -w-par -w-pia \$(COMPAT)".
               " \$(XFLAGS) \$(CFLAGS) ".
               (join " ", map {"-I$dirpfx$_"} @srcdirs) .
-              "/c \$*.c",69)."\n".
+              " /c \$*.c",69)."\n".
     ".rc.res:\n".
-    &splitline("\tbrcc32 \$(FWHACK) \$(RCFL) -i \$(BCB)\\include -r".
+    &splitline("\tbrcc32 \$(RCFL) -i \$(BCB)\\include -r".
       " -DNO_WINRESRC_H -DWIN32 -D_WIN32 -DWINVER=0x0401 \$*.rc",69)."\n".
     "\n";
-    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
     print "\n\n";
-    foreach $p (&prognames("GC")) {
+    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";
       my $ap = ($type eq "G") ? "-aa" : "-ap";
       print "\tilink32 $ap -Gn -L\$(BCB)\\lib \@$prog.rsp\n\n";
     }
-    foreach $p (&prognames("GC")) {
+    foreach $p (&prognames("G:C")) {
       ($prog, $type) = split ",", $p;
       print $prog, ".rsp: \$(MAKEFILE)\n";
       $objstr = &objects($p, "X.obj", undef, undef);
@@ -488,12 +518,12 @@ if (defined $makefiles{'borland'}) {
       print "\techo " . &objects($p, undef, "X.res", undef) . " >> $prog.rsp\n";
       print "\n";
     }
-    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) {
+    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "borland")) {
       print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})),
         "\n";
     }
     print "\n";
-    print $makefile_extra{'borland'};
+    print $makefile_extra{'borland'}->{'end'};
     print "\nclean:\n".
     "\t-del *.obj\n".
     "\t-del *.exe\n".
@@ -525,23 +555,23 @@ 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 " .
+      (join " ", map {"-I$dirpfx$_"} @srcdirs) .
+      " /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401\n".
       "LFLAGS = /incremental:no /fixed\n".
       "\n".
-      ".c.obj:\n".
-      "\tcl \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) /c \$*.c\n".
-      ".rc.res:\n".
-      "\trc \$(FWHACK) \$(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 \$*.rc\n".
+      $makefile_extra{'vc'}->{'vars'} .
+      "\n".
       "\n";
-    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
     print "\n\n";
-    foreach $p (&prognames("GC")) {
+    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("GC")) {
+    foreach $p (&prognames("G:C")) {
        ($prog, $type) = split ",", $p;
        print $prog, ".rsp: \$(MAKEFILE)\n";
        $objstr = &objects($p, "X.obj", "X.res", "X.lib");
@@ -560,12 +590,17 @@ if (defined $makefiles{'vc'}) {
        }
        print "\n";
     }
-    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) {
+    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";
+       }
     }
     print "\n";
-    print $makefile_extra{'vc'};
+    print $makefile_extra{'vc'}->{'end'};
     print "\nclean: tidy\n".
       "\t-del *.exe\n\n".
       "tidy:\n".
@@ -588,6 +623,7 @@ if (defined $makefiles{'vc'}) {
 }
 
 if (defined $makefiles{'vcproj'}) {
+    $dirpfx = &dirpfx($makefiles{'vcproj'}, "\\");
 
     $orig_dir = cwd;
 
@@ -604,11 +640,11 @@ if (defined $makefiles{'vcproj'}) {
     mkdir $makefiles{'vcproj'}
         if(! -d $makefiles{'vcproj'});
     chdir $makefiles{'vcproj'};
-    @deps = &deps("X.obj", "X.res", "", "\\");
+    @deps = &deps("X.obj", "X.res", $dirpfx, "\\", "vcproj");
     %all_object_deps = map {$_->{obj} => $_->{deps}} @deps;
     # Create the project files
     # Get names of all Windows projects (GUI and console)
-    my @prognames = &prognames("GC");
+    my @prognames = &prognames("G:C");
     foreach $progname (@prognames) {
        create_project(\%all_object_deps, $progname);
     }
@@ -739,8 +775,12 @@ if (defined $makefiles{'vcproj'}) {
        "# PROP Intermediate_Dir \"Release\"\r\n".
        "# PROP Ignore_Export_Lib 0\r\n".
        "# PROP Target_Dir \"\"\r\n".
-       "# ADD BASE CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /c\r\n".
-       "# ADD CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /c\r\n".
+       "# ADD BASE CPP /nologo /W3 /GX /O2 ".
+         (join " ", map {"/I \"..\\..\\$dirpfx$_\""} @srcdirs) .
+         " /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /c\r\n".
+       "# ADD CPP /nologo /W3 /GX /O2 ".
+         (join " ", map {"/I \"..\\..\\$dirpfx$_\""} @srcdirs) .
+         " /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /c\r\n".
        "# ADD BASE MTL /nologo /D \"NDEBUG\" /mktyplib203 /win32\r\n".
        "# ADD MTL /nologo /D \"NDEBUG\" /mktyplib203 /win32\r\n".
        "# ADD BASE RSC /l 0x809 /d \"NDEBUG\"\r\n".
@@ -766,8 +806,12 @@ if (defined $makefiles{'vcproj'}) {
        "# PROP Intermediate_Dir \"Debug\"\r\n".
        "# PROP Ignore_Export_Lib 0\r\n".
        "# PROP Target_Dir \"\"\r\n".
-       "# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /GZ /c\r\n".
-       "# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /GZ /c\r\n".
+       "# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od ".
+         (join " ", map {"/I \"..\\..\\$dirpfx$_\""} @srcdirs) .
+         " /D \"WIN32\" /D \"_DEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /GZ /c\r\n".
+       "# ADD CPP /nologo /W3 /Gm /GX /ZI /Od ".
+         (join " ", map {"/I \"..\\..\\$dirpfx$_\""} @srcdirs) .
+         " /D \"WIN32\" /D \"_DEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /GZ /c\r\n".
        "# ADD BASE MTL /nologo /D \"_DEBUG\" /mktyplib203 /win32\r\n".
        "# ADD MTL /nologo /D \"_DEBUG\" /mktyplib203 /win32\r\n".
        "# ADD BASE RSC /l 0x809 /d \"_DEBUG\"\r\n".
@@ -874,14 +918,14 @@ if (defined $makefiles{'gtk'}) {
     "mandir=\$(prefix)/man\n",
     "man1dir=\$(mandir)/man1\n",
     "\n".
+    $makefile_extra{'gtk'}->{'vars'} .
+    "\n".
     ".SUFFIXES:\n".
     "\n".
-    "%.o:\n".
-    "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) -c \$<\n".
     "\n";
-    print &splitline("all:" . join "", map { " $_" } &progrealnames("XU"));
+    print &splitline("all:" . join "", map { " $_" } &progrealnames("X:U"));
     print "\n\n";
-    foreach $p (&prognames("XU")) {
+    foreach $p (&prognames("X:U")) {
       ($prog, $type) = split ",", $p;
       $objstr = &objects($p, "X.o", undef, undef);
       print &splitline($prog . ": " . $objstr), "\n";
@@ -889,14 +933,15 @@ if (defined $makefiles{'gtk'}) {
       print &splitline("\t\$(CC)" . $mw . " \$(${type}LDFLAGS) -o \$@ " .
                        $objstr . " $libstr", 69), "\n\n";
     }
-    foreach $d (&deps("X.o", undef, $dirpfx, "/")) {
+    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");
     }
     print "\n";
-    print $makefile_extra{'gtk'};
+    print $makefile_extra{'gtk'}->{'end'};
     print "\nclean:\n".
-    "\trm -f *.o". (join "", map { " $_" } &progrealnames("XU")) . "\n";
+    "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U")) . "\n";
     select STDOUT; close OUT;
 }
 
@@ -1008,14 +1053,14 @@ if (defined $makefiles{'mpw'}) {
       }
 
     }
-    foreach $d (&deps("", "X.rsrc", "::", ":")) {
+    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";
     }
     foreach $arch (qw(68K CFM68K)) {
-        foreach $d (&deps("X.\L$arch\E.o", "", "::", ":")) {
+        foreach $d (&deps("X.\L$arch\E.o", "", "::", ":", "mpw")) {
         next unless $d->{obj};
        print &splitline(sprintf("%s \xc4 %s", $d->{obj},
                                 join " ", @{$d->{deps}}),
@@ -1025,7 +1070,7 @@ if (defined $makefiles{'mpw'}) {
          }
     }
     foreach $arch (qw(PPC Carbon)) {
-        foreach $d (&deps("X.\L$arch\E.o", "", "::", ":")) {
+        foreach $d (&deps("X.\L$arch\E.o", "", "::", ":", "mpw")) {
         next unless $d->{obj};
        print &splitline(sprintf("%s \xc4 %s", $d->{obj},
                                 join " ", @{$d->{deps}}),
@@ -1065,15 +1110,11 @@ if (defined $makefiles{'lcc'}) {
     "\n".
     "# Get include directory for resource compiler\n".
     "\n".
-    ".c.obj:\n".
-    &splitline("\tlcc -O -p6 \$(COMPAT) \$(FWHACK)".
-      " \$(XFLAGS) \$(CFLAGS)  \$*.c",69)."\n".
-    ".rc.res:\n".
-    &splitline("\tlrc \$(FWHACK) \$(RCFL) -r \$*.rc",69)."\n".
+    $makefile_extra{'lcc'}->{'vars'} .
     "\n";
-    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("GC"));
+    print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C"));
     print "\n\n";
-    foreach $p (&prognames("GC")) {
+    foreach $p (&prognames("G:C")) {
       ($prog, $type) = split ",", $p;
       $objstr = &objects($p, "X.obj", "X.res", undef);
       print &splitline("$prog.exe: " . $objstr ), "\n";
@@ -1084,12 +1125,18 @@ if (defined $makefiles{'lcc'}) {
       print "\n\n";
     }
 
-    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) {
+    foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "lcc")) {
       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";
+      } else {
+         print &splitline("\tlrc \$(RCFL) -r ".$d->{deps}->[0],69)."\n";
+      }
     }
     print "\n";
-    print $makefile_extra{'lcc'};
+    print $makefile_extra{'lcc'}->{'end'};
     print "\nclean:\n".
     "\t-del *.obj\n".
     "\t-del *.exe\n".
@@ -1097,3 +1144,78 @@ if (defined $makefiles{'lcc'}) {
 
     select STDOUT; close OUT;
 }
+
+if (defined $makefiles{'osx'}) {
+    $dirpfx = &dirpfx($makefiles{'osx'}, "/");
+
+    ##-- Mac OS X makefile
+    open OUT, ">$makefiles{'osx'}"; select OUT;
+    print
+    "# Makefile for $project_name under Mac OS X.\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
+    "CC = \$(TOOLPATH)gcc\n".
+    "\n".
+    &splitline("CFLAGS = -O2 -Wall -Werror -g " .
+              (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n".
+    "MLDFLAGS = -framework Cocoa\n".
+    "ULDFLAGS =\n".
+    "\n" .
+    $makefile_extra{'osx'}->{'vars'} .
+    "\n" .
+    &splitline("all:" . join "", map { " $_" } &progrealnames("MX:U")) .
+    "\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";
+      print "${prog}.app/Contents: ${prog}.app\n\tmkdir -p \$\@\n";
+      print "${prog}.app/Contents/MacOS: ${prog}.app/Contents\n\tmkdir -p \$\@\n";
+      $targets = "${prog}.app/Contents/MacOS/$prog";
+      if (defined $icon) {
+       print "${prog}.app/Contents/Resources: ${prog}.app/Contents\n\tmkdir -p \$\@\n";
+       print "${prog}.app/Contents/Resources/${prog}.icns: ${prog}.app/Contents/Resources $icon\n\tcp $icon \$\@\n";
+       $targets .= " ${prog}.app/Contents/Resources/${prog}.icns";
+      }
+      if (defined $infoplist) {
+       print "${prog}.app/Contents/Info.plist: ${prog}.app/Contents/Resources $infoplist\n\tcp $infoplist \$\@\n";
+       $targets .= " ${prog}.app/Contents/Info.plist";
+      }
+      $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 . " \$(MLDFLAGS) -o \$@ " .
+                       $objstr . " $libstr", 69), "\n\n";
+    }
+    foreach $p (&prognames("U")) {
+      ($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 \$@ " .
+                       $objstr . " $libstr", 69), "\n\n";
+    }
+    foreach $d (&deps("X.o", undef, $dirpfx, "/")) {
+      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";
+      } elsif ($firstdep =~ /\.m$/) {
+         print "\t\$(CC) -x objective-c \$(COMPAT) \$(FWHACK) \$(XFLAGS) \$(CFLAGS) -c \$<\n";
+      }
+    }
+    print "\n".$makefile_extra{'osx'}->{'end'};
+    print "\nclean:\n".
+    "\trm -f *.o *.dmg". (join "", map { " $_" } &progrealnames("U")) . "\n";
+    "\trm -rf *.app\n";
+    select STDOUT; close OUT;
+}