X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=mkfiles.pl;h=c0874ae07e6bfa11ff94286a6d7c81dd1aed3fa1;hb=db313b3948d27244dd7c34c2609c66d6204d8931;hp=d532c95204c7340dfefa02b1753ed46b3dd8b3dd;hpb=b375232d7dc8357e820ec00808749d077c8b06b9;p=sgt-puzzles.git diff --git a/mkfiles.pl b/mkfiles.pl index d532c95..c0874ae 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -57,7 +57,8 @@ eval 'chdir "charset"; require "sbcsgen.pl"; chdir ".."'; @srcdirs = ("./"); -$divert = undef; # ref to scalar in which text is currently being put +$divert = undef; # ref to array of refs of scalars in which text is + # currently being put $help = ""; # list of newline-free lines of help text $project_name = "project"; # this is a good enough default %makefiles = (); # maps makefile types to output makefile pathnames @@ -83,14 +84,16 @@ readinput: while (1) { if ((defined $_[0]) && $_[0] eq "!end") { $divert = undef; } else { - ${$divert} .= "$_\n"; + for my $ref (@$divert) { + ${$ref} .= "$_\n"; + } } next; } # Skip comments and blank lines. next if /^\s*#/ or scalar @_ == 0; - if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = \$help; next; } + if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = [\$help]; next; } if ($_[0] eq "!name") { $project_name = $_[1]; next; } if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; } if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;} @@ -102,10 +105,15 @@ readinput: while (1) { next; } if ($_[0] eq "!begin") { - if ($_[1] =~ /^>(.*)/) { - $divert = \$auxfiles{$1}; - } elsif (&mfval($_[1])) { - $divert = \$makefile_extra{$_[1]}; + my @args = @_; + shift @args; + $divert = []; + for my $component (@args) { + if ($component =~ /^>(.*)/) { + push @$divert, \$auxfiles{$1}; + } elsif ($component =~ /^([^_]*)(_.*)?$/ and &mfval($1)) { + push @$divert, \$makefile_extra{$component}; + } } next; } @@ -311,7 +319,7 @@ sub mfval($) { # Returns true if the argument is a known makefile type. Otherwise, # prints a warning and returns false; if (grep { $type eq $_ } - ("vc","vcproj","cygwin","borland","lcc","gtk","am","mpw","nestedvm","osx","wce","gnustep","emcc")) { + ("vc","vcproj","cygwin","borland","lcc","gtk","am","mpw","nestedvm","osx","wce","gnustep","emcc","clangcl")) { return 1; } warn "$.:unknown makefile type '$type'\n"; @@ -495,6 +503,151 @@ $orig_dir = cwd; # Now we're ready to output the actual Makefiles. +if (defined $makefiles{'clangcl'}) { + $mftyp = 'clangcl'; + $dirpfx = &dirpfx($makefiles{'clangcl'}, "/"); + + ##-- Makefile for cross-compiling using clang-cl, lld-link, and + ## MinGW's windres for resource compilation. + # + # This makefile allows a complete Linux-based cross-compile, but + # using the real Visual Studio header files and libraries. In + # order to run it, you will need: + # + # - MinGW windres on your PATH. + # * On Ubuntu as of 16.04, you can apt-get install + # binutils-mingw-w64-x86-64 and binutils-mingw-w64-i686 + # which will provide (respectively) 64- and 32-bit versions, + # under the names to which RCCMD is defined below. + # - clang-cl and lld-link on your PATH. + # * I built these from the up-to-date LLVM project trunk git + # repositories, as of 2017-02-05. + # - case-mashed copies of the Visual Studio include directories. + # * On a real VS installation, run vcvars32.bat and look at + # the resulting value of %INCLUDE%. Take a full copy of each + # of those directories, and inside the copy, for each + # include file that has an uppercase letter in its name, + # make a lowercased symlink to it. Additionally, one of the + # directories will contain files called driverspecs.h and + # specstrings.h, and those will need symlinks called + # DriverSpecs.h and SpecStrings.h. + # * Now, on Linux, define the environment variable INCLUDE to + # be a list, separated by *semicolons* (in the Windows + # style), of those directories, but before all of them you + # must also include lib/clang/5.0.0/include from the clang + # installation area (which contains in particular a + # clang-compatible stdarg.h overriding the Visual Studio + # one). + # - similarly case-mashed copies of the library directories. + # * Again, on a real VS installation, run vcvars32 or + # vcvarsx86_amd64 (as appropriate), look at %LIB%, make a + # copy of each directory, and provide symlinks within that + # directory so that all the files can be opened as + # lowercase. + # * Then set LIB to be a semicolon-separated list of those + # directories (but you'll need to change which set of + # directories depending on whether you want to do a 32-bit + # or 64-bit build). + # - for a 64-bit build, set 'Platform=x64' in the environment as + # well, or else on the make command line. + # * This is a variable understood only by this makefile - none + # of the tools we invoke will know it - but it's consistent + # with the way the VS scripts like vcvarsx86_amd64.bat set + # things up, and since the environment has to change + # _anyway_ between 32- and 64-bit builds (different set of + # paths in $LIB) it's reasonable to have the choice of + # compilation target driven by another environment variable + # set in parallel with that one. + # - for older versions of the VS libraries you may also have to + # set EXTRA_console and/or EXTRA_windows to the name of an + # object file manually extracted from one of those libraries. + # * This is because old VS seems to manage its startup code by + # having libcmt.lib contain lots of *crt0.obj objects, one + # for each possible user entry point (main, WinMain and the + # wide-char versions of both), of which the linker arranges + # to include the right one by special-case code. But lld + # only seems to mimic half of that code - it does include + # the right crt0 object, but it doesn't also deliberately + # _avoid_ including the _wrong_ ones, and since all those + # objects define a common set of global symbols for other + # parts of the library to use, lld may well select an + # arbitrary one of them the first time it sees a reference + # to one of those global symbols, and then later also select + # the _right_ one for the application's entry point, causing + # a multiple-definitions crash. + # * So the workaround is to explicitly include the right + # *crt0.obj file on the linker command line before lld even + # begins searching libraries. Hence, for a console + # application, you might extract crt0.obj from the library + # in question and set EXTRA_console=crt0.obj, and for a GUI + # application, do the same with wincrt0.obj. Then this + # makefile will include the right one of those objects + # alongside the matching /subsystem linker option. + + open OUT, ">$makefiles{'clangcl'}"; select OUT; + print + "# Makefile for cross-compiling $project_name using clang-cl, lld-link,\n". + "# and MinGW's windres, using GNU make on Linux.\n". + "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". + "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; + print $help; + print + "\n". + "CCCMD = clang-cl\n". + "ifeq (\$(Platform),x64)\n". + "CCTARGET = x86_64-pc-windows-msvc18.0.0\n". + "RCCMD = x86_64-w64-mingw32-windres\n". + "else\n". + "CCTARGET = i386-pc-windows-msvc18.0.0\n". + "RCCMD = i686-w64-mingw32-windres\n". + "endif\n". + "CC = \$(CCCMD) --target=\$(CCTARGET)\n". + &splitline("RC = \$(RCCMD) --preprocessor=\$(CCCMD) ". + "--preprocessor-arg=/TC --preprocessor-arg=/E")."\n". + "LD = lld-link\n". + "\n". + "# C compilation flags\n". + &splitline("CFLAGS = /nologo /W3 /O1 " . + (join " ", map {"-I$dirpfx$_"} @srcdirs) . + " /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401 ". + "/D_CRT_SECURE_NO_WARNINGS")."\n". + "LFLAGS = /incremental:no /dynamicbase /nxcompat\n". + &splitline("RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs). + " -DWIN32 -D_WIN32 -DWINVER=0x0400 --define MINGW32_FIX=1")."\n". + "\n". + "\n"; + print &splitline("all:" . join "", map { " \$(BUILDDIR)$_.exe" } &progrealnames("G:C")); + print "\n\n"; + foreach $p (&prognames("G:C")) { + ($prog, $type) = split ",", $p; + $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", undef); + print &splitline("\$(BUILDDIR)$prog.exe: " . $objstr), "\n"; + + $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", "X.lib"); + $subsys = ($type eq "G") ? "windows" : "console"; + print &splitline("\t\$(LD) \$(LFLAGS) \$(XLFLAGS) ". + "/out:\$(BUILDDIR)$prog.exe ". + "/lldmap:\$(BUILDDIR)$prog.map ". + "/subsystem:$subsys\$(SUBSYSVER) ". + "\$(EXTRA_$subsys) $objstr")."\n\n"; + } + foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res", $dirpfx, "/", "vc")) { + print &splitline(sprintf("%s: %s", $d->{obj}, + join " ", @{$d->{deps}})), "\n"; + if ($d->{obj} =~ /\.res$/) { + print "\t\$(RC) \$(RCFLAGS) ".$d->{deps}->[0]." -o ".$d->{obj}."\n\n"; + } else { + $deflist = join "", map { " /D$_" } @{$d->{defs}}; + print "\t\$(CC) /Fo\$(BUILDDIR)".$d->{obj}." \$(COMPAT) \$(CFLAGS) \$(XFLAGS)$deflist /c \$<\n\n"; + } + } + print "\nclean:\n". + &splitline("\trm -f \$(BUILDDIR)*.obj \$(BUILDDIR)*.exe ". + "\$(BUILDDIR)*.res \$(BUILDDIR)*.map ". + "\$(BUILDDIR)*.exe.manifest")."\n"; + select STDOUT; close OUT; +} + if (defined $makefiles{'cygwin'}) { $mftyp = 'cygwin'; $dirpfx = &dirpfx($makefiles{'cygwin'}, "/"); @@ -1181,7 +1334,8 @@ if (defined $makefiles{'gtk'}) { if (defined $makefiles{'am'}) { $mftyp = 'am'; - $dirpfx = "\$(srcdir)/" . &dirpfx($makefiles{'am'}, "/"); + die "Makefile.am in a subdirectory is not supported\n" + if &dirpfx($makefiles{'am'}, "/") ne ""; ##-- Unix/autoconf Makefile.am open OUT, ">$makefiles{'am'}"; select OUT; @@ -1190,26 +1344,25 @@ if (defined $makefiles{'am'}) { "#\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"; - @binprogs = (); + print $makefile_extra{'am_begin'} || ""; + + # All programs go in noinstprogs by default. If you want them + # installed anywhere else, you have to also add them to + # bin_PROGRAMS using '!begin am'. (Automake doesn't seem to mind + # having a program name in _both_ of bin_PROGRAMS and + # noinst_PROGRAMS.) @noinstprogs = (); foreach $p (&prognames("X:U")) { ($prog, $type) = split ",", $p; - if ("FIXME") { # decide which programs go where - push @binprogs, # FIXME "\$(BINPREFIX)" . - $prog; - } else { - push @noinstprogs, # FIXME "\$(BINPREFIX)" . - $prog; - } + push @noinstprogs, $prog; } - print &splitline(join " ", "bin_PROGRAMS", "=", @binprogs), "\n"; print &splitline(join " ", "noinst_PROGRAMS", "=", @noinstprogs), "\n"; %objtosrc = (); %amspeciallibs = (); %amlibobjname = (); %allsources = (); - foreach $d (&deps("X", undef, $dirpfx, "/", "am")) { + foreach $d (&deps("X", undef, "", "/", "am")) { my $obj = $d->{obj}; my $use_archive = 0; @@ -1222,6 +1375,7 @@ if (defined $makefiles{'am'}) { if (defined $cflags{'am'} && $cflags{'am'}->{$obj}) { # This file needs to go in an archive, so that we can # change the compile flags as specified in Recipe + $use_archive = 1; $archivecflags{$obj} = [$cflags{'am'}->{$obj}]; } if ($use_archive) { @@ -1234,6 +1388,10 @@ if (defined $makefiles{'am'}) { map { $allsources{$_} = 1 } @{$d->{deps}}; } + # 2014-02-22: as of automake-1.14 we begin to get complained at if + # we don't use this option + print "AUTOMAKE_OPTIONS = subdir-objects\n\n"; + # Complete list of source and header files. Not used by the # auto-generated parts of this makefile, but Recipe might like to # have it available as a variable so that mandatory-rebuild things @@ -1241,7 +1399,7 @@ if (defined $makefiles{'am'}) { print &splitline(join " ", "allsources", "=", sort {$a cmp $b} keys %allsources), "\n\n"; - @amcppflags = map {"-I$dirpfx$_"} @srcdirs; + @amcppflags = map {"-I\$(srcdir)/$_"} @srcdirs; print &splitline(join " ", "AM_CPPFLAGS", "=", @amcppflags, "\n"); @amcflags = ("\$(GTK_CFLAGS)", "\$(WARNINGOPTS)");