Skip to content
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

Hardcode path to librustc_driver.so in bevy_lint_driver for dynamic linking #66

Closed
wants to merge 2 commits into from

Conversation

BD103
Copy link
Member

@BD103 BD103 commented Sep 9, 2024

For a story-driven rant on how I came across this solution, see this chain of posts.


Hi! I spent a lot of my time drafting #32 trying to fix bevy_lint_driver's linking issues, but I've finally found a solution that works most of the time.

The problem

bevy_lint_driver, the program that actually registers the lints into the compiler, dynamically links to librustc_driver-*.so. This is perfectly fine with running it through Cargo and the RUSTC_WORKSPACE_WRAPPER environmental variable, but falls apart when run by itself.

Namely, calling ./target/debug/bevy_lint_driver directly fails with a dynamic linking error:

$ ./target/debug/bevy_lint_driver 
dyld[88854]: Library not loaded: @rpath/librustc_driver-a8e6b68b3c38c57d.dylib
  Referenced from: <72ACE28D-39EC-39CC-833A-92B4F3AC0DF5> ./target/debug/bevy_lint_driver
  Reason: no LC_RPATH's found
Abort trap: 6

When running it through Cargo, it sets the LD_LIBRARY_PATH variable so that the dynamic linker can discover librustc_driver.so. This variable is present, unfortunately, when running it alone.

This becomes a problem for two of my use-cases of the driver:

  1. Debugging it using LLDB. rustc is a new codebase that I've never worked on before, I'm using a debugger to figure out what code gets run.
  2. Running UI tests. ui_test calls rustc directly, not cargo, so I need to configure it to call bevy_lint_driver directly. See the problem?

While it is theoretically possible to set LD_LIBRARY_PATH for both of these, I struggled to get either of them to work. If you manage to do so, please let me know!

The solution

It is possible to hardcode a dynamic linker search path using the -rpath linker flag. To do this, I created a build script that uses rustup to locate librustc_driver.so and emit the proper flags. It only runs upon first run and whenever build.rs is changed, so this is really cheap for incremental builds.

I heavily commented the entire thing, so take a look! The two biggest drawbacks to this approach are:

  1. The hardcoded path is not portable, since it references the name of the user's home directory. (E.g. it hardcodes /Users/appleseedj/... into the produced binary.)
  2. The produced binary still requires the pinned nightly toolchain to be installed.

I'm willing to accept these costs for the time being, as it means I will actually be able to start writing lints and stop finnicking with old and complicated linker details.

Testing

This should be generally platform-compatible, but I will need help testing this. It works on:

  • MacOS
  • Linux (I can test this later today)
  • Windows (I'll need someone else to test this)

To test, please run:

$ cargo clean
$ cargo build -p bevy_lint
$ ./target/debug/bevy_lint_driver

It should print a help screen if everything worked correctly. If it didn't, please paste the error message and I'll try figuring out what went wrong. Thanks!

In the future

I hope for this solution to be temporary. In the future I want to build rustc_driver from scratch when release mode is enabled, so that the outputted binary is truly portable. That's for another PR, though!

@BD103 BD103 added A-Linter Related to the linter and custom lints C-Bug A bug in the program labels Sep 9, 2024
@bas-ie
Copy link
Collaborator

bas-ie commented Sep 9, 2024

Linux checked and working ✔️

@janhohenheim
Copy link
Member

janhohenheim commented Sep 9, 2024

Not working on Windows:
image

This is my target/debug dir:
image

@BD103
Copy link
Member Author

BD103 commented Sep 10, 2024

After lots of research, turns out this isn't necessary for dev builds. All you need to do is run rustup run nightly-2024-08-21 ./target/debug/bevy_lint_driver, and it will automatically handle all of the environment setup. Closing!

@BD103 BD103 closed this Sep 10, 2024
@BD103 BD103 deleted the rpath-fix branch September 10, 2024 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Linter Related to the linter and custom lints C-Bug A bug in the program
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants