Page MenuHomePhabricator

[Clang][Driver] Don't pun -fuse-ld=lld as -fuse-ld=lld-link with msvc
Needs ReviewPublic

Authored by Ericson2314 on Nov 3 2019, 1:05 AM.

Details

Reviewers
ruiu
rnk
mstorsjo
Summary

Besides the Mingw toolchain, there is also the CrossWindows toolchain,
which means GNU-style cli but genuine windows headers + libraries. LLD's
MinGW driver is as good a fit as binutil's ld, but there is no easy way
to select it when lld was being rewritten to lld-link.

This makes lld always be the GNU-style one, consistent with the non-msvc
case. It's a small breaking change for Windows, but the only
straightforward way.

It may seem silly to worry about the gnu-style flags, but it is useful
for mixing software designed with MinGW in mind with "real" windows
software that needs a MSVC C++ ABI, C++ threads, etc.

Testing in conjunction with https://github.com/NixOS/nixpkgs/pull/72366,
which might be the first fully automated way to cross compile to
Windows. I haven't taught Nixpkgs to wrap clang-cl like it wraps clang,
so even for some packages that have separate MSVC and MinGW builds
systems (e.g. zlib, opensll), I seem to be having better luck with the
MinGW-style builds so am going with that.

Event Timeline

Ericson2314 created this revision.Nov 3 2019, 1:05 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptNov 3 2019, 1:05 AM
Ericson2314 retitled this revision from [LLD][MinGW] Support --allow-multiple-definition to Better clang cross windows with gnu-style flags.Nov 3 2019, 1:25 AM
Ericson2314 edited the summary of this revision. (Show Details)
Ericson2314 retitled this revision from Better clang cross windows with gnu-style flags to Clang][Driver] Don't pun -fuse-ld=lld as -fuse-ld=lld-link with msvc.
Ericson2314 edited the summary of this revision. (Show Details)

Split out some changes into other diffs. 1 we are stacked on, the other 2 are independent and not stacked on,

Ericson2314 retitled this revision from Clang][Driver] Don't pun -fuse-ld=lld as -fuse-ld=lld-link with msvc to [Clang][Driver] Don't pun -fuse-ld=lld as -fuse-ld=lld-link with msvc.Nov 3 2019, 9:15 AM

I'm not familiar with where/how the CrossWindows toolchain is used, but you say (and the code seems to agree) that it's intended to be able to use ld.bfd for linking code built for the MSVC ABI with MSVC/WinSDK libs? I'm surprised that even works at all (or does it, or is it just set up and tested for minimal cases and then unused?), as ld.bfd lacks support for a lot of COFF specific features that MSVC ABI uses (which probably can be worked around with --allow-multiple-definitions for some bits at least, but I'm not confident that it generally would work even with that).

I presume all of this is about how to call the linker, as compiling with clang -target <arch>-windows-msvc, using the MSVC toolchain, should work just fine?

I think a better distinguisher would be whether clang was invoked as clang[++] or clang-cl (i.e. driver mode). Normally when linking MSVC style, the build system would call link (or the link-like tool) with the linker flags directly. Occasionally one could be linking via the cl frontend, as cl obj1.obj obj2.obj -Feout.exe somelib.lib -link -linkpath:some/path -other_link_style_option.

Now when doing linking via the clang GCC-style driver, clang obj1.obj obj2.obj -o out.exe -lsomelib -Lsome/path -Wl,--other-unix-linker-option, one expects to use unix linking style flags. Hypothesis: There's no predecent for actually using an MSVC link-style linker via this syntax. Or is there?

If there isn't, we could make that the distinguishing factor instead.

