};
# 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 ".."; select STDOUT;';
+# 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 = ("./");
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 "";
+ 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;
}
} 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 UT);
+ if ! grep { $type eq $_ } qw(G C X U MX XT UT);
} else {
push @$listref, $i;
}
# prints a warning and returns false;
if (grep { $type eq $_ }
("vc","vcproj","cygwin","borland","lcc","devcppproj","gtk","unix",
- "am","osx","vstudio10","vstudio12")) {
+ "am","osx","vstudio10","vstudio12","clangcl")) {
return 1;
}
warn "$.:unknown makefile type '$type'\n";
# 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, MinGW, or Winelib.\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
"# 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".
"# 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 " .
+ &splitline("CFLAGS = -Wall -O2 -D_WINDOWS -DDEBUG -DWIN32S_COMPAT".
+ " -D_NO_OLDNAMES " .
(join " ", map {"-I$dirpfx$_"} @srcdirs)) .
"\n".
- "LDFLAGS = -mno-cygwin -s\n".
+ "LDFLAGS = -s\n".
&splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1 ".
"--define WINVER=0x0400 ".(join " ", map {"-I$dirpfx$_"} @srcdirs))."\n".
"\n".
"# C compilation flags\n".
"CFLAGS = /nologo /W3 /O1 " .
(join " ", map {"-I$dirpfx$_"} @srcdirs) .
- " /D_WINDOWS /D_WIN32_WINDOWS=0x500 /DWINVER=0x500\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".
&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) \$(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");
+ $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")) {
+ 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} =~ /.obj$/) {
- print "\tcl \$(COMPAT) \$(CFLAGS) \$(XFLAGS) /c ".$d->{deps}->[0],"\n\n";
- } else {
- print "\trc \$(RCFL) -r \$(RCFLAGS) ".$d->{deps}->[0],"\n\n";
+ if ($d->{obj} =~ /.res$/) {
+ print "\trc /Fo@{[$d->{obj}]} \$(RCFL) -r \$(RCFLAGS) ".$d->{deps}->[0],"\n\n";
}
}
print "\n";
+ 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;
}
"# 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".
+ "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".
".SUFFIXES:\n".
"\n".
"\n";
- print &splitline("all:" . join "", map { " $_" } &progrealnames("X:U:UT"));
+ print &splitline("all:" . join "", map { " $_" }
+ &progrealnames("X:XT:U:UT"));
print "\n\n";
- foreach $p (&prognames("X:U:UT")) {
+ 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) -o \$@ " .
- $objstr . " \$(${type}LDFLAGS) $libstr", 69), "\n\n";
+ $objstr . " \$(${ldflags}LDFLAGS) $libstr", 69), "\n\n";
}
foreach $d (&deps("X.o", undef, $dirpfx, "/", "gtk")) {
if ($forceobj{$d->{obj_orig}}) {
print "\n";
print &def($makefile_extra{'gtk'}->{'end'});
print "\nclean:\n".
- "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:U:UT")) . "\n";
+ "\trm -f *.o". (join "", map { " $_" } &progrealnames("X:XT:U:UT")) . "\n";
print "\nFORCE:\n";
select STDOUT; close OUT;
}
# 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 keys %allsourcefiles);
+ @sources = ("allsources", "=",
+ sort grep {$_ ne "empty.h"} keys %allsourcefiles);
print &splitline(join " ", @sources), "\n\n";
@cliprogs = ("bin_PROGRAMS", "=");
print "endif\n\n";
@noinstcliprogs = ("noinst_PROGRAMS", "=");
- foreach $p (&prognames("UT")) {
+ foreach $p (&prognames("XT:UT")) {
($prog, $type) = split ",", $p;
push @noinstcliprogs, $prog;
}
%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,
- $cflags{'am'}->{$obj}), "\n";
+ $flags), "\n";
$amspeciallibs{$obj} = "lib${obj}.a";
}
print &splitline(join " ", "noinst_LIBRARIES", "=",
sort { $a cmp $b } values %amspeciallibs), "\n\n";
- foreach $p (&prognames("X:U:UT")) {
+ foreach $p (&prognames("X:XT:U:UT")) {
($prog, $type) = split ",", $p;
- print "if HAVE_GTK\n" if $type eq "X";
+ print "if HAVE_GTK\n" if $type eq "X" || $type eq "XT";
@progsources = ("${prog}_SOURCES", "=");
%sourcefiles = ();
@ldadd = ();
}
push @progsources, sort { $a cmp $b } keys %sourcefiles;
print &splitline(join " ", @progsources), "\n";
- if ($type eq "X") {
+ 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";
+ print "endif\n" if $type eq "X" || $type eq "XT";
print "\n";
}
print &def($makefile_extra{'am'}->{'end'});