Is there a way to declare, via the Cargo.toml
file that a particular crate cannot be used on Windows. By used, I mean cannot be compiled on Windows.
Of course, I could put an #[cfg(not(windows))]
around the main
function (it is a binary crate), making it impossible to compile it on Windows, but is there a way to do it from the crate manifest?
No, I don't think so. You can do #[cfg(windows)] compile_error!("This program isn't compatible with windows.");
though. Also is it just windows it isn't compatible with, or is it only compatible with for example unix systems. In that case you should probably use #[cfg(unix)]
/#[cfg(not(unix))]
instead.
I thought that was the default
No seriously, I gave up building anything in any language for Windows a long time ago.
Luckily Win 10 brought us the Linux Subsystem for Windows so I can still continue to develop on Windows.
https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target
I did not test but maybe you can use the "required-features" setting?
If you're developing something very unix-specific, then add categories = ["os::unix-apis"]
to crate's metadata. It won't automatically stop Windows users from getting it, but at least it's a clear classification and hopefully users will notice it when browsing crates.io or lib.rs.
It's not that bad with Rust, since the language is automatically compatible, and lots of crates do have proper support for Windows.
I even got cargo-deb
run on Windows, because it was only a matter of changing a couple of lines of code. I find it hilarious — you can make Windows-only Debian packages! (now somebody needs to RIIR dpkg
).
The convention would be #![cfg(not(windows))]
at the top level, so that the crate compiles but is empty in windows, which makes things a lot simpler in several situations.
But yeah, generally just making clear that it's Unix only or whatever in the readme/tags is all: don't let people download it and then get disappointed.
Of course, it's quite easy to make most code cross platform without any special effort unless the whole point is to expose a platform specific behavior, but I ain't your boss, so whatever.
(also, I would appreciate it if people kept their platform bashing to themselves, I've got a pretty long list of complaints for all three major desktop OSs - but airing them is petty pointless)
Well, I was initially making it Windows-compatible, but I then ran into the following issue: I am storing a path by splitting it into its parent and file-name. On Unix, /
has None
for its parent and None
for its file-name, so its clear when I am storing the root directory. But on Windows, C:\
, D:\
... all of them have None
for both parent and file-name - so how do I know what path I am referring to.
There is probably a way to solve this - possibly store the drive name somewhere, but I don't anticipate my application to be used on Windows (there are much better alternatives on Windows). So I decided that it was simpler to just rule out Windows use rather than worry about this.
Challenge accepted
(not sure if I'm really up to this, due to the size of the task, but it indeed sounds interesting)
(off the beaten path here, but why not) Not really clear from that description what the issue is: if you are trying to get a list of strings for each path component, then surely .iter() or .components() is exactly what you want: That gives "/", "foo", "bar" on unix, and "C:", "\", "foo", "bar" on windows, as either OsStr
or std::path::Components
. If you specifically want to split into (parent, file_name), then "C:\foo" splits into ("C:", "foo"), which is fine, and "/foo" splits into ("/", and "foo") which is fine. So basically, the only "weird" case is when .parent() is None, that you should just store the .to(_os)_str() instead of .file_name()
.
maybe the best choice is
#[cfg(windows)]
fn func_use_unix_api(...){
unimplemented!("Currently this crate does not support windows")
}
this may provide the capability that allow windows users modifying your code and make PR for you.
I don't understand why you use parent()
like that. Maybe there are other Path
methods that you could use instead? e.g. is_absolute or ancestors?
If you need to store paths as portable strings without C:\
showing up, there's:
Well, I have a situation like this - I need to store the "filesystem", starting at some directory as a tree. So, for an instance, I might want to store the directory "/home/deep/stuff" or "C:\Users\deep\stuff" as a tree. For paths like this, it is not a problem. The problem occurs for the directory "C:". Calling parent()
on this returns None
. So, this way I am losing the drive info. Why do I need to store the parent? For the root node. I am representing the tree as:
struct Tree {
root_parent: PathBuf,
root: Node,
}
struct Node {
name: OsString,
info: Info,
children: HashMap<OsString, Node>,
}
Unfortunately, I'd need paths. On the other hand, you have presented a really interesting crate - so thank you for that!
parent()
is not for splitting the path into components, but literally for finding a parent directory. C:\
doesn't have a parent directory — you can't be in C:\
and cd ..
to go to C
.
You need path.components()
. It's lossless and gives you C
as a separate component.
It's a reversible iterator, so you can use path.components().rev()
as a lossless alternative to ancestors()
and calling .parent()
in a loop.
path.components().rev().next()
is like parent()
, but will yield C
too.
Ah I see, that's brilliant!
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.