From f02587f7ac4f47982bf97674f5499dd3b6dede4b Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Thu, 25 May 2017 08:21:19 +0100 Subject: [PATCH] Makefile.clangcl: provide a way to tell lld-link about crt0.obj. I've been experimenting with using clang-cl with older versions of the Visual Studio libraries and headers, and found that the older VS libraries have a quirk which can cause link failure in a way that doesn't happen with the newer one. I assume the corresponding old VS linker must be doing some kind of special-case handling that lld isn't mimicking. The quirk arises because lld tries to pull in more than one of the *crt0.obj startup objects which set things up before calling main or WinMain (or whatever), and those objects define some of the same symbols as each other. The fix is to explicitly ask for the right one of those objects on the link command line, so that it's already been loaded _before_ the linker starts searching libraries for unresolved symbols; then the disputed symbols are never unresolved in the first place during the library search phase. But this means you have to pick your crt0 object differently depending on which subsystem you're compiling for. Accordingly, here's an extra feature in Makefile.clangcl to make that possible by means of the right definitions on the make command line. --- mkfiles.pl | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/mkfiles.pl b/mkfiles.pl index 8a63c65dc..1d83912bd 100755 --- a/mkfiles.pl +++ b/mkfiles.pl @@ -492,6 +492,31 @@ sub manpages { # 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 @@ -539,7 +564,8 @@ sub manpages { print &splitline("\t\$(LD) \$(LFLAGS) \$(XLFLAGS) ". "/out:\$(BUILDDIR)$prog.exe ". "/lldmap:\$(BUILDDIR)$prog.map ". - "/subsystem:$subsys\$(SUBSYSVER) $objstr")."\n\n"; + "/subsystem:$subsys\$(SUBSYSVER) ". + "\$(EXTRA_$subsys) $objstr")."\n\n"; } foreach $d (&deps("\$(BUILDDIR)X.obj", "\$(BUILDDIR)X.res.o", $dirpfx, "/", "vc")) { $extradeps = $forceobj{$d->{obj_orig}} ? ["*.c","*.h","*.rc"] : [];