Rebuild hosts automatically (for now)

This commit is contained in:
Richard Feldman 2020-10-04 16:18:33 -04:00
parent 856c01f706
commit 7e1166b3a2
3 changed files with 81 additions and 65 deletions

View file

@ -10,6 +10,10 @@ pub fn link(
host_input_path: &Path, host_input_path: &Path,
dest_filename: &Path, dest_filename: &Path,
) -> io::Result<Child> { ) -> io::Result<Child> {
// TODO we should no longer need to do this once we have platforms on
// a package repository, as we can then get precompiled hosts from there.
rebuild_host(host_input_path);
match target { match target {
Triple { Triple {
architecture: Architecture::X86_64, architecture: Architecture::X86_64,
@ -25,6 +29,68 @@ pub fn link(
} }
} }
fn rebuild_host(host_input_path: &Path) {
let c_host_src = host_input_path.with_file_name("host.c");
let c_host_dest = host_input_path.with_file_name("c_host.o");
let rust_host_src = host_input_path.with_file_name("host.rs");
let rust_host_dest = host_input_path.with_file_name("rust_host.o");
let host_dest = host_input_path.with_file_name("host.o");
// Compile host.c
Command::new("clang")
.env_clear()
.args(&[
"-c",
c_host_src.to_str().unwrap(),
"-o",
c_host_dest.to_str().unwrap(),
])
.output()
.unwrap();
if rust_host_src.exists() {
// Compile and link host.rs, if it exists
Command::new("rustc")
.args(&[
rust_host_src.to_str().unwrap(),
"-o",
rust_host_dest.to_str().unwrap(),
])
.output()
.unwrap();
Command::new("ld")
.env_clear()
.args(&[
"-r",
c_host_dest.to_str().unwrap(),
rust_host_dest.to_str().unwrap(),
"-o",
host_dest.to_str().unwrap(),
])
.output()
.unwrap();
// Clean up rust_host.o
Command::new("rm")
.env_clear()
.args(&[
"-f",
rust_host_dest.to_str().unwrap(),
c_host_dest.to_str().unwrap(),
])
.output()
.unwrap();
} else {
// Clean up rust_host.o
Command::new("mv")
.env_clear()
.args(&[c_host_dest, host_dest])
.output()
.unwrap();
}
}
fn link_linux( fn link_linux(
target: &Triple, target: &Triple,
binary_path: &Path, binary_path: &Path,
@ -34,6 +100,8 @@ fn link_linux(
// NOTE: order of arguments to `ld` matters here! // NOTE: order of arguments to `ld` matters here!
// The `-l` flags should go after the `.o` arguments // The `-l` flags should go after the `.o` arguments
Command::new("ld") Command::new("ld")
// Don't allow LD_ env vars to affect this
.env_clear()
.args(&[ .args(&[
"-arch", "-arch",
arch_str(target), arch_str(target),
@ -73,6 +141,8 @@ fn link_macos(
// NOTE: order of arguments to `ld` matters here! // NOTE: order of arguments to `ld` matters here!
// The `-l` flags should go after the `.o` arguments // The `-l` flags should go after the `.o` arguments
Command::new("ld") Command::new("ld")
// Don't allow LD_ env vars to affect this
.env_clear()
.args(&[ .args(&[
"-arch", "-arch",
target.architecture.to_string().as_str(), target.architecture.to_string().as_str(),

View file

@ -1,21 +1,8 @@
## Recompiling the platform from source # Rebuilding the host from source
This example platform for "Hello, World!" includes the same host implemented Run `build.sh` to manually rebuild this platform's host.
in two different languages—C and Rust—to demonstrate how it's done in both.
Ordinarily you'd only implement your host once, in your preferred language.
Note that the compiler currently has its own logic for rebuilding these hosts
### Recompiling the C implementation (in `link.rs`). It's hardcoded for now, but the long-term goal is that
hosts will be precompiled by platform authors and distributed in packages,
```shell at which point only package authors will need to think about rebuilding hosts.
$ clang -c host.c -o host.o
```
Then `mv` the compiled `host.o` into the apropriate subdirectory under
`host/` based on the operating system you've compiled it for.
### Recompiling the Rust implementation
```shell
$ rustc
```

View file

@ -1,49 +1,8 @@
# Rebuilding the host from source # Rebuilding the host from source
Here are the current steps to rebuild this host. These Run `build.sh` to manually rebuild this platform's host.
steps can likely be moved into a `build.rs` script after
turning `host.rs` into a `cargo` project, but that hasn't
been attempted yet.
## Compile the Rust and C sources Note that the compiler currently has its own logic for rebuilding these hosts
(in `link.rs`). It's hardcoded for now, but the long-term goal is that
Currently this host has both a `host.rs` and a `host.c`. hosts will be precompiled by platform authors and distributed in packages,
This is only because we haven't figured out a way to convince at which point only package authors will need to think about rebuilding hosts.
Rust to emit a `.o` file that doesn't define a `main` entrypoint,
but which is capable of being linked into one later.
As a workaround, we have `host.rs` expose a function called
`rust_main` instead of `main`, and all `host.c` does is provide
an actual `main` which imports and then calls `rust_main` from
the compiled `host.rs`. It's not the most elegant workaround,
but [asking on `users.rust-lang.org`](https://users.rust-lang.org/t/error-when-compiling-linking-with-o-files/49635/4)
didn't turn up any nicer approaches. Maybe they're out there though!
To make this workaround happen, we need to compile both `host.rs`
and `host.c`. First, `cd` into `platform/host/src/` and then run:
```
$ clang -c host.c -o c_host.o
$ rustc host.rs -o rust_host.o
```
Now we should have `c_host.o` and `rust_host.o` in the curent directory.
## Link together the `.o` files
Next, combine `c_host.o` and `rust_host.o` into `host.o` using `ld -r` like so:
```
$ ld -r c_host.o rust_host.o -o host.o
```
Move `host.o` into the appropriate `platform/` subdirectory
based on your architecture and operating system. For example,
on macOS, you'd move `host.o` into the `platform/host/x86_64-unknown-darwin10/` directory.
## All done!
Congratulations! You now have an updated host.
It's now fine to delete `c_host.o` and `rust_host.o`,
since they were only needed to produce `host.o`.