diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5193fead..d874d8c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -on: +on: pull_request: workflow_dispatch: @@ -8,7 +8,6 @@ concurrency: cancel-in-progress: true jobs: - build-and-test-native: runs-on: ${{ matrix.operating-system }} strategy: @@ -24,7 +23,7 @@ jobs: continue-on-error: true run: | curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-TESTING.tar.gz - + - name: There are no TESTING releases, checking regular releases instead if: steps.try_fetching_testing_release.outcome == 'failure' run: | @@ -49,6 +48,9 @@ jobs: - run: expect -v + - name: Build platform binary + run: ./roc_nightly/roc ./build.roc + - name: Run all tests run: ROC=./roc_nightly/roc EXAMPLES_DIR=./examples/ ./ci/all_tests.sh @@ -58,6 +60,3 @@ jobs: # Workaround for https://github.com/roc-lang/roc/issues/6688 - name: Check if crash occurred run: grep -zqv "crashed" all_tests_output.log - -# TODO clippy, rustfmt, roc fmt check - diff --git a/Cargo.lock b/Cargo.lock index 0c6bc9bf..593fd0bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -206,13 +206,7 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" name = "host" version = "0.0.1" dependencies = [ - "backtrace", - "crossterm", - "hyper", - "hyper-rustls", - "libc", - "roc_std", - "tokio", + "roc_host", ] [[package]] @@ -519,6 +513,34 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "roc_app" +version = "1.0.0" +dependencies = [ + "roc_std", +] + +[[package]] +name = "roc_host" +version = "0.0.1" +dependencies = [ + "backtrace", + "crossterm", + "hyper", + "hyper-rustls", + "libc", + "roc_app", + "roc_std", + "tokio", +] + +[[package]] +name = "roc_host_bin" +version = "0.0.1" +dependencies = [ + "roc_host", +] + [[package]] name = "roc_std" version = "0.0.1" diff --git a/Cargo.toml b/Cargo.toml index 6fe8df40..4be72881 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,14 @@ [workspace] resolver = "2" members = [ - "crates/host", + "crates/roc_host", + "crates/roc_host_lib", + "crates/roc_host_bin", "crates/roc_app", "crates/roc_std", -] \ No newline at end of file +] + +[profile.release] +lto = true +strip = "debuginfo" +codegen-units = 1 diff --git a/build.roc b/build.roc index 4e6874d7..df960806 100644 --- a/build.roc +++ b/build.roc @@ -1,13 +1,14 @@ -app "build-platform-prebuilt-binaries" - packages { - cli: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br", - } - imports [ - cli.Task.{Task}, - cli.Stdout, - cli.Cmd, - ] - provides [main] to cli +app [main] { + cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.11.0/SY4WWMhWQ9NvQgvIthcv15AUeA7rAIJHAHgiaSHGhdY.tar.br", + weaver: "https://github.com/smores56/weaver/releases/download/0.2.0/BBDPvzgGrYp-AhIDw0qmwxT0pWZIQP_7KOrUrZfp_xw.tar.br", +} + +import cli.Task exposing [Task] +import cli.Cmd +import cli.Stdout +import cli.Arg +import weaver.Opt +import weaver.Cli RocTarget : [ MacosArm64, @@ -18,120 +19,134 @@ RocTarget : [ WindowsX64, ] -mode : [DEBUG, RELEASE] -mode = DEBUG - -main = - native = getNativeTarget! - removePrebuiltBinary! native - buildRustTarget! native - copyBinaryToPlatform! native - Stdout.line! "COMPLETE" - - Task.ok {} +main = + + cliParser = + Cli.weave { + release: <- Opt.flag { short: "r", help: "Release build" }, + } + |> Cli.finish { + name: "basic-webserver", + version: "", + authors: ["Luke Boswell "], + description: "This build script generates the binaries and packages the platform for distribution.", + } + |> Cli.assertValid + + when Cli.parseOrDisplayMessage cliParser (Arg.list!) is + Ok args -> run args + Err message -> Task.err (Exit 1 message) + +run = \{ release } -> + + # generate glue for builtins + printInfoLine! "generating glue for builtins" + Cmd.exec "roc" ["glue", "glue.roc", "crates/", "platform/main.roc"] + |> Task.mapErr! ErrGeneratingGlue + + # get the roc target for the native machine + target = getNativeTarget! + + # build the app stub shared library (for processing surgical linker binaries) + appStubBuildPath = "platform/libapp.$(appStubExt target)" + printInfoLine! "roc build the app stub shared library at $(appStubBuildPath)" + Cmd.exec "roc" ["build", "--lib", "platform/libapp.roc"] + |> Task.mapErr! ErrBuildingAppStub + + # build the roc host binaries + (cargoBuildArgs, message) = + if release then + (["build", "--release"], "building roc host binaries in release mode") + else + (["build"], "building roc host binaries in debug mode") + + printInfoLine! message + Cmd.exec "cargo" cargoBuildArgs + |> Task.mapErr! ErrBuildingRocHostBinaries + + # move the prebuilt binary to the platform directory + prebuiltLegacyBinaryBuildPath = + if release then + "target/release/libhost.a" + else + "target/debug/libhost.a" + + prebuiltLegacyBinaryPath = "platform/$(prebuiltBinaryName target)" + printInfoLine! "moving the prebuilt binary from $(prebuiltLegacyBinaryBuildPath) to $(prebuiltLegacyBinaryPath)" + Cmd.exec "cp" [prebuiltLegacyBinaryBuildPath, prebuiltLegacyBinaryPath] + |> Task.mapErr! ErrMovingPrebuiltLegacyBinary + + #SURGICAL LINKER IS NOT YET SUPPORTED need to merge https://github.com/roc-lang/roc/pull/6808 + #prebuiltSurgicalBinaryBuildPath = + # if release then + # "target/release/host" + # else + # "target/debug/host" + #Cmd.exec "roc" ["preprocess-host", prebuiltSurgicalBinaryBuildPath, "platform/main.roc", "platform/libapp.$(appStubExt target)"] + #|> Task.mapErr! ErrPreprocessingSurgicalBinary getNativeTarget : Task RocTarget _ -getNativeTarget = +getNativeTarget = - Stdout.line! "Geting native target..." + printInfoLine! "geting native target using uname" - archFromStr = \bytes -> - when Str.fromUtf8 bytes is + archFromStr = \bytes -> + when Str.fromUtf8 bytes is Ok str if str == "arm64\n" -> Arm64 Ok str if str == "x86_64\n" -> X64 Ok str -> UnsupportedArch str _ -> crash "invalid utf8 from uname -m" - arch = + arch = Cmd.new "uname" - |> Cmd.arg "-m" - |> Cmd.output - |> Task.map .stdout - |> Task.map archFromStr - |> Task.mapErr! \err -> ErrGettingNativeArch (Inspect.toStr err) - - osFromStr = \bytes -> - when Str.fromUtf8 bytes is + |> Cmd.arg "-m" + |> Cmd.output + |> Task.map .stdout + |> Task.map archFromStr + |> Task.mapErr! ErrGettingNativeArch + + osFromStr = \bytes -> + when Str.fromUtf8 bytes is Ok str if str == "Darwin\n" -> Macos Ok str if str == "Linux\n" -> Linux Ok str -> UnsupportedOS str _ -> crash "invalid utf8 from uname -s" - os = + os = Cmd.new "uname" - |> Cmd.arg "-s" - |> Cmd.output - |> Task.map .stdout - |> Task.map osFromStr - |> Task.mapErr! \err -> ErrGettingNativeOS (Inspect.toStr err) + |> Cmd.arg "-s" + |> Cmd.output + |> Task.map .stdout + |> Task.map osFromStr + |> Task.mapErr! ErrGettingNativeOS - when (os, arch) is + when (os, arch) is (Macos, Arm64) -> Task.ok MacosArm64 (Macos, X64) -> Task.ok MacosX64 (Linux, Arm64) -> Task.ok LinuxArm64 (Linux, X64) -> Task.ok LinuxX64 _ -> Task.err (UnsupportedNative os arch) -prebuiltBinaryPath : RocTarget -> Str -prebuiltBinaryPath = \target -> - when target is - MacosArm64 -> "platform/macos-arm64.a" - MacosX64 -> "platform/macos-x64" - LinuxArm64 -> "platform/linux-arm64.a" - LinuxX64 -> "platform/linux-x64.a" - WindowsArm64 -> "platform/windows-arm64.a" - WindowsX64 -> "platform/windows-x64" - -removePrebuiltBinary : RocTarget -> Task {} _ -removePrebuiltBinary = \target -> - - Stdout.line! "Removing prebuilt binary $(Inspect.toStr target)..." - - Cmd.new "rm" - |> Cmd.args ["-f", prebuiltBinaryPath target] - |> Cmd.status - |> Task.mapErr! ErrRemovingPrebuiltBinary - -rustupTarget : RocTarget -> Str -rustupTarget = \target -> +appStubExt : RocTarget -> Str +appStubExt = \target -> + when target is + MacosArm64 -> "dylib" + MacosX64 -> "dylib" + LinuxArm64 -> "so" + LinuxX64 -> "so" + WindowsArm64 -> "dll" + WindowsX64 -> "dll" + +prebuiltBinaryName : RocTarget -> Str +prebuiltBinaryName = \target -> when target is - MacosArm64 -> "aarch64-apple-darwin" - MacosX64 -> "x86_64-apple-darwin" - LinuxArm64 -> "aarch64-unknown-linux-musl" - LinuxX64 -> "x86_64-unknown-linux-musl" - WindowsArm64 -> "aarch64-pc-windows-msvc" - WindowsX64 -> "x86_64-pc-windows-msvc" - -buildRustTarget : RocTarget -> Task {} _ -buildRustTarget = \target -> - - Stdout.line! "Building rust target $(Inspect.toStr target)..." - - args = - when mode is - DEBUG -> ["build", "--target=$(rustupTarget target)"] - RELEASE -> ["build", "--release", "--target=$(rustupTarget target)"] - - Cmd.new "cargo" - |> Cmd.args args - |> Cmd.status - |> Task.mapErr! ErrBuildingRustTarget - -cargoTargetPath : RocTarget -> Str -cargoTargetPath = \target -> - when mode is - DEBUG -> "target/$(rustupTarget target)/debug/libhost.a" - RELEASE -> "target/$(rustupTarget target)/release/libhost.a" - -copyBinaryToPlatform : RocTarget -> Task {} _ -copyBinaryToPlatform = \target -> - - from = cargoTargetPath target - to = prebuiltBinaryPath target - - Stdout.line! "Copy prebuilt binary from $(from) to $(to)..." - - Cmd.new "cp" - |> Cmd.args ["-f", from, to] - |> Cmd.status - |> Task.mapErr! ErrCopyingPrebuiltBinary + MacosArm64 -> "macos-arm64.a" + MacosX64 -> "macos-x64" + LinuxArm64 -> "linux-arm64.a" + LinuxX64 -> "linux-x64.a" + WindowsArm64 -> "windows-arm64.lib" + WindowsX64 -> "windows-x64.lib" + +printInfoLine : Str -> Task {} _ +printInfoLine = \msg -> + Stdout.line! "\u(001b)[34mROC BUILD INFO:\u(001b)[0m $(msg)" diff --git a/ci/all_tests.sh b/ci/all_tests.sh index b6c770fd..7c2f141a 100755 --- a/ci/all_tests.sh +++ b/ci/all_tests.sh @@ -5,7 +5,7 @@ set -exo pipefail if [ -z "${EXAMPLES_DIR}" ]; then echo "ERROR: The EXAMPLES_DIR environment variable is not set." >&2 - + exit 1 fi @@ -35,7 +35,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do continue fi - $ROC build $roc_file $ROC_BUILD_FLAGS + $ROC build --linker=legacy $roc_file $ROC_BUILD_FLAGS done # prep for next step @@ -88,7 +88,7 @@ for roc_file in $EXAMPLES_DIR*.roc; do $absolute_roc dev $base_file $ROC_BUILD_FLAGS cd .. else - $ROC dev $roc_file $ROC_BUILD_FLAGS + $ROC dev --linker=legacy $roc_file $ROC_BUILD_FLAGS fi done diff --git a/crates/host/Cargo.toml b/crates/roc_host/Cargo.toml similarity index 80% rename from crates/host/Cargo.toml rename to crates/roc_host/Cargo.toml index 6bf3090c..6973fdf9 100644 --- a/crates/host/Cargo.toml +++ b/crates/roc_host/Cargo.toml @@ -1,19 +1,14 @@ [package] -name = "host" +name = "roc_host" version = "0.0.1" authors = ["The Roc Contributors"] license = "UPL-1.0" edition = "2021" -[profile.release] -lto = true -strip = "debuginfo" -codegen-units = 1 - [lib] -name = "host" +name = "roc_host" path = "src/lib.rs" -crate-type = ["staticlib"] +crate-type = ["lib"] [dependencies] roc_std = { path = "../crates/roc_std" } diff --git a/crates/host/src/lib.rs b/crates/roc_host/src/lib.rs similarity index 99% rename from crates/host/src/lib.rs rename to crates/roc_host/src/lib.rs index 1344ae0a..6b8e5d81 100644 --- a/crates/host/src/lib.rs +++ b/crates/roc_host/src/lib.rs @@ -320,7 +320,7 @@ pub fn init() { } #[no_mangle] -pub extern "C" fn main() -> i32 { +pub extern "C" fn rust_main() -> i32 { init(); let size = unsafe { roc_main_size() } as usize; let layout = Layout::array::(size).unwrap(); diff --git a/crates/roc_host_bin/Cargo.toml b/crates/roc_host_bin/Cargo.toml new file mode 100644 index 00000000..2b336dcd --- /dev/null +++ b/crates/roc_host_bin/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "roc_host_bin" +version = "0.0.1" +authors = ["The Roc Contributors"] +license = "UPL-1.0" +edition = "2021" + +links = "app" + +[[bin]] +name = "host" +path = "src/main.rs" + +[dependencies] +roc_host = { path = "../roc_host" } diff --git a/crates/roc_host_bin/build.rs b/crates/roc_host_bin/build.rs new file mode 100644 index 00000000..5af62787 --- /dev/null +++ b/crates/roc_host_bin/build.rs @@ -0,0 +1,9 @@ +fn main() { + println!("cargo:rustc-link-search=platform/"); + + #[cfg(not(windows))] + println!("cargo:rustc-link-lib=dylib=app"); + + #[cfg(windows)] + println!("cargo:rustc-link-lib=dylib=libapp"); +} diff --git a/crates/roc_host_bin/src/main.rs b/crates/roc_host_bin/src/main.rs new file mode 100644 index 00000000..69ff4189 --- /dev/null +++ b/crates/roc_host_bin/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(roc_host::rust_main()); +} diff --git a/crates/roc_host_lib/Cargo.toml b/crates/roc_host_lib/Cargo.toml new file mode 100644 index 00000000..4eb86d63 --- /dev/null +++ b/crates/roc_host_lib/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "host" +version = "0.0.1" +authors = ["The Roc Contributors"] +license = "UPL-1.0" +edition = "2021" + +[lib] +name = "host" +path = "src/lib.rs" +crate-type = ["staticlib"] + +[dependencies] +roc_host = { path = "../roc_host" } diff --git a/crates/roc_host_lib/src/lib.rs b/crates/roc_host_lib/src/lib.rs new file mode 100644 index 00000000..debb8563 --- /dev/null +++ b/crates/roc_host_lib/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn main() { + roc_host::rust_main(); +} diff --git a/crates/roc_std/src/lib.rs b/crates/roc_std/src/lib.rs index 677c4f63..30cdcdbb 100644 --- a/crates/roc_std/src/lib.rs +++ b/crates/roc_std/src/lib.rs @@ -377,10 +377,6 @@ impl RocDec { } } - pub fn from_str_to_i128_unsafe(val: &str) -> i128 { - Self::from_str(val).unwrap().as_i128() - } - /// This is private because RocDec being an i128 is an implementation detail #[inline(always)] fn as_i128(&self) -> i128 { diff --git a/crates/roc_std/src/roc_dict.rs b/crates/roc_std/src/roc_dict.rs index 918c9558..e46c3a45 100644 --- a/crates/roc_std/src/roc_dict.rs +++ b/crates/roc_std/src/roc_dict.rs @@ -108,9 +108,7 @@ impl Debug for RocDict { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("RocDict ")?; - f.debug_map() - .entries(self.iter().map(|(k, v)| (k, v))) - .finish() + f.debug_map().entries(self.iter()).finish() } } diff --git a/flake.nix b/flake.nix index d41396d0..33cf2ea1 100644 --- a/flake.nix +++ b/flake.nix @@ -38,6 +38,7 @@ darwinInputs = with pkgs; lib.optionals stdenv.isDarwin (with pkgs.darwin.apple_sdk.frameworks; [ + Security ]); sharedInputs = (with pkgs; [ diff --git a/glue.roc b/glue.roc new file mode 100644 index 00000000..668ab7a2 --- /dev/null +++ b/glue.roc @@ -0,0 +1,10 @@ +app [makeGlue] { + pf: platform "https://github.com/lukewilliamboswell/roc/releases/download/test/olBfrjtI-HycorWJMxdy7Dl2pcbbBoJy4mnSrDtRrlI.tar.br", + glue: "https://github.com/lukewilliamboswell/roc-glue-code-gen/releases/download/0.1.0/NprKi63CKBinQjoke2ttsOTHmjmsrmsILzRgzlds02c.tar.br", +} + +import glue.Rust + +# generate the std lib builtins from the Rust glue code package + +makeGlue = \_ -> Ok Rust.builtins diff --git a/platform/libapp.roc b/platform/libapp.roc new file mode 100644 index 00000000..fd4182dd --- /dev/null +++ b/platform/libapp.roc @@ -0,0 +1,14 @@ +app "stub" + packages { pf: "main.roc" } + imports [pf.Task.{ Task }] + provides [main] to pf + +# Throw an error here so we can easily confirm the host +# executable built correctly just by running it. +# +# e.g. +# ``` +# $ ./target/debug/host +# Program exited early with error: JustAStub +# ``` +main = Task.err (JustAStub)