1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00
putty-source/mkfiles.pl
Simon Tatham 4f457ff7f2 Add '.so' to the list of file extensions cleared up by 'make clean' in
Makefile.cyg, since if you're building against Winelib it will
generate one of those alongside each .exe file.

[originally from svn r9952]
2013-07-21 09:16:37 +00:00

1563 lines
52 KiB
Perl
Executable File

#!/usr/bin/env perl
#
# Cross-platform Makefile generator.
#
# Reads the file `Recipe' to determine the list of generated
# executables and their component objects. Then reads the source
# files to compute #include dependencies. Finally, writes out the
# various target Makefiles.
# PuTTY specifics which could still do with removing:
# - Mac makefile is not portabilised at all. Include directories
# 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;
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
# subdirs in the source tree. So if we can't find Recipe here,
# try one level up.
chdir "..";
open IN, "Recipe" or die "unable to open Recipe file\n";
};
# 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 ".."';
@srcdirs = ("./");
$divert = undef; # ref to scalar in which text is currently being put
$help = ""; # list of newline-free lines of help text
$project_name = "project"; # this is a good enough default
%makefiles = (); # maps makefile types to output makefile pathnames
%makefile_extra = (); # maps makefile types to extra Makefile text
%programs = (); # maps prog name + type letter to listref of objects/resources
%groups = (); # maps group name to listref of objects/resources
while (<IN>) {
chomp;
@_ = 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
$rest = 1 if $rest eq "";
$cflags{$_[1]}->{$_[2]} = $rest;
next;
}
if ($_[0] eq "!forceobj") { $forceobj{$_[1]} = 1; next; }
if ($_[0] eq "!begin") {
if ($_[1] =~ /^>(.*)/) {
$divert = \$auxfiles{$1};
} elsif (&mfval($_[1])) {
$sect = $_[2] ? $_[2] : "end";
$divert = \($makefile_extra{$_[1]}->{$sect});
} else {
$dummy = '';
$divert = \$dummy;
}
next;
}
# If we're gathering help/verbatim text, keep doing so.
if (defined $divert) { ${$divert} .= "$_\n"; next; }
# Ignore blank lines.
next if scalar @_ == 0;
# Now we have an ordinary line. See if it's an = line, a : line
# or a + line.
@objs = @_;
if ($_[0] eq "+") {
$listref = $lastlistref;
$prog = undef;
die "$.: unexpected + line\n" if !defined $lastlistref;
} elsif ($_[1] eq "=") {
$groups{$_[0]} = [] if !defined $groups{$_[0]};
$listref = $groups{$_[0]};
$prog = undef;
shift @objs; # eat the group name
} elsif ($_[1] eq ":") {
$listref = [];
$prog = $_[0];
shift @objs; # eat the program name
} else {
die "$.: unrecognised line type\n";
}
shift @objs; # eat the +, the = or the :
while (scalar @objs > 0) {
$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) {
$type = substr($i,1,(length $i)-2);
} else {
push @$listref, $i;
}
}
if ($prog and $type) {
die "multiple program entries for $prog [$type]\n"
if defined $programs{$prog . "," . $type};
$programs{$prog . "," . $type} = $listref;
}
$lastlistref = $listref;
}
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.
@prognames = sort keys %programs;
%depends = ();
@scanlist = ();
foreach $i (@prognames) {
($prog, $type) = split ",", $i;
# Strip duplicate object names.
$prev = '';
@list = grep { $status = ($prev ne $_); $prev=$_; $status }
sort @{$programs{$i}};
$programs{$i} = [@list];
foreach $j (@list) {
# Dependencies for "x" start with "x.c" or "x.m" (depending on
# which one exists).
# Dependencies for "x.res" start with "x.rc".
# Dependencies for "x.rsrc" start with "x.r".
# Both types of file are pushed on the list of files to scan.
# Libraries (.lib) don't have dependencies at all.
if ($j =~ /^(.*)\.res$/) {
$file = "$1.rc";
$depends{$j} = [$file];
push @scanlist, $file;
} elsif ($j =~ /^(.*)\.rsrc$/) {
$file = "$1.r";
$depends{$j} = [$file];
push @scanlist, $file;
} elsif ($j !~ /\./) {
$file = "$j.c";
$file = "$j.m" unless &findfile($file);
$depends{$j} = [$file];
push @scanlist, $file;
}
}
}
# Scan each file on @scanlist and find further inclusions.
# Inclusions are given by lines of the form `#include "otherfile"'
# (system headers are automatically ignored by this because they'll
# be given in angle brackets). Files included by this method are
# 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"';
# - 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.
%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
$further{$file} = [];
$dirfile = &findfile($file);
$allsourcefiles{$dirfile} = 1;
open IN, "$dirfile" or die "unable to open source file $file\n";
while (<IN>) {
chomp;
/^\s*#include\s+\"([^\"]+)\"/ and do {
push @{$further{$file}}, $1;
push @scanlist, $1;
next;
};
/(RT_MANIFEST|ICON)\s+\"([^\"]+)\"\s*$/ and do {
push @{$further{$file}}, $2;
next;
}
}
close IN;
}
# Now we're ready to generate the final dependencies section. For
# each key in %depends, we must expand the dependencies list by
# iteratively adding entries from %further.
foreach $i (keys %depends) {
%dep = ();
@scanlist = @{$depends{$i}};
foreach $i (@scanlist) { $dep{$i} = 1; }
while (scalar @scanlist > 0) {
$file = shift @scanlist;
foreach $j (@{$further{$file}}) {
if (!$dep{$j}) {
$dep{$j} = 1;
push @{$depends{$i}}, $j;
push @scanlist, $j;
}
}
}
# printf "%s: %s\n", $i, join ' ',@{$depends{$i}};
}
# Validation of input.
sub mfval($) {
my ($type) = @_;
# 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","devcppproj","gtk","unix",
"am","osx",)) {
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 = "";
my $i;
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;
}
sub findfile {
my ($name) = @_;
my $dir = '';
my $i;
my $outdir = undef;
unless (defined $findfilecache{$name}) {
$i = 0;
foreach $dir (@srcdirs) {
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);
}
return $findfilecache{$name};
}
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 = "";
if ($i =~ /^(.*)\.(res|rsrc)/) {
$y = $1;
($x = $rtmpl) =~ s/X/$y/;
} elsif ($i =~ /^(.*)\.lib/) {
$y = $1;
($x = $ltmpl) =~ s/X/$y/;
} elsif ($i !~ /\./) {
($x = $otmpl) =~ s/X/$i/;
}
push @ret, $x if $x ne "";
}
return join " ", @ret;
}
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) {
push @ret, $i;
}
}
return (scalar @ret) ? (join " ", @ret) : undef;
}
sub splitline {
my ($line, $width, $splitchar) = @_;
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;
$result .= " ${splitchar}\n\t\t" if $2 ne '';
$line = $2;
$len = 60;
}
return $result . $line;
}
sub deps {
my ($otmpl, $rtmpl, $prefix, $dirsep, $mftyp, $depchar, $splitchar) = @_;
my ($i, $x, $y);
my @deps;
my @ret;
@ret = ();
$depchar ||= ':';
foreach $i (sort keys %depends) {
next if $specialobj{$mftyp}->{$i};
if ($i =~ /^(.*)\.(res|rsrc)/) {
next if !defined $rtmpl;
$y = $1;
($x = $rtmpl) =~ s/X/$y/;
} else {
($x = $otmpl) =~ s/X/$i/;
}
@deps = @{$depends{$i}};
@deps = map {
$_ = &findfile($_);
s/\//$dirsep/g;
$_ = $prefix . $_;
} @deps;
push @ret, {obj => $x, obj_orig => $i, deps => [@deps]};
}
return @ret;
}
sub prognames {
my ($types) = @_;
my ($n, $prog, $type);
my @ret;
@ret = ();
foreach $n (@prognames) {
($prog, $type) = split ",", $n;
push @ret, $n if index(":$types:", ":$type:") >= 0;
}
return @ret;
}
sub progrealnames {
my ($types) = @_;
my ($n, $prog, $type);
my @ret;
@ret = ();
foreach $n (@prognames) {
($prog, $type) = split ",", $n;
push @ret, $prog if index(":$types:", ":$type:") >= 0;
}
return @ret;
}
sub manpages {
my ($types,$suffix) = @_;
# assume that all UNIX programs have a man page
if($suffix eq "1" && $types =~ /:X:/) {
return map("$_.1", &progrealnames($types));
}
return ();
}
$orig_dir = cwd;
# Now we're ready to output the actual Makefiles.
if (defined $makefiles{'cygwin'}) {
$dirpfx = &dirpfx($makefiles{'cygwin'}, "/");
##-- CygWin makefile
open OUT, ">$makefiles{'cygwin'}"; select OUT;
print
"# Makefile for $project_name under Cygwin, MinGW, 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/$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".
"CC = \$(TOOLPATH)gcc\n".
"RC = \$(TOOLPATH)windres\n".
"# Uncomment the following two lines to compile under Winelib\n".
"# CC = winegcc\n".
"# RC = wrc\n".
"# 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 -DNO_HTMLHELP -DNO_SECUREZEROMEMORY " .
(join " ", map {"-I$dirpfx$_"} @srcdirs)) .
"\n".
"LDFLAGS = -mno-cygwin -s\n".
&splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1".
" --define WINVER=0x0400")."\n".
"\n".
$makefile_extra{'cygwin'}->{'vars'} .
"\n".
".SUFFIXES:\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.o", "X.res.o", undef);
print &splitline($prog . ".exe: " . $objstr), "\n";
my $mw = $type eq "G" ? " -mwindows" : "";
$libstr = &objects($p, undef, undef, "-lX");
print &splitline("\t\$(CC)" . $mw . " \$(LDFLAGS) -o \$@ " .
"-Wl,-Map,$prog.map " .
$objstr . " $libstr", 69), "\n\n";
}
foreach $d (&deps("X.o", "X.res.o", $dirpfx, "/", "cygwin")) {
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]." -o ".$d->{obj}."\n\n";
} else {
print "\t\$(CC) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) -c ".$d->{deps}->[0]."\n\n";
}
}
print "\n";
print $makefile_extra{'cygwin'}->{'end'};
print "\nclean:\n".
"\trm -f *.o *.exe *.res.o *.so *.map\n".
"\n".
"FORCE:\n";
select STDOUT; close OUT;
}
##-- Borland makefile
if (defined $makefiles{'borland'}) {
$dirpfx = &dirpfx($makefiles{'borland'}, "\\");
%stdlibs = ( # Borland provides many Win32 API libraries intrinsically
"advapi32" => 1,
"comctl32" => 1,
"comdlg32" => 1,
"gdi32" => 1,
"imm32" => 1,
"shell32" => 1,
"user32" => 1,
"winmm" => 1,
"winspool" => 1,
"wsock32" => 1,
);
open OUT, ">$makefiles{'borland'}"; select OUT;
print
"# Makefile for $project_name under Borland C.\n".
"#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
"# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
# bcc32 command line option is -D not /D
($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
print $_;
print
"\n".
"# If you rename this file to `Makefile', you should change this line,\n".
"# so that the .rsp files still depend on the correct makefile.\n".
"MAKEFILE = Makefile.bor\n".
"\n".
"# C compilation flags\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'} .
"\n".
".c.obj:\n".
&splitline("\tbcc32 -w-aus -w-ccc -w-par -w-pia \$(COMPAT)".
" \$(CFLAGS) \$(XFLAGS) ".
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
" /c \$*.c",69)."\n".
".rc.res:\n".
&splitline("\tbrcc32 \$(RCFL) -i \$(BCB)\\include -r".
" \$(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);
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("G:C")) {
($prog, $type) = split ",", $p;
print $prog, ".rsp: \$(MAKEFILE)\n";
$objstr = &objects($p, "X.obj", undef, undef);
@objlist = split " ", $objstr;
@objlines = ("");
foreach $i (@objlist) {
if (length($objlines[$#objlines] . " $i") > 50) {
push @objlines, "";
}
$objlines[$#objlines] .= " $i";
}
$c0w = ($type eq "G") ? "c0w32" : "c0x32";
print "\techo $c0w + > $prog.rsp\n";
for ($i=0; $i<=$#objlines; $i++) {
$plus = ($i < $#objlines ? " +" : "");
print "\techo$objlines[$i]$plus >> $prog.rsp\n";
}
print "\techo $prog.exe >> $prog.rsp\n";
$objstr = &objects($p, "X.obj", "X.res", undef);
@libs = split " ", &objects($p, undef, undef, "X");
@libs = grep { !$stdlibs{$_} } @libs;
unshift @libs, "cw32", "import32";
$libstr = join ' ', @libs;
print "\techo nul,$libstr, >> $prog.rsp\n";
print "\techo " . &objects($p, undef, "X.res", undef) . " >> $prog.rsp\n";
print "\n";
}
foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "borland")) {
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 "\nclean:\n".
"\t-del *.obj\n".
"\t-del *.exe\n".
"\t-del *.res\n".
"\t-del *.pch\n".
"\t-del *.aps\n".
"\t-del *.il*\n".
"\t-del *.pdb\n".
"\t-del *.rsp\n".
"\t-del *.tds\n".
"\t-del *.\$\$\$\$\$\$\n".
"\n".
"FORCE:\n".
"\t-rem dummy command\n";
select STDOUT; close OUT;
}
if (defined $makefiles{'vc'}) {
$dirpfx = &dirpfx($makefiles{'vc'}, "\\");
##-- Visual C++ makefile
open OUT, ">$makefiles{'vc'}"; select OUT;
print
"# Makefile for $project_name under Visual C.\n".
"#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n".
"# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n";
print $help;
print
"\n".
"# If you rename this file to `Makefile', you should change this line,\n".
"# so that the .rsp files still depend on the correct makefile.\n".
"MAKEFILE = Makefile.vc\n".
"\n".
"# C compilation flags\n".
"CFLAGS = /nologo /W3 /O1 " .
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
" /D_WINDOWS /D_WIN32_WINDOWS=0x500 /DWINVER=0x500\n".
"LFLAGS = /incremental:no /fixed\n".
"RCFLAGS = -DWIN32 -D_WIN32 -DWINVER=0x0400\n".
"\n".
$makefile_extra{'vc'}->{'vars'} .
"\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);
print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n";
print "\tlink \$(LFLAGS) \$(XLFLAGS) -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");
@objlist = split " ", $objstr;
@objlines = ("");
foreach $i (@objlist) {
if (length($objlines[$#objlines] . " $i") > 50) {
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 "\n";
}
foreach $d (&deps("X.obj", "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} =~ /.obj$/) {
print "\tcl \$(COMPAT) \$(CFLAGS) \$(XFLAGS) /c ".$d->{deps}->[0],"\n\n";
} else {
print "\trc \$(RCFL) -r \$(RCFLAGS) ".$d->{deps}->[0],"\n\n";
}
}
print "\n";
print $makefile_extra{'vc'}->{'end'};
print "\nclean: tidy\n".
"\t-del *.exe\n\n".
"tidy:\n".
"\t-del *.obj\n".
"\t-del *.res\n".
"\t-del *.pch\n".
"\t-del *.aps\n".
"\t-del *.ilk\n".
"\t-del *.pdb\n".
"\t-del *.rsp\n".
"\t-del *.dsp\n".
"\t-del *.dsw\n".
"\t-del *.ncb\n".
"\t-del *.opt\n".
"\t-del *.plg\n".
"\t-del *.map\n".
"\t-del *.idb\n".
"\t-del debug.log\n";
select STDOUT; close OUT;
}
if (defined $makefiles{'vcproj'}) {
$dirpfx = &dirpfx($makefiles{'vcproj'}, "\\");
##-- MSVC 6 Workspace and projects
#
# Note: All files created in this section are written in binary
# mode, because although MSVC's command-line make can deal with
# LF-only line endings, MSVC project files really _need_ to be
# CRLF. Hence, in order for mkfiles.pl to generate usable 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{'vcproj'}
if(! -d $makefiles{'vcproj'});
chdir $makefiles{'vcproj'};
@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("G:C");
foreach $progname (@prognames) {
create_vc_project(\%all_object_deps, $progname);
}
# Create the workspace file
open OUT, ">$project_name.dsw"; binmode OUT; select OUT;
print
"Microsoft Developer Studio Workspace File, Format Version 6.00\r\n".
"# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r\n".
"\r\n".
"###############################################################################\r\n".
"\r\n";
# List projects
foreach $progname (@prognames) {
($windows_project, $type) = split ",", $progname;
print "Project: \"$windows_project\"=\".\\$windows_project\\$windows_project.dsp\" - Package Owner=<4>\r\n";
}
print
"\r\n".
"Package=<5>\r\n".
"{{{\r\n".
"}}}\r\n".
"\r\n".
"Package=<4>\r\n".
"{{{\r\n".
"}}}\r\n".
"\r\n".
"###############################################################################\r\n".
"\r\n".
"Global:\r\n".
"\r\n".
"Package=<5>\r\n".
"{{{\r\n".
"}}}\r\n".
"\r\n".
"Package=<3>\r\n".
"{{{\r\n".
"}}}\r\n".
"\r\n".
"###############################################################################\r\n".
"\r\n";
select STDOUT; close OUT;
chdir $orig_dir;
sub create_vc_project {
my ($all_object_deps, $progname) = @_;
# Construct program's dependency info
%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") ? "windows" : "console";
open OUT, ">$windows_project.dsp"; binmode OUT; select OUT;
print
"# Microsoft Developer Studio Project File - Name=\"$windows_project\" - Package Owner=<4>\r\n".
"# Microsoft Developer Studio Generated Build File, Format Version 6.00\r\n".
"# ** DO NOT EDIT **\r\n".
"\r\n".
"# TARGTYPE \"Win32 (x86) Application\" 0x0101\r\n".
"\r\n".
"CFG=$windows_project - Win32 Debug\r\n".
"!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r\n".
"!MESSAGE use the Export Makefile command and run\r\n".
"!MESSAGE \r\n".
"!MESSAGE NMAKE /f \"$windows_project.mak\".\r\n".
"!MESSAGE \r\n".
"!MESSAGE You can specify a configuration when running NMAKE\r\n".
"!MESSAGE by defining the macro CFG on the command line. For example:\r\n".
"!MESSAGE \r\n".
"!MESSAGE NMAKE /f \"$windows_project.mak\" CFG=\"$windows_project - Win32 Debug\"\r\n".
"!MESSAGE \r\n".
"!MESSAGE Possible choices for configuration are:\r\n".
"!MESSAGE \r\n".
"!MESSAGE \"$windows_project - Win32 Release\" (based on \"Win32 (x86) Application\")\r\n".
"!MESSAGE \"$windows_project - Win32 Debug\" (based on \"Win32 (x86) Application\")\r\n".
"!MESSAGE \r\n".
"\r\n".
"# Begin Project\r\n".
"# PROP AllowPerConfigDependencies 0\r\n".
"# PROP Scc_ProjName \"\"\r\n".
"# PROP Scc_LocalPath \"\"\r\n".
"CPP=cl.exe\r\n".
"MTL=midl.exe\r\n".
"RSC=rc.exe\r\n".
"\r\n".
"!IF \"\$(CFG)\" == \"$windows_project - Win32 Release\"\r\n".
"\r\n".
"# PROP BASE Use_MFC 0\r\n".
"# PROP BASE Use_Debug_Libraries 0\r\n".
"# PROP BASE Output_Dir \"Release\"\r\n".
"# PROP BASE Intermediate_Dir \"Release\"\r\n".
"# PROP BASE Target_Dir \"\"\r\n".
"# PROP Use_MFC 0\r\n".
"# PROP Use_Debug_Libraries 0\r\n".
"# PROP Output_Dir \"Release\"\r\n".
"# 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 ".
(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".
"# ADD RSC /l 0x809 /d \"NDEBUG\"\r\n".
"BSC32=bscmake.exe\r\n".
"# ADD BASE BSC32 /nologo\r\n".
"# ADD BSC32 /nologo\r\n".
"LINK32=link.exe\r\n".
"# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:$subsys /machine:I386\r\n".
"# ADD LINK32 $libs /nologo /subsystem:$subsys /machine:I386\r\n".
"# SUBTRACT LINK32 /pdb:none\r\n".
"\r\n".
"!ELSEIF \"\$(CFG)\" == \"$windows_project - Win32 Debug\"\r\n".
"\r\n".
"# PROP BASE Use_MFC 0\r\n".
"# PROP BASE Use_Debug_Libraries 1\r\n".
"# PROP BASE Output_Dir \"Debug\"\r\n".
"# PROP BASE Intermediate_Dir \"Debug\"\r\n".
"# PROP BASE Target_Dir \"\"\r\n".
"# PROP Use_MFC 0\r\n".
"# PROP Use_Debug_Libraries 1\r\n".
"# PROP Output_Dir \"Debug\"\r\n".
"# 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 ".
(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".
"# ADD RSC /l 0x809 /d \"_DEBUG\"\r\n".
"BSC32=bscmake.exe\r\n".
"# ADD BASE BSC32 /nologo\r\n".
"# ADD BSC32 /nologo\r\n".
"LINK32=link.exe\r\n".
"# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:$subsys /debug /machine:I386 /pdbtype:sept\r\n".
"# ADD LINK32 $libs /nologo /subsystem:$subsys /debug /machine:I386 /pdbtype:sept\r\n".
"# SUBTRACT LINK32 /pdb:none\r\n".
"\r\n".
"!ENDIF \r\n".
"\r\n".
"# Begin Target\r\n".
"\r\n".
"# Name \"$windows_project - Win32 Release\"\r\n".
"# Name \"$windows_project - Win32 Debug\"\r\n".
"# Begin Group \"Source Files\"\r\n".
"\r\n".
"# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\r\n";
foreach $source_file (@source_files) {
print
"# Begin Source File\r\n".
"\r\n".
"SOURCE=..\\..\\$source_file\r\n";
if($source_file =~ /ssh\.c/io) {
# Disable 'Edit and continue' as Visual Studio can't handle the macros
print
"\r\n".
"!IF \"\$(CFG)\" == \"$windows_project - Win32 Release\"\r\n".
"\r\n".
"!ELSEIF \"\$(CFG)\" == \"$windows_project - Win32 Debug\"\r\n".
"\r\n".
"# ADD CPP /Zi\r\n".
"\r\n".
"!ENDIF \r\n".
"\r\n";
}
print "# End Source File\r\n";
}
print
"# End Group\r\n".
"# Begin Group \"Header Files\"\r\n".
"\r\n".
"# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\r\n";
foreach $header_file (@header_files) {
print
"# Begin Source File\r\n".
"\r\n".
"SOURCE=..\\..\\$header_file\r\n".
"# End Source File\r\n";
}
print
"# End Group\r\n".
"# Begin Group \"Resource Files\"\r\n".
"\r\n".
"# PROP Default_Filter \"ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe\"\r\n";
foreach $resource_file (@resources) {
print
"# Begin Source File\r\n".
"\r\n".
"SOURCE=..\\..\\$resource_file\r\n".
"# End Source File\r\n";
}
print
"# End Group\r\n".
"# End Target\r\n".
"# End Project\r\n";
select STDOUT; close OUT;
chdir "..";
}
}
if (defined $makefiles{'gtk'}) {
$dirpfx = &dirpfx($makefiles{'gtk'}, "/");
##-- X/GTK/Unix makefile
open OUT, ">$makefiles{'gtk'}"; select OUT;
print
"# Makefile for $project_name under X/GTK and 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";
# gcc command line option is -D not /D
($_ = $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+-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) .
" \$(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".
&def($makefile_extra{'gtk'}->{'vars'}) .
"\n".
".SUFFIXES:\n".
"\n".
"\n";
print &splitline("all:" . join "", map { " $_" } &progrealnames("X:U"));
print "\n\n";
foreach $p (&prognames("X:U")) {
($prog, $type) = split ",", $p;
$objstr = &objects($p, "X.o", undef, undef);
print &splitline($prog . ": " . $objstr), "\n";
$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, "/", "gtk")) {
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 "\nclean:\n".
"\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U")) . "\n";
print "\nFORCE:\n";
select STDOUT; close 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 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";
# gcc command line option is -D not /D
($_ = $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".
"\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)).
" -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".
&def($makefile_extra{'unix'}->{'vars'}) .
"\n".
".SUFFIXES:\n".
"\n".
"\n";
print &splitline("all:" . join "", map { " $_" } &progrealnames("U"));
print "\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) -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")) . "\n";
print "\nFORCE:\n";
select STDOUT; close OUT;
}
if (defined $makefiles{'am'}) {
$dirpfx = "\$(srcdir)/" . &dirpfx($makefiles{'am'}, "/");
##-- 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";
# 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", "=",
map {"${dirpfx}$_"} sort 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";
%objtosrc = ();
foreach $d (&deps("X", undef, $dirpfx, "/", "am")) {
$objtosrc{$d->{obj}} = $d->{deps}->[0];
}
print &splitline(join " ", "AM_CPPFLAGS", "=",
map {"-I$dirpfx$_"} @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'}}) {
print "lib${obj}_a_SOURCES = ", $objtosrc{$obj}, "\n";
print &splitline(join " ", "lib${obj}_a_CFLAGS", "=", @amcflags,
$cflags{'am'}->{$obj}), "\n";
$amspeciallibs{$obj} = "lib${obj}.a";
}
print &splitline(join " ", "noinst_LIBRARIES", "=",
sort { $a cmp $b } values %amspeciallibs), "\n\n";
foreach $p (&prognames("X:U")) {
($prog, $type) = split ",", $p;
print "if HAVE_GTK\n" if $type eq "X";
@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") {
push @ldadd, "\$(GTK_LIBS)";
}
if (@ldadd) {
print &splitline(join " ", "${prog}_LDADD", "=", @ldadd), "\n";
}
print "endif\n" if $type eq "X";
print "\n";
}
print $makefile_extra{'am'}->{'end'};
select STDOUT; close OUT;
}
if (defined $makefiles{'lcc'}) {
$dirpfx = &dirpfx($makefiles{'lcc'}, "\\");
##-- lcc makefile
open OUT, ">$makefiles{'lcc'}"; select OUT;
print
"# Makefile for $project_name under lcc.\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";
# lcc command line option is -D not /D
($_ = $help) =~ s/([=" ])\/D/$1-D/gs;
print $_;
print
"\n".
"# If you rename this file to `Makefile', you should change this line,\n".
"# so that the .rsp files still depend on the correct makefile.\n".
"MAKEFILE = Makefile.lcc\n".
"\n".
"# C compilation flags\n".
"CFLAGS = -D_WINDOWS " .
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
"\n".
"# Resource compilation flags\n".
"RCFLAGS = \n".
"\n".
"# Get include directory for resource compiler\n".
"\n".
$makefile_extra{'lcc'}->{'vars'} .
"\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);
print &splitline("$prog.exe: " . $objstr ), "\n";
$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");
print "\n\n";
}
foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\", "lcc")) {
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)".
" \$(CFLAGS) \$(XFLAGS) ".$d->{deps}->[0],69)."\n";
} else {
print &splitline("\tlrc \$(RCFL) -r \$(RCFLAGS) ".
$d->{deps}->[0],69)."\n";
}
}
print "\n";
print $makefile_extra{'lcc'}->{'end'};
print "\nclean:\n".
"\t-del *.obj\n".
"\t-del *.exe\n".
"\t-del *.res\n".
"\n".
"FORCE:\n";
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/$1-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) \$(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) \$(ULDFLAGS) -o \$@ " .
$objstr . " $libstr", 69), "\n\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) \$(CFLAGS) \$(XFLAGS) -c \$<\n";
} elsif ($firstdep =~ /\.m$/) {
print "\t\$(CC) -x objective-c \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS) -c \$<\n";
}
}
print "\n".&def($makefile_extra{'osx'}->{'end'});
print "\nclean:\n".
"\trm -f *.o *.dmg". (join "", map { " $_" } &progrealnames("U")) . "\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 = dirname($makefiles{"am"}))
or die "$targetdir: chdir: $!\n";
}
system "./configure", @confargs;
die "mkfiles.pl: configure returned $?\n" if $? > 0;
}