E542 std: Add Motor OS std library port by lasiotus · Pull Request #147000 · rust-lang/rust · GitHub
[go: up one dir, main page]

Skip to content

Conversation

lasiotus
Copy link
Contributor

Motor OS was added as a no-std Tier-3 target in
PR 146848 as x86_64-unknown-motor.

This PR adds the std library for Motor OS.

While the PR may seem large, all it does is proxy
std pal calls to moto-rt. Where there is some non-trivial
code (e.g. thread::spawn), it is quite similar, often
identical, to what other platforms do.

@rustbot
Copy link
Collaborator
rustbot commented Sep 24, 2025

These commits modify the library/Cargo.lock file. Unintentional changes to library/Cargo.lock can be introduced when switching branches and rebasing PRs.

If this was unintentional then you should revert the changes before this PR is merged.
Otherwise, you can ignore this comment.

The list of allowed third-party dependencies may have been modified! You must ensure that any new dependencies have compatible licenses before merging.

cc @davidtwco, @wesleywiser

@rustbot rustbot added A-tidy Area: The tidy tool S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Sep 24, 2025
@rustbot
Copy link
Collaborator
rustbot commented Sep 24, 2025

r? @tgross35

rustbot has assigned @tgross35.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@tgross35
Copy link
Contributor

Is there any notable std functionality that isn't supported on this platform? Just skimming it, it seems like things are pretty complete (threads, systemtime, process, etc)

Nominating for libs as this adds a new std target.

@rustbot label +I-libs-nominated

@rustbot rustbot added the I-libs-nominated Nominated for discussion during a libs team meeting. label Sep 24, 2025
@lasiotus
Copy link
Contributor Author

Is there any notable std functionality that isn't supported on this platform? Just skimming it, it seems like things are pretty complete (threads, systemtime, process, etc)

I believe all major pieces are supported/implemented, including networking. Some specific things are not (yet) fully implemented, like FS links, or DNS lookup (at the moment, only "localhost" resolves to an IP address). On the other hand, tokio is ported via a mio port, which was not completely trivial...

