Porting Rust standard library: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
Add instructions on making the PAL functional
Format article source and remove use of deprecated <source> tag
Line 1: Line 1:
{{Rating|1}}
{{rating|1}}
{{template:In_Progress}}
{{template:In_Progress}}


Line 7: Line 7:


By the end you should be able to compile a project with
By the end you should be able to compile a project with
<source lang="bash">
<syntaxhighlight lang="bash">
cargo +dev-x86_64-unknown-myos r --target x86_64-unknown-myos
cargo +dev-x86_64-unknown-myos r --target x86_64-unknown-myos
</syntaxhighlight>
</source>


===Get sources===
===Get sources===


<source lang="bash">
<syntaxhighlight lang="bash">
git clone https://github.com/rust-lang/rust
git clone https://github.com/rust-lang/rust
</syntaxhighlight>
</source>


===Configuration===
===Configuration===


<source lang="ini">
<syntaxhighlight lang="ini">
# config.toml
# config.toml
profile = "compiler"
profile = "compiler"
Line 30: Line 30:
[rust]
[rust]
incremental = true
incremental = true
</syntaxhighlight>
</source>


===Adding the target===
===Adding the target===
Line 37: Line 37:
In addition, the rust compiler must be given a path to a valid crt0 object file. Rustc does not supply a <code>_start</code> symbol of its own, and the defalt linker doesn't provide one either, so we must provide our own. (TODO: Figure out self-contained linking of the crt0).
In addition, the rust compiler must be given a path to a valid crt0 object file. Rustc does not supply a <code>_start</code> symbol of its own, and the defalt linker doesn't provide one either, so we must provide our own. (TODO: Figure out self-contained linking of the crt0).


<source lang="rust">
<syntaxhighlight lang="rust">
// compiler/rustc_target/src/spec/base/myos.rs
// compiler/rustc_target/src/spec/base/myos.rs
use crate::spec::crt_objects;
use crate::spec::crt_objects;
Line 54: Line 54:
}
}
}
}
</syntaxhighlight>
</source>



<source lang="rust">
<syntaxhighlight lang="rust">
// compiler/rustc_target/src/spec/targets/x86_64_unknown_myos.rs
// compiler/rustc_target/src/spec/targets/x86_64_unknown_myos.rs
use crate::spec::{base, PanicStrategy, Target, TargetMetadata};
use crate::spec::{base, PanicStrategy, Target, TargetMetadata};
Line 82: Line 83:
}
}
}
}
</source><syntaxhighlight lang="diff">
</syntaxhighlight>


<syntaxhighlight lang="diff">
--- a/compiler/rustc_target/src/spec/base/mod.rs
--- a/compiler/rustc_target/src/spec/base/mod.rs
+++ b/compiler/rustc_target/src/spec/base/mod.rs
+++ b/compiler/rustc_target/src/spec/base/mod.rs
Line 93: Line 97:
pub(crate) mod nto_qnx;
pub(crate) mod nto_qnx;
pub(crate) mod openbsd;
pub(crate) mod openbsd;
</syntaxhighlight><source lang="diff">
</syntaxhighlight>


<syntaxhighlight lang="diff">
--- a/compiler/rustc_target/src/spec/mod.rs
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
Line 103: Line 110:
+
+
}
}
</source><syntaxhighlight lang="diff">
</syntaxhighlight>


<syntaxhighlight lang="diff">
--- a/compiler/rustc_target/src/spec/crt_objects.rs
--- a/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
+++ b/compiler/rustc_target/src/spec/crt_objects.rs
Line 163: Line 173:


