Separate hello-world platform switching into its own example

This commit is contained in:
Jan Van Bruggen 2022-06-20 23:57:24 -06:00
parent 6943e742f5
commit a9d9acb2b8
38 changed files with 213 additions and 82 deletions

View file

@ -293,26 +293,25 @@ mod cli_run {
let file_name = example_file(dir_name, example.filename); let file_name = example_file(dir_name, example.filename);
match example.executable_filename { match example.executable_filename {
"helloWeb" => {
// this is a web webassembly example, but we don't test with JS at the moment
eprintln!("WARNING: skipping testing example {} because the test is broken right now!", example.filename);
return;
}
"form" => { "form" => {
// test is skipped until we upgrate to zig 0.9 / llvm 13 // test is skipped until we upgrate to zig 0.9 / llvm 13
eprintln!("WARNING: skipping testing example {} because the test is broken right now!", example.filename); eprintln!("WARNING: skipping testing example {} because the test is broken right now!", example.filename);
return; return;
} }
"helloSwift" => { "hello-gui" | "breakout" => {
// Since these require opening a window, we do `roc build` on them but don't run them.
run_roc_on(&file_name, [CMD_BUILD, OPTIMIZE_FLAG], &[], None);
return;
}
"rocLovesSwift" => {
if cfg!(not(target_os = "macos")) { if cfg!(not(target_os = "macos")) {
eprintln!("WARNING: skipping testing example {} because it only works on MacOS.", example.filename); eprintln!("WARNING: skipping testing example {} because it only works on MacOS.", example.filename);
return; return;
} }
} }
"hello-gui" | "breakout" => { "rocLovesWeb" => {
// Since these require opening a window, we do `roc build` on them but don't run them. // this is a web assembly example, but we don't test with JS at the moment
run_roc_on(&file_name, [CMD_BUILD, OPTIMIZE_FLAG], &[], None); eprintln!("WARNING: skipping testing example {} because the test is broken right now!", example.filename);
return; return;
} }
_ => {} _ => {}
@ -385,50 +384,58 @@ mod cli_run {
examples! { examples! {
helloWorld:"hello-world" => Example { helloWorld:"hello-world" => Example {
filename: "main.roc", filename: "main.roc",
executable_filename: "hello", executable_filename: "helloWorld",
stdin: &[], stdin: &[],
input_file: None, input_file: None,
expected_ending:"Hello, World!\n", expected_ending:"Hello, World!\n",
use_valgrind: true, use_valgrind: true,
}, },
helloC:"hello-world/c-platform" => Example { platformSwitching:"platform-switching" => Example {
filename: "helloC.roc", filename: "main.roc",
executable_filename: "helloC", executable_filename: "rocLovesPlatforms",
stdin: &[], stdin: &[],
input_file: None, input_file: None,
expected_ending:"Hello, World!\n", expected_ending:"Which platform am I running on now?\n",
use_valgrind: true, use_valgrind: true,
}, },
helloZig:"hello-world/zig-platform" => Example { platformSwitchingC:"platform-switching/c-platform" => Example {
filename: "helloZig.roc", filename: "main.roc",
executable_filename: "helloZig", executable_filename: "rocLovesC",
stdin: &[], stdin: &[],
input_file: None, input_file: None,
expected_ending:"Hello, World!\n", expected_ending:"Roc <3 C!\n",
use_valgrind: true, use_valgrind: true,
}, },
helloRust:"hello-world/rust-platform" => Example { platformSwitchingRust:"platform-switching/rust-platform" => Example {
filename: "helloRust.roc", filename: "main.roc",
executable_filename: "helloRust", executable_filename: "rocLovesRust",
stdin: &[], stdin: &[],
input_file: None, input_file: None,
expected_ending:"Hello, World!\n", expected_ending:"Roc <3 Rust!\n",
use_valgrind: true, use_valgrind: true,
}, },
helloSwift:"hello-world/swift-platform" => Example { platformSwitchingSwift:"platform-switching/swift-platform" => Example {
filename: "helloSwift.roc", filename: "main.roc",
executable_filename: "helloSwift", executable_filename: "rocLovesSwift",
stdin: &[], stdin: &[],
input_file: None, input_file: None,
expected_ending:"Hello, World!\n", expected_ending:"Roc <3 Swift!\n",
use_valgrind: true, use_valgrind: true,
}, },
helloWeb:"hello-world/web-platform" => Example { platformSwitchingWeb:"platform-switching/web-platform" => Example {
filename: "helloWeb.roc", filename: "main.roc",
executable_filename: "helloWeb", executable_filename: "rocLovesWeb",
stdin: &[], stdin: &[],
input_file: None, input_file: None,
expected_ending:"Hello, World!\n", expected_ending:"Roc <3 Web!\n",
use_valgrind: true,
},
platformSwitchingZig:"platform-switching/zig-platform" => Example {
filename: "main.roc",
executable_filename: "rocLovesZig",
stdin: &[],
input_file: None,
expected_ending:"Roc <3 Zig!\n",
use_valgrind: true, use_valgrind: true,
}, },
fib:"algorithms" => Example { fib:"algorithms" => Example {
@ -804,8 +811,8 @@ mod cli_run {
let example_dir_name = entry.file_name().into_string().unwrap(); let example_dir_name = entry.file_name().into_string().unwrap();
// TODO: Improve this with a more-dynamic approach. (Read all subdirectories?) // TODO: Improve this with a more-dynamic approach. (Read all subdirectories?)
// Some hello-world examples live in nested directories // Some platform-switching examples live in nested directories
if example_dir_name == "hello-world" { if example_dir_name == "platform-switching" {
for sub_dir in [ for sub_dir in [
"c-platform", "c-platform",
"rust-platform", "rust-platform",

View file

@ -1,7 +1 @@
helloC
helloRust
helloSwift
helloWorld
helloZig
hello hello
*.wasm

View file

@ -13,6 +13,5 @@ defaults to running a file named `main.roc`. Other `roc` commands (like `roc bui
This uses a very simple platform which does nothing more than printing the string you give it. This uses a very simple platform which does nothing more than printing the string you give it.
The line `main = "Hello, World!\n"` sets this string to be `"Hello, World!"` with a newline at the end, and the lines `packages { pf: "c-platform/hello.roc" }` and `provides [main] to pf` specify that the `c-platform/` directory contains this app's platform. The line `main = "Hello, World!\n"` sets this string to be `"Hello, World!"` with a newline at the end, and the lines `packages { pf: "platform/main.roc" }` and `provides [main] to pf` specify that the `platform/` directory contains this app's platform.
This platform is called `c-platform` because its low-level code is written in C. There's also a `rust-platform`, `zig-platform`, and so on; if you like, you can try switching `"c-platform/main.roc"` to `"zig-platform/main.roc"` or `"rust-platform/main.roc"` to try one of those platforms instead. They all do the same thing, so the application won't look any different, but if you want to start building your own platforms, this Hello World example gives you some very simple platforms to use as starting points too.

View file

@ -1,5 +1,5 @@
app "hello" app "hello"
packages { pf: "c-platform/main.roc" } packages { pf: "platform/main.roc" }
imports [] imports []
provides [main] to pf provides [main] to pf

View file

@ -1,4 +1,4 @@
platform "hello-world-in-c" platform "hello-world"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,9 +0,0 @@
platform "hello-world-in-web-assembly"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main

View file

@ -1,6 +0,0 @@
app "helloZig"
packages { pf: "main.roc" }
imports []
provides [main] to pf
main = "Hello, World!\n"

View file

@ -0,0 +1,7 @@
rocLovesC
rocLovesPlatforms
rocLovesRust
rocLovesSwift
rocLovesWebAssembly
rocLovesZig
*.wasm

View file

@ -0,0 +1,20 @@
# Platform switching
To run, `cd` into this directory and run this in your terminal:
```bash
roc run
```
This will run `main.roc` because, unless you explicitly give it a filename, `roc run`
defaults to running a file named `main.roc`. Other `roc` commands (like `roc build`, `roc test`, and so on) also default to `main.roc` unless you explicitly give them a filename.
# About this example
This uses a very simple platform which does nothing more than printing the string you give it.
The line `main = "Which platform am I running on now?\n"` sets this string to be `"Which platform am I running on now?"` with a newline at the end, and the lines `packages { pf: "c-platform/main.roc" }` and `provides [main] to pf` specify that the `c-platform/` directory contains this app's platform.
This platform is called `c-platform` because its lower-level code is written in C. There's also a `rust-platform`, `zig-platform`, and so on; if you like, you can try switching `pf: "c-platform/main.roc"` to `pf: "zig-platform/main.roc"` or `pf: "rust-platform/main.roc"` to try one of those platforms instead. They all do similar things, so the application won't look any different.
If you want to start building your own platforms, these are some very simple example platforms to use as starting points.

View file

@ -0,0 +1,84 @@
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void* roc_alloc(size_t size, unsigned int alignment) { return malloc(size); }
void* roc_realloc(void* ptr, size_t new_size, size_t old_size,
unsigned int alignment) {
return realloc(ptr, new_size);
}
void roc_dealloc(void* ptr, unsigned int alignment) { free(ptr); }
void roc_panic(void* ptr, unsigned int alignment) {
char* msg = (char*)ptr;
fprintf(stderr,
"Application crashed with message\n\n %s\n\nShutting down\n", msg);
exit(0);
}
void* roc_memcpy(void* dest, const void* src, size_t n) {
return memcpy(dest, src, n);
}
void* roc_memset(void* str, int c, size_t n) { return memset(str, c, n); }
struct RocStr {
char* bytes;
size_t len;
size_t capacity;
};
bool is_small_str(struct RocStr str) { return ((ssize_t)str.capacity) < 0; }
// Determine the length of the string, taking into
// account the small string optimization
size_t roc_str_len(struct RocStr str) {
char* bytes = (char*)&str;
char last_byte = bytes[sizeof(str) - 1];
char last_byte_xored = last_byte ^ 0b10000000;
size_t small_len = (size_t)(last_byte_xored);
size_t big_len = str.len;
// Avoid branch misprediction costs by always
// determining both small_len and big_len,
// so this compiles to a cmov instruction.
if (is_small_str(str)) {
return small_len;
} else {
return big_len;
}
}
extern void roc__mainForHost_1_exposed_generic(struct RocStr *string);
int main() {
struct RocStr str;
roc__mainForHost_1_exposed_generic(&str);
// Determine str_len and the str_bytes pointer,
// taking into account the small string optimization.
size_t str_len = roc_str_len(str);
char* str_bytes;
if (is_small_str(str)) {
str_bytes = (char*)&str;
} else {
str_bytes = str.bytes;
}
// Write to stdout
if (write(1, str_bytes, str_len) >= 0) {
// Writing succeeded!
return 0;
} else {
printf("Error writing to stdout: %s\n", strerror(errno));
return 1;
}
}

View file

@ -1,4 +1,4 @@
platform "hello-world-in-zig" platform "echo-in-c"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,6 +1,6 @@
app "helloC" app "rocLovesC"
packages { pf: "main.roc" } packages { pf: "main.roc" }
imports [] imports []
provides [main] to pf provides [main] to pf
main = "Hello, World!\n" main = "Roc <3 C!\n"

View file

@ -0,0 +1,11 @@
app "rocLovesPlatforms"
packages { pf: "c-platform/main.roc" }
# To switch platforms, comment-out the line above and un-comment one below.
# packages { pf: "rust-platform/main.roc" }
# packages { pf: "swift-platform/main.roc" }
# packages { pf: "web-platform/main.roc" } # See ./web-platform/README.md
# packages { pf: "zig-platform/main.roc" }
imports []
provides [main] to pf
main = "Which platform am I running on now?\n"

View file

@ -1,4 +1,4 @@
platform "hello-world-in-rust" platform "echo-in-rust"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -1,6 +1,6 @@
app "helloSwift" app "rocLovesRust"
packages { pf: "main.roc" } packages { pf: "main.roc" }
imports [] imports []
provides [main] to pf provides [main] to pf
main = "Hello, World!\n" main = "Roc <3 Rust!\n"

View file

@ -1,4 +1,4 @@
platform "hello-world-in-swift" platform "echo-in-swift"
requires {} { main : Str } requires {} { main : Str }
exposes [] exposes []
packages {} packages {}

View file

@ -0,0 +1,6 @@
app "rocLovesSwift"
packages { pf: "main.roc" }
imports []
provides [main] to pf
main = "Roc <3 Swift!\n"

View file

@ -3,12 +3,12 @@
To run this website, first compile either of these identical apps: To run this website, first compile either of these identical apps:
```bash ```bash
# Option A: Compile helloWeb.roc # Option A: Compile examples/platform-switching/web-assembly-platform/rocLovesWeb.roc
cargo run -- build --target=wasm32 examples/hello-world/web-platform/helloWeb.roc cargo run -- build --target=wasm32 examples/platform-switching/web-assembly-platform/rocLovesWeb.roc
# Option B: Compile helloWorld.roc with `pf: "web-platform"` and move the result # Option B: Compile examples/platform-switching/main.roc with `pf: "web-assembly-platform/main.roc"` and move the result
cargo run -- build --target=wasm32 examples/hello-world/main.roc cargo run -- build --target=wasm32 examples/platform-switching/main.roc
(cd examples/hello-world && mv helloWorld.wasm web-platform/helloWeb.wasm) (cd examples/platform-switching && mv rocLovesPlatforms.wasm web-assembly-platform/rocLovesWeb.wasm)
``` ```
Then `cd` into the website directory Then `cd` into the website directory
@ -16,7 +16,7 @@ and run any web server that can handle WebAssembly.
For example, with `http-server`: For example, with `http-server`:
```bash ```bash
cd examples/hello-world/web-platform cd examples/platform-switching/web-assembly-platform
npm install -g http-server npm install -g http-server
http-server http-server
``` ```

View file

@ -0,0 +1,9 @@
platform "echo-in-web"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main

View file

@ -1,6 +1,6 @@
app "helloWeb" app "rocLovesWeb"
packages { pf: "main.roc" } packages { pf: "main.roc" }
imports [] imports []
provides [main] to pf provides [main] to pf
main = "Hello, World!\n" main = "Roc <3 Web!\n"

View file

@ -0,0 +1,9 @@
platform "echo-in-zig"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : Str
mainForHost = main

View file

@ -1,6 +1,6 @@
app "helloRust" app "rocLovesZig"
packages { pf: "main.roc" } packages { pf: "main.roc" }
imports [] imports []
provides [main] to pf provides [main] to pf
main = "Hello, World!\n" main = "Roc <3 Zig!\n"

View file

@ -22,11 +22,11 @@
0. Run examples with: 0. Run examples with:
``` ```
# Rust. If you installed rust in this terminal you'll need to open a new one first! # Rust. If you installed rust in this terminal you'll need to open a new one first!
./roc examples/hello-world/rust-platform/helloRust.roc ./roc examples/platform-switching/rust-platform/rocLovesRust.roc
# Zig # Zig
./roc examples/hello-world/zig-platform/helloZig.roc --linker=legacy ./roc examples/platform-switching/zig-platform/rocLovesZig.roc --linker=legacy
# C # C
./roc examples/hello-world/c-platform/helloC.roc --linker=legacy ./roc examples/platform-switching/c-platform/rocLovesC.roc --linker=legacy
``` ```
0. See [here](../README.md#examples) for the other examples. 0. See [here](../README.md#examples) for the other examples.

View file

@ -4,11 +4,11 @@
3. Run examples with: 3. Run examples with:
``` ```
# Rust # Rust
cargo run examples/hello-world/rust-platform/helloRust.roc cargo run examples/platform-switching/rust-platform/rocLovesRust.roc
# Zig # Zig
cargo run examples/hello-world/zig-platform/helloZig.roc cargo run examples/platform-switching/zig-platform/rocLovesZig.roc
# C # C
cargo run examples/hello-world/c-platform/helloC.roc cargo run examples/platform-switching/c-platform/rocLovesC.roc
``` ```
4. See [here](../README.md#examples) for the other examples. 4. See [here](../README.md#examples) for the other examples.