How to detect if a package contains anything installable?

I'm contributing to a meta-build tool that's designed to be able to build packages from many different types of build systems, and I'm trying to help it support cargo.

One step of the meta-build tool is to install any build artifacts that are relevant to install. I tried using cargo install, and this mostly works with one exception: library-only packages emit an error when you run cargo install on them, with the following message:

error: no packages found with binaries or examples

We try to have the meta-build tool rely on error codes emitted by the different build systems to determine whether each step of the overall build was successful, but in this situation cargo install gives back an error code of 101, and this seems to be the same error code that goes out for any kind of error, e.g. build errors, so we can't just ignore it.

If there is some reliable way that I can detect in advance whether the package is library-only, then I could just skip running cargo install during this step of the procedure.

Alternatively if I could tell cargo install that the absence of anything installable should not be treated as an error, I'd be happy to use that, but I don't see any option like that in the cargo book.

I'd like to avoid parsing the Cargo manifest myself since that seems too fragile, and I'm likely to miss many corner cases.

Can anyone think of a clean solution to this? The best I can think of at the moment is to parse the stdout to see if that specific message is the only one that gets produced, and then ignore the error code if that's the case, but that also seems awfully fragile to me.

You can run cargo metadata to get a JSON that includes the targets for the package you are trying to install. If it doesn't contain any bin targets, there aren't any binaries to install.

4 Likes

If you do end up parsing stdout, use --message-format=json.

2 Likes

Thanks, this will do nicely, especially with the --no-deps flag. I overlooked this initially because when I first ran the command it seemed like a wild massive dump of raw data for the whole dependency tree. But now that I see it's actually a nicely formatted JSON, we should be able to use this :tada:

1 Like

Are you sure the behavior you're asking for makes sense? I don't know exactly what workflow you intend your tool to be used in, but in most cases, when a Cargo package is used as a library, then

  • binary targets in the package may be completely irrelevant to using the library, and
  • building the package outside of the context of a specific dependent package is useless, because it and its dependencies may be built with the wrong feature flags and other build settings.

So, given that your tool is attempting to use Cargo as opposed to replacing it, you should probably consider it an error by default to be given a library package, because building library packages only makes sense for:

  • building a dependent on the library (in which case the build is automatically done by Cargo, in that dependent's target directory, so there is nothing you can usefully do separately),
  • when you are doing development of the library itself,
  • or if the package is providing a "cydlib" or "staticlib" library for linking into a non-Rust program. In this case, the package's Cargo.toml will declare that crate-type, so you can detect these kinds of packages.

In particular, you should not take a Rust package and install all the binaries you find in its transitive dependencies. That would not meet the expectations of the authors of any of the involved packages.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.