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

Symlink in the exec-root so that relative paths will work, unchanged. #1781

Merged
merged 4 commits into from
May 23, 2023

Conversation

freeformstu
Copy link
Contributor

@freeformstu freeformstu force-pushed the dev/symlink-exec-root branch 5 times, most recently from 1909efb to 0f6c5b1 Compare January 17, 2023 22:10
Copy link
Collaborator

@illicitonion illicitonion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty cute solution, thanks for putting it together!

Could you add add a test-case to https:/bazelbuild/rules_rust/tree/main/test/cargo_build_script which shows that this works, so that we don't break it in the future?

)
})?;

// Only symlink directories.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not symlink files too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's actually no reason not to symlink in files as well. I did not need it for my use case so I ignored it. I'll get file symlinks added in.

Copy link
Collaborator

@illicitonion illicitonion left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just some minor comments - thanks!

Comment on lines 66 to 68
.ok_or_else(|| "Failed while getting file name".to_string())?
.to_str()
.ok_or_else(|| "Failed while converting file name to string".to_string())?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.ok_or_else(|| "Failed while getting file name".to_string())?
.to_str()
.ok_or_else(|| "Failed while converting file name to string".to_string())?;
.ok_or_else(|| "Failed while getting file name".to_string())?;

You can use an OsString to Path::join

Comment on lines 78 to 79
name = "root_file",
out = "root_file.txt",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name = "root_file",
out = "root_file.txt",
name = "cargo_manifest_dir_file",
out = "cargo_manifest_dir_file.txt",

My first read of this in the build script assumed "root" meant "root of repo"

