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

Add error message for invalid include! paths #368

Closed
wants to merge 3 commits into from
Closed

Add error message for invalid include! paths #368

wants to merge 3 commits into from

Conversation

Bromeon
Copy link
Contributor

@Bromeon Bromeon commented Oct 23, 2020

As promised in #367, here's the pull request for an error message when include! receives a path that it cannot handle. This is to avoid that such errors propagate further down and only fail at the C++ compile step (and was a reason I spend a lot of time debugging my cxx examples).

The logic is: path must begin with the configured include prefix (crate name by default) or must be an absolute path.

Remarks:

  1. There were multiple places where I could have added the verification, but I thought the parser is not a good idea, because what include! means depends on the user of the parser (can be an external crate such as autocxx). So I implemented it close to the bridge generation.
  2. In the parser, I now no longer skip include! statements, but integrate them with the Types struct and carry that information upward several levels.
  3. There are unit tests for the verify_include_dir() function, but I'm not sure what's the best location for them. I cannot move them to another crate without making the function under test public.
  4. For a similar reason I couldn't write any integration tests (testing the whole chain like in tests/cxx_gen.rs). I did some manual tests however. Probably you know much better how and where to add extra tests, if it's even necessary (this PR is primarily a quality-of-life/diagnostic improvement)

Extracts the used include paths in the parsing step, and propagates them up to the cxxbridge build, which performs the actual check.
@@ -28,6 +29,7 @@ impl<'a> Types<'a> {
let mut aliases = Map::new();
let mut untrusted = Map::new();
let mut explicit_impls = Set::new();
let mut include_dirs = UnorderedSet::new();
Copy link
Owner

Choose a reason for hiding this comment

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

This needs to be an ordered set because gen/src/mod.rs contains code that iterates over it. The only valid thing to do with an unordered set is testing for membership. Otherwise you end up with the code generator being nondeterministic which is never good.

}

// Include prefix is stored with backslashes under Windows -> very basic slash conversion (use path-slash for more sophisticated one)
panic!("include!(\"{}\") is invalid:\n path must either start with include prefix '{}' or be an absolute path.\n\n",
Copy link
Owner

Choose a reason for hiding this comment

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

This shouldn't requiring panicking the build script. It should report the error the same way that type errors are reported, which displays the line number and source line of code similar to rustc diagnostics.

@@ -298,7 +302,61 @@ fn generate_bridge(prj: &Project, build: &mut Build, rust_source_file: &Path) ->
Ok(())
}

// Ensures that the argument of the include!() macro is either starting with the crate name, or an absolute path
Copy link
Owner

Choose a reason for hiding this comment

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

I think this check is somewhat too strict. For example the caller's build script is free to make any other directories available here and that wouldn't be a problem. Using https://crates.io/crates/pkg-config this could be a common pattern:

let python3 = pkg_config::probe_library("python3")?;
cxx_build::bridge("src/bridge.rs")
    .includes(python3.include_paths)
    .compile("repro");
extern "C" {
    include("Python.h");
    ...
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Under that circumstance, would it even be possible to check extra include directories inside cxx?
We give the cc::Build object to the user and effectively lose control of how it's further configured.

Copy link
Owner

@dtolnay dtolnay left a comment

Choose a reason for hiding this comment

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

I ended up landing a more specific check for includes relative to . or .., since we know those are meaningless in the Cargo-based workflow because the positioning of the generated code inside of Cargo's OUT_DIR is not specified.

@Bromeon
Copy link
Contributor Author

Bromeon commented Oct 28, 2020

Okay.

Do you think the aggregation code I added in syntax/types.rs to collect all include! paths could still be used in the future (after I correct the set type)? As someone unfamiliar with the codebase, it took me a while to find the place to extract those. But we can of course add it only once it's really needed.

@dtolnay
Copy link
Owner

dtolnay commented Oct 28, 2020

Probably not. We do almost nothing with includes in this crate, and all of it is only iterating over them (to insert them into the output code). Iterating is easily done on only the syntax tree -- it doesn't require a more structured representation than that. The sets/maps in syntax/types.rs are for things where the generator needs to do more complicated lookup of type information.

cxx/gen/src/write.rs

Lines 25 to 29 in 353d98c

for api in apis {
if let Api::Include(include) = api {
out.include.insert(include);
}
}

@Bromeon
Copy link
Contributor Author

Bromeon commented Oct 28, 2020

Makes sense, thanks for the explanation! 🙂

@Bromeon Bromeon deleted the feature/include-error-message branch October 28, 2020 22:50
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.

2 participants