Does anyone know of a tailor impl that generates m...
# development
g
Does anyone know of a tailor impl that generates multiple target for a single file? I was thinking about Rust again the other day, and a single Cargo.toml can expand to multiple binaries. So the regular owned/unowned set difference isn't enough to know whether more targets need to be added.
I realize the response to this is probably "use a target generator", but I think there's a simplicity in addressing and usage to just have targets in a file.
l
If tailor worked in this case, what would be the result? the creation of individual target entries (in BUILD) for each unowned binary mentioned in Cargo.toml, or would it create a target generator to mop up any binaries that haven't already been explicitly accounted for?
g
If we involve target generators there isn't any need for anything beyond
cargo_package
which maps to zero-or-one libraries and zero-or-more binaries. Otherwise, I'd expect something like
cargo_package
followed by maybe one
library_crate
followed by any number of
binary_crate
.
The problem is that e.g. a
binary_crate
can be create either by specific files or by content in
Cargo.toml
. Same for libraries. So one can't independently look at files or
Cargo.toml
, both have to be investigated.
The thing I'm thinking about is simply sidestepping all previous discussions which mean reimplementing cargo and just wrapping cargo in Pants targets and workflows. So no
rustc
or
rustfmt
things, but rather get 90% of work with minimal wraps.
I already have a toolchain provisioner that plumbs into a
CargoProcess
, so a lot of the work is done once I figure out how to wrapping should happen. But since we can't do 111 it becomes a bit messy... and potentially leads to a lot of redundant work; e.g. linting a crate a dozen times because it has a dozen binaries. So linting has to hit a package; but run has to hit a crate inside the package. Hmm. I wonder if a TargetGenerator can be a target as well? I guess I could do
cargo_package()
as a generator which generates
cargo_package_impl()
as a utility.
b
The nascent JS backend does something vaguely similar with package scripts (a single package.json can have multiple scripts that are individually runnable). I don’t know exactly how it does it, but maybe there’s some breadcrumbs there in terms of prior discussions
g
Nice, thanks @broad-processor-92400! Scanned through it and it looks like goes with the TargetGenerator approach.
h
TBH I think Rust is a great example of where we shouldn't need explicit targets at all, or at least not usually
All the info is available in the directory structure plus Cargo.toml
BUILD files would just be pointless extra boilerplate most of the time
g
That isn't possible today, though, is it? We need some form of target to hook on
Oh wait, synthetic targets can be used for that, right? I've not used them a lot so far. Hmm. Maybe synthetic target + a target generator would be quite nice. But I think it's tangential, the target structure still has to exist even if we're not explicitly creating any targets, no? I'm also not sure what we gain from not being explicit. Easier to detect failures as a user.
h
Less pointless boilerplate. We get feedback from users that it seems silly to have to generate a bunch of basically empty BUILD files just for scaffolding. It makes things unnecessarily heavyweight.
I don't think we need a target to hook on to in a new backend (like for Rust). A lot of the Python backend machinery is invested in Target, so that would be harder to retroactively remove, but in a greenfield backend I would definitely try and not require BUILD files
It's a barrier to adoption
g
I see -- I'll trust your word when you say that. My experience is that Bazel's explicitness plus gazelle/buildifier helps catch mistakes in build configuration. But at least with my current approach of just wrapping Cargo, there's little to no gain of trying to be smart... With a smarter approach (actually doing rustc commands etc) the explicitness would maybe add some introspection to that process.
(Though Pants approach of "mostly everything is inferred" makes that an open question too...)
I definitely agree that having a codebase where 99% of BUILD files are
python_sources()\npython_tests()
is... a bit pointless. 😛
l
Pondering on the tension between the two models and the ideas behind the existing recommendation to explicitly put these boilerplate-y BUILD files. Coming into it, it seemed reasonable to have BUILD files in directories because in a mono-repo, functionality would tend to be organized approximately aligned with the tree structure (rather than aligned with the repos in a polyrepo world). My fable for the need of these files was that any directory and its subtree could be the whole world to a particular developer and their team, and the BUILD files in there represented their ability to control the aspects of what happens within their area of responsibility. Like if they wanted to skip mypy in here, or if they were defining which things are meaningful to
run
or
package
. If they have something defined in a lambda, they would define it in BUILD in their subdir, rather than have to register it in some global file or even a file in a parent dir. This is neither here or there, excuse the rambling ...
g
I think the discussion is interesting at least, but as I said - I think tangential. I guess
targets
as a concept would still exist with or without BUILD files, so finding a good structure is still important. FWIW I ended up trying the TargetGenerator approach and it looks a bit dumb for single-bin-crates, but works:
Copy code
✦ ❯ cat examples/hello-world/src/main.rs
fn main() {
    println!("Hello, world!");
}

✦ ❯ cat examples/hello-world/BUILD
cargo_package(name="hello-world")

✦ ❯ pants package examples/hello-world#hello-world
00:02:03.45 [INFO] Wrote dist/examples.hello-world/hello-world

✦ ❯ dist/examples.hello-world/hello-world
Hello, world!
This is with pants-hosted rustup/toolchain building in a sandbox.
👍 1