Open
Description
This is a persistent issue with target_family = "unix"
being defined by targets that happen to have a somewhat Unix-like compiling-for-them experience but do not have a Unix runtime. This causes considerable amounts of working around them in configuration code for libraries, since you cannot simply treat them as Unix.
Some examples:
Activity
ivmarkov commentedon Jun 1, 2025
While removing
cfg(unix)
for these targets would indeed cause the "CtrlCs" of this world to now be opted out automatically, and same for processes and Unix domain sockets, now you have to put more work to explicitly opt in same or different crates into knowing that these targets which are!cfg(unix)
actually do support BSD sockets and other Unix-y stuff (not that once these crates take thecfg(unix)
route, there are no additional per-OS branches inside, including for "ESPIDF"):cfg(unix)
is just too coarse-grained :(With that said, if
cfg(unix)
is indeed considered to mean a multi-process POSIX OS (or suchlike), then!cfg(unix)
might indeed be the way to go. I'm just not sold on the argument that we should do this because it will result in less amount of workarounds.workingjubilee commentedon Jun 1, 2025
Mostly what I'm noticing, @ivmarkov, is that even if we e.g. address various stdlib APIs with a solution like
cfg(target_has_processes)
orcfg(target_has_threads)
, we don't touch on artifacts that Rust generally doesn't consider part of itself, but are still core to the platform and of interest to developers, like signals.workingjubilee commentedon Jun 1, 2025
And I certainly must express at least some doubt that we want to touch signals in the stdlib.
ivmarkov commentedon Jun 1, 2025
cfg(unix)
already means two things: (a) a proclamation for the user that the OS is unix-like (b) a way to do code-branching in stdlib itself.I'm not following why we can't have
cfg(target_has_signals)
even if just for the purpose of (a) and not for (b)?workingjubilee commentedon Jun 1, 2025
I suppose we could, but that raises the question: how many such
cfg
do we add that ESP-IDF would fail before we start wishing to have answered differently oncfg(unix)
?workingjubilee commentedon Jun 1, 2025
@ivmarkov To be clear, I'm not trying to inconvenience you specifically, I'm just thinking about how we can relatively-ergonomically support various use-cases without every Rust crate author having to hand-roll their own list of platform support.
ivmarkov commentedon Jun 1, 2025
Sure. And
cfg(unix)
does (or should) indeed mean "you have signals" on all OSes except on the microcontroller ones.For microcontrollers (ESP-IDF and Nuttx at least), it is just messy either way:
cfg(unix)
, the case where signals have to be disabled for those is solved cleanly without additional cfg;OR cfg(target_os = "thisorthat")
conf next to thecfg(unix)
one.So in either case, for microcontrollers you do need additional confs. Because
cfg(unix)
is just too coarse grained.But also - either way is no big deal for us.
If T-libs decides to pull us out of
cfg(unix)
- say - because the status quo gives the wrong "impression" w.r.t. system caps to the users - we need to update all downstream unix-y crates known to work with ESP-IDF - as well as STD itself - with the aboveOR cfg(target_os = "thisorthat")
conf so that they can still take their "unix" code path where BSD INET sockets live. Annoying but quite doable.It is only that the issue was seemingly opened not with the "impression" argument in mind, but with the argument that "This causes considerable amounts of working around them in configuration code for libraries" and what I'm saying is that either way you decide to treat microcontrollers - "some amount of working around them in configuration code" is just unavoidable. And that my gut feeling is still that with
cfg(unix)
"on" for microcontrollers, we have better chances for crates to typecheck without or with less changes, and yeah, eventually fail at runtime for - say - processes, which might actually be acceptable.===
BTW - and sorry if clear - but running most "off the shelf" STD crates from crates.io on microcontrollers without any modifications is a chimera anyway.
When you have a total of ~ 200KB for the
.bss
and heap of your app (MCUs total RAM is ~ 400KB for the beefier ones) memory optimizations are almost certainly necessary. In the lucky cases, just reducing some buffer sizes, in the not so lucky ones - more obtrusive memory opts or just giving up on the crate altogether as it was not designed with memory constrained environments in mind to begin with.Popular crates, which are thin, mostly zero-cost wrappers around the OS, like STD itself and the networking crates I enumerated above; async runtimes; utilities like
url
,time
,chrono
,random
etc. - these do fit the bill and do work without or with relatively small modifications (which - again in my experience are smaller withcfg(unix)
!). But I don't think I can generalize this to ALL STD crates on crates.io or even to the majority of those. Only very-popular crates receive the amount of memory-banging so that they are a good fit for microcontrollers.Just mentioning because this whole "let's make sure downstream crates have an easier life by selecting the more correct
cfg(unix)
vs!cfg(unix)
for microcontrollers" seems a bit like a storm in a teacup to me given that the crate has to be memory-optimized to begin with, which often induces changes to it anyway, or considerably reduces the crate selection options.===
I don't follow.
In a perfect world where we have the
cfg(have_*)
capability system,cfg(unix)
,cfg(windows)
andcfg(target_os = "thisorthat")
become obsolete for downstream crates. So whether ESP-IDF iscfg(unix)
or not becomes an irrelevant question.Alas, we are not there, hence the whole discussion, I guess.
mkroening commentedon Jun 16, 2025
We are facing this issue too with Hermit. Hermit has traditionally had custom system calls, but nowadays, we are moving towards POSIX in many ways, but not in all. We are committing to POSIX networking and file descriptors nowadays, but explicitly don't support spawning processes or signals.
So when we are adding support for Hermit in popular crates such as Tokio, we mostly need to change
cfg(unix)
tocfg(any(unix, target_os = "hermit"))
. When considering upstreaming the Hermit support, we even considered if it was worthwhile making Hermitcfg(unix)
and instead opting out of all the things that Hermit does not support, but that's probably not the right thing to do.So having something more fine-grained like
cfg(posix_net)
,cfg(posix_fd)
would be great for us.