"Build script must be in the current directory"
);
assert!(
root_files.take("root_file.txt").is_some(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's assert on the contents too

@freeformstu
Copy link
Contributor Author

@illicitonion Apologies for the delay on this PR. I just addressed your comments - I'm still working through some windows test failures in this PR. I'll try to get those addressed by the end of this week.

Do you mind if I squash and rebase?

@illicitonion
Copy link
Collaborator

Thanks! Feel free to manage the branch however you want (rewrite history or add commits on top), and I'll squash + rebase into main whenever it's done :)

@xortive
Copy link
Contributor

xortive commented Feb 23, 2023

Hey @freeformstu @illicitonion! #1762 is a hard blocker for us to start using a custom toolchain with our bazel build. I've been using this PR's changes in a fork successfully and I'd love to see it merged. I'm willing to offer help in resolving the windows build problems if that makes things easier for y'all

Copy link
Collaborator

@UebelAndre UebelAndre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the failure here is caused by the Windows not actually having support for sandboxing. I don't have a windows box so it's kinda hard to confirm but reading https://bazel.build/versions/6.1.0/docs/sandboxing it seems to explicitly mention Linux and MacOS but not Windows which, in addition to the failure here, makes me think there's just no sandboxing. This is potentially a good find for the feature as we should make sure it works correctly with and without sandboxing.

@@ -53,6 +53,23 @@ fn run_buildrs() -> Result<(), String> {
create_dir_all(&out_dir_abs)
.unwrap_or_else(|_| panic!("Failed to make output directory: {:?}", out_dir_abs));

// Symlink the execroot to the manifest_dir so that we can use relative paths in the arguments.
let exec_root_paths = std::fs::read_dir(&exec_root)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I think the issue here is that when running outside of a sandbox there will actually be more files in this directory than expected. Instead of reading from the execroot, is there a MANIFEST file or something that tracks all inputs to an action? I forget if that's created for actions or just tests. The idea would be you can link only the things the build script has as an explicitly registered as an input.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like MANIFEST is only found in runfiles

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @UebelAndre! I can reproduce the issue locally with this diff now:

diff --git a/cargo/private/cargo_build_script.bzl b/cargo/private/cargo_build_script.bzl
index e567c1c5..3d1f4858 100644
--- a/cargo/private/cargo_build_script.bzl
+++ b/cargo/private/cargo_build_script.bzl
@@ -242,6 +242,9 @@ def _cargo_build_script_impl(ctx):
         mnemonic = "CargoBuildScriptRun",
         progress_message = "Running Cargo build script {}".format(pkg_name),
         env = env,
+        execution_requirements = {
+            "local": "",
+        }
     )
 
     return [

What do you think the behavior should be in this case? Should I just disable all of this logic if you're building outside of a bazel sandbox since that's the whole point of this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My most recent change updates the test to only assert that the execroot is empty if the test is running in a sandbox. This resolves almost all of the issues but now I have 3 remaining. One is definitely symlink related and the other two look unrelated but may be

Questions:

  1. Would it be acceptable to make this a feature which does not exist when running on Windows so that it can entirely avoid the windows symlinking issues?
  2. If that's not acceptable, would it be acceptable to make this feature opt-in (perhaps through an environment variable) so that consumers of this change can toggle it on where they see fit? That would give folks the ability to enable it for windows in the environments where they have symlinks enabled.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think making this a feature would be good. It can be disabled by default and enabled globally via --features in user's .bazelrc files. My experience is doing anything on windows is a bad idea 😅 but we should probably aim to keep the behavior consistent across operating systems.

@@ -53,6 +53,23 @@ fn run_buildrs() -> Result<(), String> {
create_dir_all(&out_dir_abs)
.unwrap_or_else(|_| panic!("Failed to make output directory: {:?}", out_dir_abs));

// Symlink the execroot to the manifest_dir so that we can use relative paths in the arguments.
let exec_root_paths = std::fs::read_dir(&exec_root)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think making this a feature would be good. It can be disabled by default and enabled globally via --features in user's .bazelrc files. My experience is doing anything on windows is a bad idea 😅 but we should probably aim to keep the behavior consistent across operating systems.

@freeformstu
Copy link
Contributor Author

freeformstu commented May 17, 2023

Now I just have ios and mac build issues which look like they're just generally broken (not due to my changes). @UebelAndre any recommendations here?

It's working now after rebasing on the latest changes.

Copy link
Collaborator

@UebelAndre UebelAndre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work! Just a few questions 😅

@@ -27,6 +27,7 @@ default_windows_targets: &default_windows_targets
- "-//bindgen/..."
- "-//test/proto/..."
- "-//test/unit/pipelined_compilation/..."
- "-//test/cargo_build_script:test_exec_root_access.build.feature_enabled"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you delete this in favor of a target_compatible_with flag on the target should you need it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes definitely!

@@ -3,6 +3,7 @@
load("@bazel_skylib//lib:paths.bzl", "paths")
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "CPP_COMPILE_ACTION_NAME", "C_COMPILE_ACTION_NAME")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("//cargo:features.bzl", "SYMLINK_EXEC_ROOT_FEATURE", "feature_enabled")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would this need to be a part of the public api vs living in //cargo/private?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can move it in there. I was thinking it would be useful to be able to load the constant in downstream repositories. But even in our repository we're just setting this feature in the .bazelrc so it doesn't add any value there.

I'll move it under //cargo/private.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds reasonable, but could you then move the feature_enabled logic into //cargo/private? Surely that doesn't seem necessary, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

@UebelAndre UebelAndre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work! Thank you so much!

@UebelAndre UebelAndre merged commit 94cbe4c into bazelbuild:main May 23, 2023
@dk333333
Copy link

dk333333 commented Jun 2, 2023

Hi @freeformstu apologies for the naive question, but how/where do I enable this feature? I had cherry picked an earlier commit but will need to enable it for real when upgrading. I checked the docs but could not find it there

Silcet pushed a commit to Silcet/rules_rust that referenced this pull request Jul 10, 2023
…bazelbuild#1781)

* Symlink in the exec-root so that relative paths will work, unchanged.

* Address feedback

* Address more feedback

* buildifier
Silcet pushed a commit to Silcet/rules_rust that referenced this pull request Jul 10, 2023
…bazelbuild#1781)

* Symlink in the exec-root so that relative paths will work, unchanged.

* Address feedback

* Address more feedback

* buildifier
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

Successfully merging this pull request may close these issues.

5 participants