mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 00:24:34 +00:00
Separate hello-world platform switching into its own example
This commit is contained in:
parent
6943e742f5
commit
a9d9acb2b8
38 changed files with 213 additions and 82 deletions
|
@ -293,26 +293,25 @@ mod cli_run {
|
|||
let file_name = example_file(dir_name, example.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" => {
|
||||
// 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);
|
||||
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")) {
|
||||
eprintln!("WARNING: skipping testing example {} because it only works on MacOS.", example.filename);
|
||||
return;
|
||||
}
|
||||
}
|
||||
"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);
|
||||
|
||||
"rocLovesWeb" => {
|
||||
// this is a web assembly 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;
|
||||
}
|
||||
_ => {}
|
||||
|
@ -385,50 +384,58 @@ mod cli_run {
|
|||
examples! {
|
||||
helloWorld:"hello-world" => Example {
|
||||
filename: "main.roc",
|
||||
executable_filename: "hello",
|
||||
executable_filename: "helloWorld",
|
||||
stdin: &[],
|
||||
input_file: None,
|
||||
expected_ending:"Hello, World!\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
helloC:"hello-world/c-platform" => Example {
|
||||
filename: "helloC.roc",
|
||||
executable_filename: "helloC",
|
||||
platformSwitching:"platform-switching" => Example {
|
||||
filename: "main.roc",
|
||||
executable_filename: "rocLovesPlatforms",
|
||||
stdin: &[],
|
||||
input_file: None,
|
||||
expected_ending:"Hello, World!\n",
|
||||
expected_ending:"Which platform am I running on now?\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
helloZig:"hello-world/zig-platform" => Example {
|
||||
filename: "helloZig.roc",
|
||||
executable_filename: "helloZig",
|
||||
platformSwitchingC:"platform-switching/c-platform" => Example {
|
||||
filename: "main.roc",
|
||||
executable_filename: "rocLovesC",
|
||||
stdin: &[],
|
||||
input_file: None,
|
||||
expected_ending:"Hello, World!\n",
|
||||
expected_ending:"Roc <3 C!\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
helloRust:"hello-world/rust-platform" => Example {
|
||||
filename: "helloRust.roc",
|
||||
executable_filename: "helloRust",
|
||||
platformSwitchingRust:"platform-switching/rust-platform" => Example {
|
||||
filename: "main.roc",
|
||||
executable_filename: "rocLovesRust",
|
||||
stdin: &[],
|
||||
input_file: None,
|
||||
expected_ending:"Hello, World!\n",
|
||||
expected_ending:"Roc <3 Rust!\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
helloSwift:"hello-world/swift-platform" => Example {
|
||||
filename: "helloSwift.roc",
|
||||
executable_filename: "helloSwift",
|
||||
platformSwitchingSwift:"platform-switching/swift-platform" => Example {
|
||||
filename: "main.roc",
|
||||
executable_filename: "rocLovesSwift",
|
||||
stdin: &[],
|
||||
input_file: None,
|
||||
expected_ending:"Hello, World!\n",
|
||||
expected_ending:"Roc <3 Swift!\n",
|
||||
use_valgrind: true,
|
||||
},
|
||||
helloWeb:"hello-world/web-platform" => Example {
|
||||
filename: "helloWeb.roc",
|
||||
executable_filename: "helloWeb",
|
||||
platformSwitchingWeb:"platform-switching/web-platform" => Example {
|
||||
filename: "main.roc",
|
||||
executable_filename: "rocLovesWeb",
|
||||
stdin: &[],
|
||||
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,
|
||||
},
|
||||
fib:"algorithms" => Example {
|
||||
|
@ -804,8 +811,8 @@ mod cli_run {
|
|||
let example_dir_name = entry.file_name().into_string().unwrap();
|
||||
|
||||
// TODO: Improve this with a more-dynamic approach. (Read all subdirectories?)
|
||||
// Some hello-world examples live in nested directories
|
||||
if example_dir_name == "hello-world" {
|
||||
// Some platform-switching examples live in nested directories
|
||||
if example_dir_name == "platform-switching" {
|
||||
for sub_dir in [
|
||||
"c-platform",
|
||||
"rust-platform",
|
||||
|
|
6
examples/hello-world/.gitignore
vendored
6
examples/hello-world/.gitignore
vendored
|
@ -1,7 +1 @@
|
|||
helloC
|
||||
helloRust
|
||||
helloSwift
|
||||
helloWorld
|
||||
helloZig
|
||||
hello
|
||||
*.wasm
|
||||
|
|
|
@ -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.
|
||||
|
||||
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.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
app "hello"
|
||||
packages { pf: "c-platform/main.roc" }
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
platform "hello-world-in-c"
|
||||
platform "hello-world"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
|
@ -1,9 +0,0 @@
|
|||
platform "hello-world-in-web-assembly"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
|
@ -1,6 +0,0 @@
|
|||
app "helloZig"
|
||||
packages { pf: "main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World!\n"
|
7
examples/platform-switching/.gitignore
vendored
Normal file
7
examples/platform-switching/.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
rocLovesC
|
||||
rocLovesPlatforms
|
||||
rocLovesRust
|
||||
rocLovesSwift
|
||||
rocLovesWebAssembly
|
||||
rocLovesZig
|
||||
*.wasm
|
20
examples/platform-switching/README.md
Normal file
20
examples/platform-switching/README.md
Normal 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.
|
84
examples/platform-switching/c-platform/host.c
Normal file
84
examples/platform-switching/c-platform/host.c
Normal 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;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
platform "hello-world-in-zig"
|
||||
platform "echo-in-c"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
|
@ -1,6 +1,6 @@
|
|||
app "helloC"
|
||||
app "rocLovesC"
|
||||
packages { pf: "main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World!\n"
|
||||
main = "Roc <3 C!\n"
|
11
examples/platform-switching/main.roc
Normal file
11
examples/platform-switching/main.roc
Normal 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"
|
|
@ -1,4 +1,4 @@
|
|||
platform "hello-world-in-rust"
|
||||
platform "echo-in-rust"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
|
@ -1,6 +1,6 @@
|
|||
app "helloSwift"
|
||||
app "rocLovesRust"
|
||||
packages { pf: "main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World!\n"
|
||||
main = "Roc <3 Rust!\n"
|
|
@ -1,4 +1,4 @@
|
|||
platform "hello-world-in-swift"
|
||||
platform "echo-in-swift"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
|
@ -0,0 +1,6 @@
|
|||
app "rocLovesSwift"
|
||||
packages { pf: "main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Roc <3 Swift!\n"
|
|
@ -3,12 +3,12 @@
|
|||
To run this website, first compile either of these identical apps:
|
||||
|
||||
```bash
|
||||
# Option A: Compile helloWeb.roc
|
||||
cargo run -- build --target=wasm32 examples/hello-world/web-platform/helloWeb.roc
|
||||
# Option A: Compile examples/platform-switching/web-assembly-platform/rocLovesWeb.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
|
||||
cargo run -- build --target=wasm32 examples/hello-world/main.roc
|
||||
(cd examples/hello-world && mv helloWorld.wasm web-platform/helloWeb.wasm)
|
||||
# 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/platform-switching/main.roc
|
||||
(cd examples/platform-switching && mv rocLovesPlatforms.wasm web-assembly-platform/rocLovesWeb.wasm)
|
||||
```
|
||||
|
||||
Then `cd` into the website directory
|
||||
|
@ -16,7 +16,7 @@ and run any web server that can handle WebAssembly.
|
|||
For example, with `http-server`:
|
||||
|
||||
```bash
|
||||
cd examples/hello-world/web-platform
|
||||
cd examples/platform-switching/web-assembly-platform
|
||||
npm install -g http-server
|
||||
http-server
|
||||
```
|
9
examples/platform-switching/web-platform/main.roc
Normal file
9
examples/platform-switching/web-platform/main.roc
Normal file
|
@ -0,0 +1,9 @@
|
|||
platform "echo-in-web"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
|
@ -1,6 +1,6 @@
|
|||
app "helloWeb"
|
||||
app "rocLovesWeb"
|
||||
packages { pf: "main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World!\n"
|
||||
main = "Roc <3 Web!\n"
|
9
examples/platform-switching/zig-platform/main.roc
Normal file
9
examples/platform-switching/zig-platform/main.roc
Normal file
|
@ -0,0 +1,9 @@
|
|||
platform "echo-in-zig"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
|
@ -1,6 +1,6 @@
|
|||
app "helloRust"
|
||||
app "rocLovesZig"
|
||||
packages { pf: "main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World!\n"
|
||||
main = "Roc <3 Zig!\n"
|
|
@ -22,11 +22,11 @@
|
|||
0. Run examples with:
|
||||
```
|
||||
# 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
|
||||
./roc examples/hello-world/zig-platform/helloZig.roc --linker=legacy
|
||||
./roc examples/platform-switching/zig-platform/rocLovesZig.roc --linker=legacy
|
||||
# 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.
|
||||
|
||||
|
|
|
@ -4,11 +4,11 @@
|
|||
3. Run examples with:
|
||||
```
|
||||
# Rust
|
||||
cargo run examples/hello-world/rust-platform/helloRust.roc
|
||||
cargo run examples/platform-switching/rust-platform/rocLovesRust.roc
|
||||
# Zig
|
||||
cargo run examples/hello-world/zig-platform/helloZig.roc
|
||||
cargo run examples/platform-switching/zig-platform/rocLovesZig.roc
|
||||
# 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.
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue