Target (os, architecture, environment) as a crate property

When I compile some Rust binary or dependency on Linux and see crates such a winapi downloaded and compiled I always feel that in addition to overlook by crate's authors this is also a flaw in cargo's design. As we have a set of crates which are not fully cross-platform or even target some specialized architecture or environment I think it makes sense to add this information to Cargo.toml.

Probably the easiest approach will be addition of package level target_* properties which follow currently existing configuration for conditional compilation. In addition to simply informing crate users this can be used to validate dependent crates. So if some crate (e.g. winapi) adds target_family="windows" to the Cargo.toml it will be required for dependent crate to use target.'cfg(windows)'.dependencies on this dependency. In addition to clearer dependency tree and better developer notifications (e.g. we can add related icons to crates.io) it could potentially prevent some bugs. Also it could be used to promote no_std crates, as for now there is no way of knowing which crates can be used for bare-metal development and which are not.

Of course there will be a more complex cases and we should discuss various corner cases and details of dependency validation algorithm. But before opening issue and starting RFC I would like to hear your comments and ideas on this.

2 Likes

Why not have the configuration in the Cargo.toml of the crate using the dependency? That seems like it'd make more sense to me.

[dependencies.windows]
winapi = "*"

There could be an optional hint in the dependency crate, something like
target = "windows"

I don't think cargo should enforce that though. It could just be used to display extra information on crates.io. Setting target to no_std could however prevent rustc from allowing usage of the standard library.

We already have it with [target.'cfg(windows)'.dependencies]. (docs) But as this feature was introduced only in 1.8 you can quite often see crates which do not use it, either crate is old and no more supported or developer simply does not know about such feature.

My proposal exactly is about addition of such "hints" to the manifest format and they of course will be optional.

Regarding enforcement by cargo I disagree on this, in my opinion if we have reliable information about crate we should use to reduce risk of potential mistakes and make explicit platform specific subtrees of crates infrastructure.

Such validation will not introduce any backward compatibility issues. Because if some crate does not specify any target attributes cargo will not set any restrictions on its users.

Well, cargo can simply require to use #![no_std]if no_std target was enabled in Cargo.toml and everything else will be done by existing tools.

2 Likes

The issue lies with when the crate doesn't specify a subsystem because it doesn't know about it.

Could you please elaborate on? If crate does not specify any targets for dependent crates everything will work absolutely in the same way as it does now.

Or the author is supporting older versions of Rust which wouldn't understand those sections, and didn't want to have to repeat the Windows-specific dependencies four times.

5 Likes

Yes, this too. But I don't quite understand why do you need support older versions of compiler. Could you please specify such scenarios?

As far as I understand if you depend on some crate and it's starts using some new feature (say ?) you'll have to bump compiler version either way if you want to stay up to date.

... because not everyone is using the latest version of the compiler? Because not everyone may want to or be able to change the version of the compiler they're using? Because maybe a newer compiler breaks their code? Because they're using the version shipped with their distro which is still Rust 1.6? Because the project in question uses a specific version of nightly for a critical compiler plugin? Because their employer won't let them? Because they're on a severely constrained net connection? Because forcing people to incessantly install updates they don't need is a shitty way to treat your users?

There are plenty of obvious reasons to not be using the latest version of almost any piece of software, Rust included.

3 Likes

Whoa, hold your horses. I was asking you in context of staying up to date with crates infrastructure. If you want to stay on older versions of crates and it's fine with you no one will force you to change your environment. But I hope you understand that likewise you can't force crate authors to support older compiler versions. And I can't say that I see support of older compiler versions at the cost of not using new features as the right general direction for crate developers.

If you acknowledge that some users need to stay on old versions of the compiler, then it shouldn't be a stretch that some crate authors want to continue supporting those users even for new versions of their crate.

Of course I do acknowledge that and this is why I explicitly said that proposed feature will not affect the old way of doing things if none of your dependencies use proposed feature. But it could cause a ripple effect up in dependency tree the same way as 1.8 release did.

The issue lies when the crate does mention a subsystem but not every subsystem it is compatible with.

Say someone is working on a system which is to some extent compatible with the Linux subsystem, the crate owner should be able to select which dependencies it's compatible with. Maybe such subsystem becomes popular in five years but no rust libraries will compile because of some dull cargo code policing. I acknowledge this is a rare issue that not many will face, but it's something to consider.

I think this should be handled by the compiler by simply giving some linking errors rather than cargo trying to guess for you.

I understand that such corner cases are possible and I wrote about it in the last paragraph of the OP.

About your case thought, I don't think it will happen, because majority of the libraries will be either without any specified target (as they now) or will use some OS families or OSes as a target. (do not forget it possible to specify general targets, not a simply set of triplets) So if some new target appears, say linux-newarm-neolibc, code for this target will be able to use all libraries which are:

  • not specified any target or no_std
  • specified target_family="unix" (or simply target="unix" if it will be possible make it work without problems)
  • specified target_os = "linux" (or target="linix")

Of course there can be several supported targets for the crate, so probably it's better to rename to targets=["target1", "target2"].

1 Like