-
-
Notifications
You must be signed in to change notification settings - Fork 640
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
[WIP] Support for rust #7260
[WIP] Support for rust #7260
Conversation
This is very awesome to see: thank you @Robert-Steiner! Reviewing it will likely take considerable time, but when you believe that you have an MVP (doesn't need to be perfect, but would be unlikely to require a fundamental overhaul of BUILD files or Options values to fix), please let us know and we'll review as soon as possible! Of the TODOs listed in the description, I think that only:
...is likely to be a blocker for landing. |
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.
Wow, thank you!
I took a quick glance over this for small style and Python 3 compatibility changes. Didn't check correctness at this point, as it seems you're still iterating on this.
contrib/rust/src/python/pants/contrib/rust/tasks/cargo_toolchain.py
Outdated
Show resolved
Hide resolved
contrib/rust/src/python/pants/contrib/rust/tasks/cargo_toolchain.py
Outdated
Show resolved
Hide resolved
contrib/rust/src/python/pants/contrib/rust/utils/basic_invocation_conversion_rules.py
Outdated
Show resolved
Hide resolved
- moved workspace methods to the workspace class
- replaced dict with array
- added tests for build output parsing functions - fixed year in headers - fixed parsing of `rustc-flags` ([can be a set of flags](https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script))
You hit one flaky test in CI: have restarted it. |
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.
Thanks a huge amount for this patch: it already looks really great, and I expect that:
- adding the examples
- applying a bit of review feedback
- addressing the future of
--build-plan
will be sufficient to get it landable.
Regarding one of the limitations you mentioned in the description:
- requires cargo nightly (because of the usage of the option
--build-plan
)
Is this feature on track to be stabilized? Is it risky to depend on it? Is it likely to be maintained?
contrib/rust/src/python/pants/contrib/rust/tasks/cargo_binary.py
Outdated
Show resolved
Hide resolved
contrib/rust/src/python/pants/contrib/rust/tasks/cargo_binary.py
Outdated
Show resolved
Hide resolved
|
||
cmd = ['cargo', 'build', | ||
'--manifest-path', abs_manifest_path, | ||
'--build-plan', '-Z', 'unstable-options'] |
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.
Would you mind adding a reference to the upstream issues/prs that introduced/will-stabilize this feature?
contrib/rust/src/python/pants/contrib/rust/tasks/cargo_build.py
Outdated
Show resolved
Hide resolved
@staticmethod | ||
def is_cargo_synthetic_binary(target): | ||
return isinstance(target, CargoSyntheticBinary) | ||
|
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.
My feeling is that the is_X
methods might actually obscure things a little bit here. I would recommend inlining all of them, and waiting to reintroduce them until they are either used to represent a union of multiple parent classes... or, at that point, choosing to change the class hierarchy by introducing a mixin or other parent class instead.
register( | ||
'--toolchain', | ||
type=str, | ||
default=None, |
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.
This should probably have a fixed default value to encourage build determinism. For now, it sounds like it would need to be a particular nightly sometime past nightly-2018-12-31
. Once the --build-plan
feature has landed, could swap it to a particular stable release.
It's just a default, and would want the docs to recommend overriding it. But important to have a stable default to minimize surprises.
contrib/rust/src/python/pants/contrib/rust/tasks/cargo_toolchain.py
Outdated
Show resolved
Hide resolved
contrib/rust/src/python/pants/contrib/rust/tasks/cargo_toolchain.py
Outdated
Show resolved
Hide resolved
contrib/rust/tests/python/pants_test/contrib/rust/utils/test_custom_build_output_parsing.py
Show resolved
Hide resolved
Reference to cargo's build plan generation: rust-lang/cargo#5579 |
- member names and paths are automatically resolved by interpreting the workspace manifest - the list of member names in the BUILD file is no longer necessary
Thanks @stuhood for your feedback. Before this pr is ready I would like to complete two tasks. First, I would like to add support for single cargo binary/library crates, so a user doesn't have to create a workspace to build a single crate. |
- binary and library targets aren’t enabled yet - refactored target class hierarchy
@stuhood is there a way to define a 3rd party library that is only used by this plugin? The CI is failing because I use the toml library in my cargo_workspace target. I defined the library in 3rdparty/python/requirements.txt. The library will be installed during the bootstrap process but it isn't included in the |
- the toolchain can be defined in `pants.ini` Example ``` [bootstrap.cargo] toolchain: nightly-2018-12-31 ``` - the value can be a name or a path to a rust-toolchain file - the default value is `nightly-2018-12-31` - removed the toolchain path in the cargo_workspace target
Adding it to |
- added examples for binary, library and workspace targets
Right, I've already added the dependency in |
Gotcha. Yea, there are at least 3 execution modes for pants (from-source in a venv, a directly-built local pex, wheels-into-pex, etc)... I believe that under the "local pex" mode, it does make sense to actually declare the dep on the rust contrib module. I'll go ahead and make this edit to save you some CI time. |
- removed duplicate log message
- switched default toolchain to explicit toolchain to have the highest precedence - CI tests failed because the `rust-toolchain` file overwrote the default toolchain - [More information about the toolchain override precedence](https://github.com/rust-lang/rustup.rs#override-precedence)
- made the fingerprint of the rustup install script configurable via the option `--script_fingerprint` - the rustup install script is only downloaded once and stored in `<versioned_workdir>/rustup_install_script/rustup.sh` - the task tries to find the executable of rustup in the default location `~/.cargo/bin` if the task can’t find the executable via the `PATH` variable
- fixed AttributeError for self.LAST_KNOWN_FINGERPRINT
To build always valid binaries, the compile task implements a simple solution to support `cargo:rerun-if-env-changed` and `cargo:rerun-if-changed` statements. If a build script target contains a `cargo:rerun-if-env-changed` or `cargo:rerun-if-changed` statement, the compile task marks that target and its dependent targets as invalid. The task itself doesn’t actually check if an environment variable or a file has changed.
- to have no duplicate paths in make_dirs and make_sym_links
- Cancel the execution of pants if the execution of a subprocess call in the tasks `fetch`, `build` or `bootstrap` fails. - Show `std_out` and `std_err` if the execution of a build script fails. - fixed a bug in program_rule (multiple targets may depend on a build script)
- libraries of the kind `rlib`, `dylib`, and `staticlib` are now supported - removed the `CargoSyntheticProcMacro` target - cargo libraries of the kind `proc-marco` are now treated as `CargoSyntheticLibrary` - replaced the workunit outcome with the return code - removed the logging of the workunit outcome - added the env variables of a test invocation to the `rust_test` product (if the `DYLD_LIBRARY_PATH` is missing, the proc-macro test will fail)
- added build, fetch integration tests - added build, workspace tests - refactored basic, custom build rules to reduce code duplications - added build_flags fingerprint strategy (additional cargo options such as `release` or `test` are now taken into account in the fingerprint) - added additional examples - removed cargo lock files in rust examples - changed dist path of libraries and binaries from `dist/lib`, `dist/bin` to `dist/rust/lib`, `dist/rust/bin` - the way in which the fingerprint of a crate is calculated has been changed to prevent crates from being compiled multiple times
Very excited for this work! Please let us know when you're ready for another round of review. |
@stuhood I think the plugin is now in good state to be reviewed. I will add the README for this plugin next week. |
Thank you! I'll try to take a look this weekend. |
Hey @Robert-Steiner : really sorry: I didn't get time to look this weekend. Will try again tomorrow night. Thank you again for the patch! |
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.
Thank you Robert.
There is a huge amount to absorb here... I think that it is on the right track, but if possible, it would be great to defer any more-advanced cargo usage to a followup PR and focus on getting some basic documentation in place.
I'm very heartened by the thorough testing, so I think that once the docs are in place we should be able to look at landing this.
@classmethod | ||
def register_options(cls, register): | ||
super(Build, cls).register_options(register) | ||
register( |
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.
If these options affect the identity of the output (they probably do), they should be marked fingerprint=True
.
from pants.contrib.rust.tasks.cargo_task import CargoTask | ||
|
||
|
||
class Workspace(CargoTask): |
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.
If this class is intended to be abstract, it would be good to have it subclass AbstractClass
as well:
from pants.util.meta import AbstractClass
...
class NativeCompile(NativeTask, AbstractClass):
def get_member_sources_files(self, member_definition): | ||
_, path, include_sources = member_definition | ||
rglobs = RGlobs.to_filespec(include_sources, root=path) | ||
path_globs = [PathGlobsAndRoot( |
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.
To capture a Snapshot
at the buildroot, you should be able to skip the AndRoot
part here and request something like:
snapshot = self.context._scheduler.product_request(Snapshot, [PathGlobs(tuple(rglobs['globs']))])
...which has the advantage of being fully cachable.
':program_rule', | ||
] | ||
) | ||
|
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.
There is a huge amount to absorb in this PR... would it be possible to break out some of the more advanced features of the cargo support into a second PR? I'm commenting here just because I'm not sure I recognize "custom build invocations" (...are they build.rs
scripts?)
get_test_target_information) | ||
|
||
|
||
def get_default_conversion_rules(): |
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.
I don't think I understand the pattern behind the rules
that are exposed by basic_invocation
and custom_invocation
.
Are they intended to have the same shape (similar to two implementations of a trait/interface)? If so, should something enforce/signal that (ie: should they be in an interface)? If not, some comments to explain their composition would be helpful.
And did they start out as @rules
as in https://github.com/pantsbuild/pants/blob/master/src/python/pants/engine/README.md ? If so, would be interested to hear if you ran into trouble using that model, as we're still iterating on it, and feedback would be welcome.
Closing due to being stale. This is a great change, though, and we appreciate all the work you put into this @Robert-Steiner! For what it's worth, @cosmicexplorer has been drafting adding support for Rust through Pants' new V2 engine. @gshuflin is also looking into it. This PR will be quite helpful to both of them for sketching out what the API should look like. Please let us know also if you'd have any interest in contributing to that project :) we'd love the help. |
Problem
Pants doesn't support rust.
Solution
Creating a new contributor plugin that adds support for the rust language. Since cargo stores all compiled crates (including all dependencies) in one
target
directory, it isn't enough to write a thin wrapper around cargo and tell pants to cache the wholetarget
directory. Once you change a source file in one crate, it will compile and cache all crates again and not only the crate where the change was made. This plugin tries to solve this problem by creating a cache for each crate/dependency. It uses the cargo--build-plan
option as an initial point which outputs all invocations that cargo would do to compile a crate.Execution Flow
bootstrap
rustup
,rustc
andcargo
via the downloaded shell scriptPATH
ofcargo/bins
as the product of this taskresolve
pants.d/resolve/cargo/<version_dir>/cargo_home
and provides the path of cargo home as the product of this taskCargo.toml
manifest and stores them in path of cargo homecompile
--build-plan
binary
compile
task to the pants dist foldertest
compile
task to thepants.d/test/cargo/<version_dir>/
directory and executes themLimitations
only supports cargo workspaces--build-plan
)Building the rust pants engine
Since this plugin supports cargo workspaces you can compile the pants rust engine with it.
Steps:
if the environment variablesPROTOC
andPROTOC_INCLUDE
aren't set yet, set them first helpchange the content in./rust-toolchain
tonightly-2018-12-31
./src/rust/engine/BUILD
filepants.ini
fileAdditional cargo options can be specified in the
pants.ini
file:Example
TODO
fmt
,run
anddoc
rerun-if-changed
,rerun-if-env-changed
,rustc-env
Cargo.toml
file)