Comment on lines +6 to +4
#[unstable(feature = "motor_ext", issue = "none")]
pub fn map_motor_error(err: moto_rt::ErrorCode) -> crate::io::Error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably doesn't need to be crate public?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a Rust program calls into moto-sys (the Motor OS kernel API) or moto-rt (the Motor OS runtime API), they get moto_rt::ErrorCode. To convert it into io::Error (e.g. for Tokio) they need access to a similar function. So either the function should be exported here as pub, or duplicated elsewhere, from where std can't import (due to io::Error being in std). If io::Error is moved to core (which I've seen being discussed), I'll move this function to moto-rt.

I prefer to avoid code duplication and just export it here. If it is better to duplicate it elsewhere, I can do that also, let me know.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you could do here is define the RawOsError type as moto_rt::ErrorCode (copy how we do this for UEFI) and override fn decode_error_kind. That way io::Error is actually just a a moto_rt::ErrorCode, and io::Error::from_raw_os_error can be used rather than needing this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you could do here is define the RawOsError type as moto_rt::ErrorCode (copy how we do this for UEFI) and override fn decode_error_kind. That way io::Error is actually just a a moto_rt::ErrorCode, and io::Error::from_raw_os_error can be used rather than needing this function.

Oh, that's a nice trick! I've had a vague desire to use a proper Error enum in public Motor OS API (which is in Rust), and to use a plain ErrorCode/u16 only in internal ABI (which uses C/Linux calling conventions, as Rust doesn't define an ABI).

So I'm going to spend the next several days refactoring the whole Motor OS codebase around a new enum Error (repr u16, most likely).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you could do here is define the RawOsError type as moto_rt::ErrorCode (copy how we do this for UEFI) and override fn decode_error_kind. That way io::Error is actually just a a moto_rt::ErrorCode, and io::Error::from_raw_os_error can be used rather than needing this function.

Oh, that's a nice trick! I've had a vague desire to use a proper Error enum in public Motor OS API (which is in Rust), and to use a plain ErrorCode/u16 only in internal ABI (which uses C/Linux calling conventions, as Rust doesn't define an ABI).

So I'm going to spend the next several days refactoring the whole Motor OS codebase around a new enum Error (repr u16, most likely).

Bummer... Spent the weekend to make Motor OS API (moto-rt, moto-sys) return an enum Error instead of a u16, only to find out that Rust library assumes it is an integer of no more than 32 bits. Will just use u16 then - this is a fight for another day...

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Sep 25, 2025
}

pub fn current_exe() -> io::Result<PathBuf> {
Ok(crate::sys::args::args().next().unwrap().into())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you run say ls foo on Motor OS, is the first argument ls (like on Unix and Windows) or /path/to/ls? If the former, this is not a correct implementation. std::env::current_exe() is supposed to return an absolute path to the executable file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In many modern systems, even unices, there is often no global "absolute path", as programs run in their own jails/containers/whatever. Also just by looking at how other platforms deal with it, it is all over the place:

  • aix just "infers" the location if args[0] is not an absolute path (which is buggy and thus worse, I'd say);
  • openbsd does the same thing as Motor OS, only additionally calls canonicalize() if args[0] starts with a dot or contains a slash; if not, args[0] is returned unmodified;
  • same for vxworks.

So I'd say Motor OS is not unique here. I can add a call to canonicalize(), if you insist, but I don't think it will make things better: I'd rather have an unmodified args[0] rather than have it massaged in some cases and not in others.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the loose expectation here is that you could pass the result of std::env::current_exe() to another process, which may possibly be launched in another directory, and launch the same binary. If there is a best effort change to make this work then I think it's worthwhile (unless I'm misunderstanding things here)

@bors
Copy link
Collaborator
bors commented Sep 25, 2025

☔ The latest upstream changes (presumably #147019) made this pull request unmergeable. Please resolve the merge conflicts.

As part of work to add stdlib support for Motor OS.
@rustbot
Copy link
Collaborator
rustbot commented Sep 26, 2025

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Motor OS was added as a no-std Tier-3 target in
rust-lang#146848
as x86_64-unknown-motor.

This patch/PR adds the std library for Motor OS.

While the patch may seem large, all it does is proxy
std pal calls to moto-rt. When there is some non-trivial
code (e.g. thread::spawn), it is quite similar, often
identical, to what other platforms do.
@lasiotus lasiotus requested a review from tgross35 September 26, 2025 21:38
@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Sep 26, 2025
@lasiotus lasiotus requested a review from bjorn3 September 26, 2025 21:38
@Amanieu
Copy link
Member
Amanieu commented Oct 1, 2025

We discussed this in the @rust-lang/libs meeting and are happy to add std support for this target because it supports all major functionality of std.

@Amanieu Amanieu removed the I-libs-nominated Nominated for discussion during a libs team meeting. label Oct 1, 2025
@lasiotus
Copy link
Contributor Author
lasiotus commented Oct 2, 2025

We discussed this in the @rust-lang/libs meeting and are happy to add std support for this target because it supports all major functionality of std.

Thanks, Amanieu!

@tgross35 Trevor, how can I improve this PR to make it mergeable?

@tgross35
Copy link
Contributor
tgross35 commented Oct 2, 2025

It's on my list, I just haven't had a chance to do a thorough review yet (probably later this week)

Comment on lines +6 to +4
#[unstable(feature = "motor_ext", issue = "none")]
pub fn map_motor_error(err: moto_rt::ErrorCode) -> crate::io::Error {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you could do here is define the RawOsError type as moto_rt::ErrorCode (copy how we do this for UEFI) and override fn decode_error_kind. That way io::Error is actually just a a moto_rt::ErrorCode, and io::Error::from_raw_os_error can be used rather than needing this function.

Comment on lines +4 to +12
#[unstable(feature = "motor_ext", issue = "none")]
pub trait ChildExt: Sealed {
/// Extracts the main thread raw handle, without taking ownership
#[unstable(feature = "motor_ext", issue = "none")]
fn sys_handle(&self) -> u64;
}

#[unstable(feature = "motor_ext", issue = "none")]
impl ChildExt for crate::process::Child {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following up from #147000 (comment): just make a library tracking issue (there's a library tracking template) and paste these API in them. We can then go through the stabilization process to make them usable on MotorOS with stable rustc, once we eventually have build-std usable on stable.

It's an imperfect system for the tier 3 targets currently given the build-std situation, but at least this will point interested parties somewhere.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stable attributes here should technically be unstable(feature = "motor_ext") like the others. Doesn't matter too much for T3 targets though so maybe this is fine (asked on Zulip)

Comment on lines 13 to 28
target_os = "motor" => {
mod motor;
pub use motor::*;
}
target_os = "wasi" => {
mod wasi;
pub use wasi::*;
}
target_os = "uefi" => {
mod uefi;
pub use uefi::*;
}
_ => {
mod unsupported;
pub use unsupported::*;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can Motor just use the mod unsupported; fallback here? io_slice/motor.rs looks the same.

Comment on lines +13 to +15
pub fn error_string(errno: i32) -> String {
format!("errno: {errno}")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you do the RawOsError bit I mentioned, then s/i32/RawOsError.

Is there a way to go from moto_rt::ErrorCode to a name like E_ALREADY_IN_USE or a descriptive string? If so, that could be returned here.

}

pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut temp_vec = alloc::vec::Vec::new();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already in scope

Suggested change
let mut temp_vec = alloc::vec::Vec::new();
let mut temp_vec = Vec::new();

Comment on lines +114 to +116
pub fn read2(_p1: AnonPipe, _v1: &mut Vec<u8>, _p2: AnonPipe, _v2: &mut Vec<u8>) -> io::Result<()> {
todo!()
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably either unsupported() or a panic!() rather than an empty todo!()

Comment on lines +59 to +67
for (k, v) in env.capture() {
if k.clone().into_string().unwrap() != moto_rt::process::STDIO_IS_TERMINAL_ENV_KEY {
vars.push((k, v));
}
}

for (k, v) in vars {
env.set(&k, &v);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Save a clone & collect

Suggested change
for (k, v) in env.capture() {
if k.clone().into_string().unwrap() != moto_rt::process::STDIO_IS_TERMINAL_ENV_KEY {
vars.push((k, v));
}
}
for (k, v) in vars {
env.set(&k, &v);
}
for (k, v) in env.capture() {
if k == moto_rt::process::STDIO_IS_TERMINAL_ENV_KEY {
continue;
}
env.set(k, v);
}

Comment on lines +178 to +194
impl From<File> for Stdio {
fn from(_file: File) -> Stdio {
todo!()
}
}

impl From<io::Stdout> for Stdio {
fn from(_: io::Stdout) -> Stdio {
todo!()
}
}

impl From<io::Stderr> for Stdio {
fn from(_: io::Stderr) -> Stdio {
todo!()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use panic!(...) or unsupported!(...) rather than todo!(...) (TODO is usually for things to do before merge by tidy's convention)

Comment on lines +138 to +139
let val = if let Some(v) = v { v.to_str().unwrap() } else { "" };
env.push((k.to_str().unwrap().to_owned(), val.to_owned()));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can use as_str() rather than to_str().unwrap()

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 3, 2025
@lasiotus lasiotus mentioned this pull request Oct 6, 2025
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-tidy Area: The tidy tool S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants
0