The same issue has come up for build systems (meson tried to tackle this recently, don't remember how/if they did yet), when just invoking "clang" on a windows platform (instead of intentionally e.g. "clang-cl"), not knowing whether the implicit default triple is an msvc or mingw triple, which means they don't know in what form to pass linker options. For cross cases where there's an explicit -target option, this are slightly clearer (at least from some perspectives), but with the default target, you're really working blindly.

rnk added a comment.Nov 5 2019, 10:00 AM

I think a better distinguisher would be whether clang was invoked as clang[++] or clang-cl (i.e. driver mode).

I think Martin said most of what I wanted to say. Making this dependent on the driver mode seems reasonable and would be the easier way forward.

If you still want to make clang-cl -fuse-ld=lld call ld.lld with gnu-style flags, you will need to pre-fix the various in-tree test suites. If you look through the LLDB, compiler-rt, and debuginfo-tests test suites, you will see many instances of -fuse-ld=lld that rely on the current behavior. See cases like:
https://github.com/llvm/llvm-project/blob/dd0c00b5f8b303f78565ab407d37a643e99a9e75/compiler-rt/test/asan/lit.cfg.py#L96
Maybe that case in particular doesn't apply, but it needs to be looked into.

We currently do cross builds of chrome/win on linux, and this breaks that.

As far as I know, no linker other than lld-link is able to write PDB files, so when targeting windows-msvc we definitely shouldn't change the current behavior. I don't have an opinion on windows-mingw.

We currently do cross builds of chrome/win on linux, and this breaks that.

As far as I know, no linker other than lld-link is able to write PDB files, so when targeting windows-msvc we definitely shouldn't change the current behavior. I don't have an opinion on windows-mingw.

Actually, we don't call the linker through the compiler driver when targeting Windows, so this doesn't break our cross build. I manually use clang-cl -fuse-ld=lld often though, so it'd make me type a lot more :)

hans added a subscriber: hans.Nov 6 2019, 4:40 AM

We currently do cross builds of chrome/win on linux, and this breaks that.

As far as I know, no linker other than lld-link is able to write PDB files, so when targeting windows-msvc we definitely shouldn't change the current behavior. I don't have an opinion on windows-mingw.

Actually, we don't call the linker through the compiler driver when targeting Windows, so this doesn't break our cross build. I manually use clang-cl -fuse-ld=lld often though, so it'd make me type a lot more :)

IIUC, with Martin and Reid's suggestion to key this off the driver mode rather than the triple, "clang-cl -fuse-ld=lld" would still work though? I like that approach as well.

While I am fine making -fuse-ld=lld mean "use that lld driver most appropriate for the clang driver", in principle the clang driver and lld driver choices are orthogonal, and I'd want to expose that with something like -fuse-ld=ld.lld to compliment -fuse-ld=lld-link. How does that sound? Should we support -fuse-ld=ld.bfd and -fuse-ld=ld64.lld too?

Ericson2314 abandoned this revision.Fri, Nov 8, 2:07 PM
This comment was removed by Ericson2314.
Ericson2314 reclaimed this revision.Fri, Nov 8, 2:07 PM
This comment was removed by Ericson2314.

While I am fine making -fuse-ld=lld mean "use that lld driver most appropriate for the clang driver", in principle the clang driver and lld driver choices are orthogonal

In principle, but as ld.lld and lld-link uses different syntaxes that only really are handled correctly if passed through from the gcc and cl drivers respectively, I find it mostly theoretical to want to use them in the opposite combination forms. (Additionally, in practice, people using the cl driver in many cases call (lld-)link directly as it requires very little boilerplate options, contrary to unix style environments where one is supposed to pass in paths to crt2.o and crtbegin.o and the builtins library, etc. So if one wants to use a link style linker it's in most cases easiest to just call it directly instead of using the $CC frontend.)

and I'd want to expose that with something like -fuse-ld=ld.lld to compliment -fuse-ld=lld-link.

I don't mind adding these two cases as explicit overrides over the generic logic

How does that sound? Should we support -fuse-ld=ld.bfd and -fuse-ld=ld64.lld too?

I don't see where you'd need those? -fuse-ld=bfd should pick ld.bfd in most cases, right? In which case wouldn't it? The mapping between parameter name to -fuse-ld and system linker naming scheme varies a bit between the platforms, and I'd presume the other existing toolchains in clang does this right as it is right now. Or can you clarify and elaborate in which cases you'd want to use them?