===Adapt library/std===
===Adapt library/std===
In addition to rustc, std must also be modified to support the target. By default, std will error on build if the OS isn't explicitly supported, so we must add our OS to the list of supported OSes. In addition, we must provide a PAL (Platform Abstraction Layer) to tell std how to interact with our OS.<source lang="diff">
In addition to rustc, std must also be modified to support the target. By default, std will error on build if the OS isn't explicitly supported, so we must add our OS to the list of supported OSes. In addition, we must provide a PAL (Platform Abstraction Layer) to tell std how to interact with our OS.
<syntaxhighlight lang="diff">
--- a/library/std/build.rs
--- a/library/std/build.rs
+++ b/library/std/build.rs
+++ b/library/std/build.rs
Line 174: Line 185:
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
// See src/bootstrap/src/core/build_steps/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
</syntaxhighlight>
</source>


Copy <code>library/std/src/sys/pal/unsupported</code> to <code>library/std/src/sys/pal/myos</code>.
Copy <code>library/std/src/sys/pal/unsupported</code> to <code>library/std/src/sys/pal/myos</code>.


<source lang="diff">
<syntaxhighlight lang="diff">
--- a/library/std/src/sys/pal/mod.rs
--- a/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
+++ b/library/std/src/sys/pal/mod.rs
Line 191: Line 202:
mod unsupported;
mod unsupported;
pub use self::unsupported::*;
pub use self::unsupported::*;
</syntaxhighlight>
</source>


===Add toolchain===
===Add toolchain===


<source lang="bash">
<syntaxhighlight lang="bash">
rustup toolchain link dev-x86_64-unknown-myos ~/Documents/rust/rust/build/x86_64-unknown-linux-gnu/stage2
rustup toolchain link dev-x86_64-unknown-myos ~/Documents/rust/rust/build/x86_64-unknown-linux-gnu/stage2
</syntaxhighlight>
</source>


==Making the standard library functional==
==Making the standard library functional==
Line 243: Line 254:
====Global statics (easiest, single-threaded only) ====
====Global statics (easiest, single-threaded only) ====
{{Warning | This WILL not work on multi-threaded systems.}}
{{Warning | This WILL not work on multi-threaded systems.}}
If your OS is single-threaded or you don't want to implement full TLS before adding multithreading to your PAL, Rust can implement TLS via global statics. <syntaxhighlight lang="diff">
If your OS is single-threaded or you don't want to implement full TLS before adding multithreading to your PAL, Rust can implement TLS via global statics.
<syntaxhighlight lang="diff">
--- a/library/std/src/sys/thread_local/mod.rs
--- a/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
+++ b/library/std/src/sys/thread_local/mod.rs
Line 261: Line 273:


====Native ELF TLS (fastest)====
====Native ELF TLS (fastest)====
This option is the fastest way of doing TLS, but requires more complex suport from the OS. To implement it, see the linked wiki article on TLS. Enabling it in rustc is done by adding a target option for your OS.<syntaxhighlight lang="diff">
This option is the fastest way of doing TLS, but requires more complex suport from the OS. To implement it, see the linked wiki article on TLS. Enabling it in rustc is done by adding a target option for your OS.
<syntaxhighlight lang="diff">
--- a/compiler/rustc_target/src/spec/base/myos.rs
--- a/compiler/rustc_target/src/spec/base/myos.rs
+++ b/compiler/rustc_target/src/spec/base/myos.rs
+++ b/compiler/rustc_target/src/spec/base/myos.rs
Line 279: Line 292:
Adding print support is fairly simple given the architecture of the PAL, and merly requires filling out the Write implementations of stdout/err in <code>stdio.rs</code>. In addition, the panic_output function shoudl be set to the desired output stream for panic messages, usually stderr.
Adding print support is fairly simple given the architecture of the PAL, and merly requires filling out the Write implementations of stdout/err in <code>stdio.rs</code>. In addition, the panic_output function shoudl be set to the desired output stream for panic messages, usually stderr.


Example code is provided below. The given code assumes syscalls are done with interrupt 0x80 with the number in rax and the first parameter in rcx, and syscall 0 takes a byte to write to some text output device. You will probably need to change the syscall number and parameters for your OS, but this should be a basic starting point.<syntaxhighlight lang="diff">
Example code is provided below. The given code assumes syscalls are done with interrupt 0x80 with the number in rax and the first parameter in rcx, and syscall 0 takes a byte to write to some text output device. You will probably need to change the syscall number and parameters for your OS, but this should be a basic starting point.
<syntaxhighlight lang="diff">
--- a/library/std/src/sys/pal/myos/stdio.rs
--- a/library/std/src/sys/pal/myos/stdio.rs
+++ b/library/std/src/sys/pal/myos/stdio.rs
+++ b/library/std/src/sys/pal/myos/stdio.rs
Line 320: Line 334:
+ Some(Stderr::new())
+ Some(Stderr::new())
}
}
</syntaxhighlight>
</syntaxhighlight>Now you should be able to compile and run the default Rust hello world program for your target and see it print to screen.
Now you should be able to compile and run the default Rust hello world program for your target and see it print to screen.


==Runtime==
==Runtime==
Line 328: Line 343:
If you use a crate for the runtime (e.g. <code>myos_rt</code>), you can add it as a dependency to the standard library:
If you use a crate for the runtime (e.g. <code>myos_rt</code>), you can add it as a dependency to the standard library:


<source lang="ini">
<syntaxhighlight lang="toml">
[target.'cfg(target_os = "myos")'.dependencies]
[target.'cfg(target_os = "myos")'.dependencies]
myos_rt = { version = "*", features = ["rustc-dep-of-std"] }
myos_rt = { version = "*", features = ["rustc-dep-of-std"] }
</syntaxhighlight>
</source>


The <code>rustc-dep-of-std</code> feature is necessary since <code>libcore</code> et al. don't exist yet.
The <code>rustc-dep-of-std</code> feature is necessary since <code>libcore</code> et al. don't exist yet.
Line 337: Line 352:
Modify the <code>Cargo.toml</code> of your runtime library to include the feature and propagate it up, e.g.:
Modify the <code>Cargo.toml</code> of your runtime library to include the feature and propagate it up, e.g.:


<source lang="ini">
<syntaxhighlight lang="toml">
[dependencies]
[dependencies]
cfg-if = "1.0"
cfg-if = "1.0"
Line 349: Line 364:
"cfg-if/rustc-dep-of-std"
"cfg-if/rustc-dep-of-std"
]
]
</syntaxhighlight>
</source>


Do keep in mind that the same crate with different feature flags are seen as [https://github.com/rust-lang/cargo/issues/2363 <strong>different crates</strong> by the compiler]. This means that if you any globals in the runtime crate and have a project that uses both stdlib and your runtime crate there will be two separate sets of those globals. One way to work around this is by giving these globals an explicit name with <code>#[export_name = "__rt_whatever"]</code> and weakly linking them with <code>#[linkage = "weak"]</code>.
Do keep in mind that the same crate with different feature flags are seen as [https://github.com/rust-lang/cargo/issues/2363 <strong>different crates</strong> by the compiler]. This means that if you any globals in the runtime crate and have a project that uses both stdlib and your runtime crate there will be two separate sets of those globals. One way to work around this is by giving these globals an explicit name with <code>#[export_name = "__rt_whatever"]</code> and weakly linking them with <code>#[linkage = "weak"]</code>.
Line 359: Line 374:
Add <code>compiler_builtins</code> as a dependency for the crates you use in stdlib, e.g.:
Add <code>compiler_builtins</code> as a dependency for the crates you use in stdlib, e.g.:


<source lang="ini">
<syntaxhighlight lang="ini">
[dependencies]
[dependencies]
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
Line 369: Line 384:
"compiler_builtins/rustc-dep-of-std", # <--
"compiler_builtins/rustc-dep-of-std", # <--
]
]
</syntaxhighlight>
</source>


[[Category:Rust]]
[[Category:Rust]]