Skip to content

Trying to -fuse-ld with swiftly's ld.lld proxy causes circular invocation #272

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

Open
ADKaster opened this issue Mar 29, 2025 · 8 comments
Open

Comments

@ADKaster
Copy link

ADKaster commented Mar 29, 2025

It's impossible to use swiftly's lld with -fuse-ld on Ubuntu 24.04

$ /home/andrew/.local/clang -Wl,--version -fuse-ld=/home/andrew/.local/bin/ld.lld
Circular swiftly proxy invocation
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Passing in the lld as distributed by apt.llvm.org works fine:

$ /home/andrew/.local/bin/clang -Wl,--version -fuse-ld=/usr/bin/ld.lld
Ubuntu LLD 18.1.3 (compatible with GNU linkers)

Invoking swiftly's ld.lld proxy directly works as well

$ ld.lld --version
LLD 17.0.0 (https://github.com/swiftlang/llvm-project.git 62b5a0f34622c567cd5716c05319efbe67596104) (compatible with GNU linkers)
@ADKaster
Copy link
Author

ADKaster commented Mar 29, 2025

After some more testing, it seems that in CMake, CMAKE_LINKER_TYPE=LLD (from CMake 3.29) will always pass -fuse-ld=lld to clang or -use-ld=lld to swiftc. -- both of those work.

However, this originally came up with a third-party meson configure via vcpkg inside a CI runner, which ends up passing the full path to the linker.

I'm not quite sure how it ended up selecting the ld.lld version from the swiftly toolchain, because on my local machine it always picks /usr/bin/ld.lld, but that's what https://github.com/microsoft/vcpkg/blob/master/scripts/cmake/vcpkg_configure_meson.cmake ends up doing -- giving the full path to the linker to -fuse-ld.

@cmcgee1024
Copy link
Member

Thanks for raising this.

There are some ideas about how the circularity error could make it easier to pinpoint how it happens. For example, maybe the internal environment variable could keep a PID, and the error might dump both process' argv and env. Do you think that would help track down this problem?

@ADKaster
Copy link
Author

Well, I suppose a better way to frame my issue is that I'd prefer that that this "just works ™ ". While it's not particularly standard to use a full path in -fuse-ld, it does seem like clang supports it just fine for other linkers.

I could go poking around in the vcpkg wrapper for meson builds and try to see why it's normalizing the path to the system linker. A "portable" final command line might look more like -fuse-ld=lld -B $SWIFTLY_BIN_DIR.

Is there a good place to look in the swiftly code for why a "circular proxy invocation" needs to be a fatal error? Even if invoked for two different tools?

@cmcgee1024
Copy link
Member

@ADKaster the circular proxy invocation is a fatal error to avoid process bombing a system. Maybe the check needs to be more sophisticated, but that's the reasoning.

@ADKaster
Copy link
Author

It seems that the reason this happens in my vcpkg config is related to the vcpkg-get-cmake-vars utility package:

https://github.com/microsoft/vcpkg/blob/master/ports/vcpkg-cmake-get-vars/cmake_get_vars/CMakeLists.txt#L239

Whenever a port needs to extract information such as the compiler, the linker, the archiver, or other implicit information to pass on to a non-cmake build system, it will use this get-cmake-vars function to write those variables to disk for later extraction and input into the foreign build system.

It's simply bad luck that the first case I ran into was the vcpkg-tool-meson one, where the meson tool writes an argument file that essentially does meson_c_ld = $CMAKE_LINKER and meson_cxx_ld = $CMAKE_LINKER.

It seems that CMake itself normalizes the path to CMAKE_LINKER, which is a private cmake_toolchains(7) variable.

@ADKaster
Copy link
Author

If there's no clear way to make the proxy sometimes accept circular arguments, then in order to keep using swiftly toolchains for my project I'll need some way to work around this limitation with full paths to -fuse-ld.

Is there a way to add a command to like, print the current toolchain bin dir? If I use the paths to binaries that are directly in the toolchain dir as CMAKE_C_COMPILER/CMAKE_CXX_COMPILER, then they don't have the proxy wrapping them, and have symlinks as I would expect from an install of llvm and friends.

I suppose this is a special case where the pre-proxy behavior was desirable, as it simply created symlinks into the real toolchain directory.

@cmcgee1024
Copy link
Member

@ADKaster a workaround for now might be to ask swiftly where the currently in-use toolchain is located:

swiftly use --print-location

And then construct a PATH without swiftly, and just this path entry in it.

@ADKaster
Copy link
Author

Ah! I'm not sure how I missed that option. I prototyped up a CMake disaster using clang --print-prog-name that seems to work. Using that path from swiftly use should make things a lot less messy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants