Embedded code may interact with C and thus may find these types useful. It'd make sense to allow usage of CStr in libcore and CString in liballoc.
Of course, right now due to the way implementations work in the standard library it may not be possible to include CStr in libcore. However, moving it to liballoc is still a step up.
Including CStr in libcore means the target-dependent type c_char will need to be in libcore as well.
@kennytm in that case, it would make sense to just move the entire os::raw module over to libcore. I'd probably rename it, though, and put it as a submodule of ffi.
@clarcharr libcore should not contain any public platform-dependent items (liballoc is also platform-independent at the moment). If we move CStr and std::os::raw out, it's better be an independent libffi crate.
Can we not make a pragmatic compromise of moving the meat of CStr (with c_char replaced by u8) to libcore and retain compatibility by providing a facade with c_char in libstd? I doubt we will ever port Rust to any platforms with CHAR_BIT != 8 (which will still be possible with a customized libcore,) and all operations provided by the current CStr seem to be indifferent with the possible signedness of c_char.
Cf. https://stackoverflow.com/questions/40575116/ C's char, signed char and unsigned char are one and the same ("character") type in the context of aliasing.
Inconsistency I noticed: CStr converts from [u8], which makes it very obvious that we are putting a preference for u8, but it references c_char. I would consider this a bug but I'm not sure if we'd be able to change this, considering how it'd be a breaking change :(
Including CStr in libcore means the target-dependent type c_char will need to be in libcore as well.
Why is that a problem? usize as well as isize are in libcore as well, and both of them are target dependent.
@est31
usize and isize are built in primitives, c_char is just a type alias to u8 or i8 depending on #[cfg]. Moving c_char to libcore represents a change in policy (even encoded in a tidy check), which while is currently happening due to VaList, should still be verified whether it's suitable.
Just because there's some platform-dependent stuff in libcore (usize and atomics) doesn't mean we want more.
In the meantime, is anyone aware of a crate which would do this (provide cstr/cstring for no_std situation) ?
Personally I think that the methods involving *const c_char should be removed (i.e. deprecated) in favour of ones that reference *const u8. That way, people who want to cast to *const c_char still can, but we can at least move CStr to core and CString to alloc without the platform-specific types.
We can't expose CStr in libcore. libcore is by definition platform independent, but CStr is a string of C chars, which are by definition platform-dependent types. In C, char is a different type than signed char and unsigned char, and in particular, the signedness of char is implementation defined (platform specific).
What we could do is move CStr to libc, which is IMO where it belongs. libstd can then re-export libc's CStr in std::ffi::, and libc could re-export libstd's CStr when libstd is available (that is, when libc/use_std is enabled). That way both libc::CStr and std::ffi::CStr would be the same type.
The main reason not to move CStr to libc right now is that it is not FFI safe. Until that's fixed, it's probably dangerous to move it to libc since that might encourage people to use it in C FFI and that would be instant undefined behavior.
libcore is by definition platform independent
I don't see how this is true-- as pointed out above, libcore contains usize and isize which both vary by target.
I don't see how this is true-- as pointed out above, libcore contains usize and isize which both vary by target.
To be more specific, they vary by target_env (e.g. depending on the C library used by the target). Are there any other things in libcore that depend on this ?
@gnzlbg Different question -- considering the way Rust is currently packaged, it's impossible to get libcore separately from libstd; when you download for a target, you download both. Is there a plan to separate out the current notion of "target" to just the underlying CPU architecture and not the operating/build environment?
This basically affects whether this discussion is meaningful in any way.
@gnzlbg Different question -- considering the way Rust is currently packaged, it's impossible to get libcore separately from libstd; when you download for a target, you download both.
Some targets only ship libcore, and some targets do not even ship libcore.
Is there a plan to separate out the current notion of "target" to just the underlying CPU architecture and not the operating/build environment?
There are targets that are independent of that, e.g., wasm32-unknown-unknown.
I guess that I'm asking the wrong question-- the point I'm making is that, although there are targets without libstd, there isn't any notion in Rust of compiled code that's independent from its operating environment. Sure, you can specify the environment to be "none" and the resulting bytecode will be environment-agnostic, but there's never the opportunity to link code between different "targets" regardless of whether they share the same architecture. So, yes, while there are targets that ship without libstd, these targets can still have a "different" libcore than the ones that do, regardless of whether the actual contents of these are the same.
I honestly don't see this changing.
Sure, I agree that using libcore shouldn't require linking against libc. But, on targets that want to link with libc, I don't think it's bad that libcore has code to help with that, because the libcore they're using will always match the environment they're in.
The only way that would change if we offered, say, one compiled version of libcore for all of x86_64. Then, the code for interfacing with libc for x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc, for example, could be incorrect. But, with the way that Rust bundles targets right now, this isn't the case.
Sure, you can specify the environment to be "none" and the resulting bytecode will be environment-agnostic, but there's never the opportunity to link code between different "targets" regardless of whether they share the same architecture.
I'm not sure I follow. You can build a static lib of a none target, and link it with a static lib of a non-none target.
But, on targets that want to link with libc, I don't think it's bad that libcore has code to help with that,
If you have a program that needs to link against libc, you can just link the libc crate.
I feel like moving c_void to libcore was, in hindsight, a bad idea. The libc crate lives between libcore and currently liballoc. We have dozens of workarounds to support binaries that link it twice, once via liballoc, and once from crates.io, for very little value.
The reason c_void was moved into libcore was because libstd::c_void uses the liballoc's libc, and this type is different, but otherwise identical, to the libc::c_void type from crates.io. There are other types like this, e.g., thread handles, and one could make the same argument that the right thing for these would be to live in libcore.
It is probably too late to fix this for c_void, but I think the better fix would be to allow people to use the bundled libc without having to enable a nightly feature. This libc would provide c_void, c_int, CStr, etc. So you could build a #[no_std] binary without liballoc, that uses CStr by just writing use libc::CStr.
Most helpful comment
I'm not sure I follow. You can build a static lib of a
nonetarget, and link it with a static lib of a non-nonetarget.If you have a program that needs to link against libc, you can just link the
libccrate.I feel like moving
c_voidto libcore was, in hindsight, a bad idea. Thelibccrate lives betweenlibcoreand currentlyliballoc. We have dozens of workarounds to support binaries that link it twice, once vialiballoc, and once from crates.io, for very little value.The reason
c_voidwas moved intolibcorewas becauselibstd::c_voiduses theliballoc's libc, and this type is different, but otherwise identical, to thelibc::c_voidtype from crates.io. There are other types like this, e.g., thread handles, and one could make the same argument that the right thing for these would be to live in libcore.It is probably too late to fix this for
c_void, but I think the better fix would be to allow people to use the bundled libc without having to enable a nightly feature. This libc would providec_void,c_int,CStr, etc. So you could build a#[no_std]binary without liballoc, that usesCStrby just writinguse libc::CStr.