Skip to content

Commit

Permalink
Makefile.clangcl: provide a way to tell lld-link about crt0.obj.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
sgtatham committed May 25, 2017
1 parent 8d2755c commit f02587f
Showing 1 changed file with 27 additions and 1 deletion.
28 changes: 27 additions & 1 deletion mkfiles.pl
Expand Up @@ -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
Expand Down Expand Up @@ -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"] : [];
Expand Down

0 comments on commit f02587f

Please sign in to comment.