-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Prefer lld in NativeAot when using clang #85478
Conversation
This detects availability of lld and prefers it, when using clang. If not found, falls back on bfd as before.
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Build is failing with invalid linker name in argument '-fuse-ld=bfd'
Also use CppCompilerAndLinker to match existing pattern
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise LGTM, assuming we will add lld
to the prerequisite docs: https://learn.microsoft.com/en-us/dotnet/core/deploying/native-aot/#prerequisites
@@ -180,11 +178,21 @@ The .NET Foundation licenses this file to you under the MIT license. | |||
<Error Condition="'$(_WhereLinker)' != '0' and '$(CppCompilerAndLinkerAlternative)' == '' and '$(_IsApplePlatform)' != 'true'" | |||
Text="Requested linker ('$(CppLinker)') not found in PATH." /> | |||
|
|||
<Exec Command=""$(CppLinker)" -fuse-ld=lld -Wl,--version" Condition="'$(LinkerFlavor)' == 'lld'" IgnoreExitCode="true" StandardOutputImportance="Low" ConsoleToMSBuild="true"> | |||
<Exec Command=""$(CppLinker)" -fuse-ld=lld -Wl,--version" Condition="'$(LinkerFlavor)' == 'lld' or ('$(LinkerFlavor)' == '' and $(CppCompilerAndLinker.Contains('clang')))" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
<Exec Command=""$(CppLinker)" -fuse-ld=lld -Wl,--version" Condition="'$(LinkerFlavor)' == 'lld' or ('$(LinkerFlavor)' == '' and $(CppCompilerAndLinker.Contains('clang')))" | |
<Exec Command=""$(CppLinker)" -fuse-ld=lld -Wl,--version" Condition="'$(LinkerFlavor)' == 'lld'" IgnoreExitCode="true" StandardOutputImportance="Low" ConsoleToMSBuild="true"> |
Revert this line: this is not correct. Before we were checking the --version regardless of LinkerFlavor emptiness. Which means FreeBSD and user-supplied -p:LinkkerFlavor cases were also considered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're still checking the version when LinkerFlavor
is lld
, like before, whether user-supplied or due to the FreeBSD default above. Maybe I'm missing something - could you give an example?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When LinkerFlavor
is lld
, we will always check the version. Which means _LinkerVersion
can't be empty if lld
exists and changes made in src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
are not needed, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible that LinkerFlavor
is lld
, but lld
did not exist - then _LinkerVersion
is empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then it will result in error one way or the other with fuse-ld=<non-existing-flavor>
. We shouldn't be checking for emptiness.
fuse-ld
is even sensitive to version. Try apt install clang-13 lld-14
and fuse-ld=lld
will fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that if we try to compare versions against an empty string, the build fails at that comparison:
A numeric comparison was attempted on "$(_LinkerVersion)" that evaluates to "" instead of a number, in condition "'$(LinkerFlavor)' == 'lld' and '$(_LinkerVersion)' > '12'"
This looks like an error in the build logic, whereas failing on the invocation with:
clang : error : invalid linker name in argument '-fuse-ld=lld
gives a clearer indication of what's wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, revert changes in this file.
My assumption was that it comes by default with clang, no? |
Nope, |
Ok, I have not realized that lld does not come with clang by default. It means that lld is an optional light-up. If it is available, we will use it. If it is not available, we are happy to fallback to bfd silently (bfd is pretty much guaranteed to be available because of it comes as a dependency of clang). llvm-objdump is on the same plan. If it is available, we will use it. If it is not available, we will be happy to fallback to objdump silently (again, objdump is pretty much guaranteed to be available because of it comes as a dependency of clang). Including both lld and llvm-objdump in the instructions would make sense then. I am wondering whether we should print something to the console when we use the fallback silently to make it clear that we prefer llvm-based tools. I can be useful for troubleshooting. Or even change the fallback to be explicit to make sure that people are not building with the less preferred tools by accident. |
This is similar to the optional light-up we have for clang, where if clang isn't installed, we will silently fall back on gcc if it's available. Personally I would prefer the approach of defining our preferred tools, and requiring some explicit user action to take a different path - it makes things more predictable. |
Yes, especially given that there are 3 different packages that one has to install to get the preferred tools for out-of-the-box experience. It was just one package ( |
Yes, they have similarities. The difference is that runtime/eng/native/configuretools.cmake Lines 24 to 71 in 4719575
That is quite robust but implementing that in MSBuild without cmake dependency is non-trivial work. |
It looks like installing |
If you can "apt-get install llvm" that will add version-less alias for llvm-objdump. |
Good to know - that seems to work on ubuntu 20.04 - but not 18.04. On 18.04 I get |
On Alpine, |
Also, lld is only available since version 7, while on 18.04 the default |
This sounds like a very complicated matrix. Do we really want to change these defaults? |
Hmm, we are exposed to it already. So trying to auto-detected what is on the box is about the best that we can do. |
Agreed. I don't have a strong opinion on what should be the default, but I think there should at least be an easy way to predictably use llvm tools. If we support Ubuntu 18.04 then I think that means we need to at least detect version of llvm-objcopy matching clang, and possibly detect higher versions of installed clang. |
Actually, to avoid version-based detection in MSBuild, could we consider Ubuntu 18.04 to have degraded support, and require more steps from the user (ask them either to symlink Then on Ubuntu 20.04 and Alpine 3.15 we can just update steps to recommend installing |
init-compiler.sh is tied to dotnet/runtime engineering infrastructure. It lives in arcade repo and it is not meant to be a shipping artifact. I would hope that we can land on something simpler for the linker detection than hundred lines shell script. I like the default experience today: Install clang, the rest just works, the implementation is not that complicated. It feels we are trying to complicate it quite a bit. |
To address the problem with bfd linker not being available in our cross-build containers, can we set |
Yes, solving this in the runtime build only should be easy enough, and doesn't need to complicate the shipping logic. The reason I was changing the product layer is that there was a desire to make the shipping defaults more similar to what we use in the runtime build. But we haven't landed on a tradeoff we like (since it requires extra install steps and/or more complicated detection logic). @jkotas I think you were on board with making
For 2. I think we could solve it with a little extra detection logic if necessary. But detecting higher Ubuntu 18.04 goes out of standard support the end of this month. I would like it if we could choose defaults that match what we do in our builds, and what makes most sense on more recent platforms. I think it would be reasonable to document some extra steps needed to work around those issues on 18.04. The workaround would look something like:
If that is too much to ask of users, then maybe we should live with the fall-back that doesn't require any user action. It has worked well enough for |
Yes, I have not realized that it will require installing additional packages and expose us to potential version mismatches. I think it is likely problematic on more than just Ubuntu 18. Every other distro seems to have their own tweaks on how the explicitly versioned binaries are setup, and it varies over time. With these insights, I think it is better to lean on the standard config by default that should be simple, and allow people to manually override when it does not work. |
Hmm, I thought I commented on this issue, but I don't see it. I must have forgot to submit. I've been thinking about the matrix here and it seems like, no matter what, we're going to have to be compatible with a variety of different linkers. Even if we ignore lld/bfd, we have to support ld64, the Mac linker. That means we're always going to be in a bit of a passive position of adapting to the system requirements. Given that, it seems like we should roll with whatever the user has on the machine. Preference for one linker over another seems mostly academic, since it's unlikely that we'll get the exact same version of a linker we test with, regardless of which linker we choose. This also seems to be necessary since we want to be on the latest linker version in our official builds for fixes and patches, but most Linux distros ship with very old versions of the linkers. So, no matter what we choose we probably won't be running on something we explicitly tested. In that case, I wouldn't provide a warning if we run with something other than our preferred linker, I would at most produce some sort of diagnostic message, like the "Generating native code" message that's output during Native AOT publish. |
Closing this since we are going with the existing defaults that are more likely to work on the most common linux distros - so |
This detects availability of lld and prefers it, when using clang. If not found, falls back on bfd as before, as discussed in #84794. Fixes #84934.