From 2e229cb179ccb35d97160e92b6987b3073496b5f Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 5 Feb 2017 10:59:08 +0000 Subject: [PATCH] New makefile, for Windows cross-builds with clang-cl. This was very strange to write, because it's a bizarre combination of the GNU-make-isms and rc commands of Makefile.mgw with the cl and link commands of Makefile.vc (but also the latter thankfully doesn't need those horrible response files). I've added a big comment in mkfiles.pl about what the build requirements for this makefile actually are, which _hopefully_ will be usable by people other than me. --- .gitignore | 1 + Recipe | 9 ++++ mkfiles.pl | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 133 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 7da51392..15c253c2 100644 --- a/.gitignore +++ b/.gitignore @@ -127,6 +127,7 @@ /windows/*.tds /windows/*.td2 /windows/*.map +/windows/Makefile.clangcl /windows/Makefile.bor /windows/Makefile.mgw /windows/Makefile.vc diff --git a/Recipe b/Recipe index 6dc306fa..9d011f5a 100644 --- a/Recipe +++ b/Recipe @@ -12,6 +12,7 @@ # Overall project name. !name putty # Locations and types of output Makefiles. +!makefile clangcl windows/Makefile.clangcl !makefile vc windows/Makefile.vc !makefile vcproj windows/MSVC !makefile cygwin windows/Makefile.mgw @@ -147,6 +148,10 @@ endif CFLAGS = $(CFLAGS) /DHAS_GSSAPI !end +!begin clangcl vars +CFLAGS += /DHAS_GSSAPI +!end + # `make install' target for Unix. !begin gtk install: @@ -352,3 +357,7 @@ testbn : [C] testbn sshbn misc version conf tree234 winmisc LIBS cleantestprogs: -del $(BUILDDIR)testbn.exe !end +!begin clangcl +cleantestprogs: + -rm -f $(BUILDDIR)testbn.exe +!end diff --git a/mkfiles.pl b/mkfiles.pl index 1570f256..5b7ebc1d 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -269,7 +269,7 @@ sub mfval($) { # 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"; @@ -438,6 +438,128 @@ $orig_dir = cwd; # Now we're ready to output the actual Makefiles. +if (defined $makefiles{'clangcl'}) { + $dirpfx = &dirpfx($makefiles{'clangcl'}, "/"); + + ##-- Makefile for cross-compiling using clang-cl, lld-link, and + ## MinGW's windres for resource compilation. + # + # This makefile allows a complete Linux-based cross-compile, but + # using the real Visual Studio header files and libraries. In + # order to run it, you will need: + # + # - MinGW windres on your PATH. + # * On Ubuntu as of 16.04, you can apt-get install + # binutils-mingw-w64-x86-64 and binutils-mingw-w64-i686 + # which will provide (respectively) 64- and 32-bit versions, + # under the names to which RCCMD is defined below. + # - clang-cl and lld-link on your PATH. + # * I built these from the up-to-date LLVM project trunk git + # repositories, as of 2017-02-05. + # - case-mashed copies of the Visual Studio include directories. + # * On a real VS installation, run vcvars32.bat and look at + # the resulting value of %INCLUDE%. Take a full copy of each + # of those directories, and inside the copy, for each + # include file that has an uppercase letter in its name, + # make a lowercased symlink to it. Additionally, one of the + # directories will contain files called driverspecs.h and + # specstrings.h, and those will need symlinks called + # DriverSpecs.h and SpecStrings.h. + # * Now, on Linux, define the environment variable INCLUDE to + # be a list, separated by *semicolons* (in the Windows + # style), of those directories, but before all of them you + # must also include lib/clang/5.0.0/include from the clang + # installation area (which contains in particular a + # clang-compatible stdarg.h overriding the Visual Studio + # one). + # - similarly case-mashed copies of the library directories. + # * Again, on a real VS installation, run vcvars32 or + # vcvarsx86_amd64 (as appropriate), look at %LIB%, make a + # copy of each directory, and provide symlinks within that + # directory so that all the files can be opened as + # lowercase. + # * Then set LIB to be a semicolon-separated list of those + # directories (but you'll need to change which set of + # directories depending on whether you want to do a 32-bit + # or 64-bit build). + # - for a 64-bit build, set 'Platform=x64' in the environment as + # well, or else on the make command line. + # * This is a variable understood only by this makefile - none + # of the tools we invoke will know it - but it's consistent + # with the way the VS scripts like vcvarsx86_amd64.bat set + # things up, and since the environment has to change + # _anyway_ between 32- and 64-bit builds (different set of + # paths in $LIB) it's reasonable to have the choice of + # compilation target driven by another environment variable + # set in parallel with that one. + + open OUT, ">$makefiles{'clangcl'}"; select OUT; + print + "# Makefile for cross-compiling $project_name using clang-cl, lld-link,\n". + "# and MinGW's windres, using GNU make on Linux.\n". + "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". + "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; + print $help; + print + "\n". + "CCCMD = clang-cl\n". + "ifeq (\$(Platform),x64)\n". + "CCTARGET = x86_64-pc-windows-msvc18.0.0\n". + "RCCMD = x86_64-w64-mingw32-windres\n". + "else\n". + "CCTARGET = i386-pc-windows-msvc18.0.0\n". + "RCCMD = i686-w64-mingw32-windres\n". + "endif\n". + "CC = \$(CCCMD) --target=\$(CCTARGET)\n". + &splitline("RC = \$(RCCMD) --preprocessor=\$(CCCMD) ". + "--preprocessor-arg=/TC --preprocessor-arg=/E")."\n". + "LD = lld-link\n". + "\n". + "# C compilation flags\n". + &splitline("CFLAGS = /nologo /W3 /O1 " . + (join " ", map {"-I$dirpfx$_"} @srcdirs) . + " /D_WINDOWS /D_WIN32_WINDOWS=0x500 /DWINVER=0x500 ". + "/D_CRT_SECURE_NO_WARNINGS")."\n". + "LFLAGS = /incremental:no /dynamicbase /nxcompat\n". + &splitline("RCFLAGS = ".(join " ", map {"-I$dirpfx$_"} @srcdirs). + " -DWIN32 -D_WIN32 -DWINVER=0x0400")."\n". + "\n". + &def($makefile_extra{'clangcl'}->{'vars'}) . + "\n". + "\n"; + print &splitline("all:" . join "", map { " \$(BUILDDIR)$_.exe" } &progrealnames("G:C")); + print "\n\n"; + foreach $p (&prognames("G:C")) { + ($prog, $type) = split ",", $p; + $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", undef); + print &splitline("\$(BUILDDIR)$prog.exe: " . $objstr), "\n"; + + $objstr = &objects($p, "\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", "X.lib"); + $subsys = ($type eq "G") ? "windows" : "console"; + print &splitline("\t\$(LD) \$(LFLAGS) \$(XLFLAGS) ". + "/out:\$(BUILDDIR)$prog.exe ". + "/lldmap:\$(BUILDDIR)$prog.map ". + "/subsystem:$subsys\$(SUBSYSVER) $objstr")."\n\n"; + } + foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", $dirpfx, "/", "vc")) { + $extradeps = $forceobj{$d->{obj_orig}} ? ["*.c","*.h","*.rc"] : []; + print &splitline(sprintf("%s: %s", $d->{obj}, + join " ", @$extradeps, @{$d->{deps}})), "\n"; + if ($d->{obj} =~ /\.res\.o$/) { + print "\t\$(RC) \$(RCFLAGS) ".$d->{deps}->[0]." -o ".$d->{obj}."\n\n"; + } else { + print "\t\$(CC) /Fo\$(BUILDDIR) \$(COMPAT) \$(CFLAGS) \$(XFLAGS) /c \$<\n\n"; + } + } + print "\n"; + print &def($makefile_extra{'clangcl'}->{'end'}); + print "\nclean:\n". + &splitline("\trm -f \$(BUILDDIR)*.obj \$(BUILDDIR)*.exe ". + "\$(BUILDDIR)*.res.o \$(BUILDDIR)*.map ". + "\$(BUILDDIR)*.exe.manifest")."\n"; + select STDOUT; close OUT; +} + if (defined $makefiles{'cygwin'}) { $dirpfx = &dirpfx($makefiles{'cygwin'}, "/"); -- 2.45.1