release: publish compiler and static runtime
a52696f parent: 0c2e37c modified
.github/workflows/release.yml +13 -22 | @@ -69,35 +69,24 @@ jobs: | ||
| 69 | 69 | nim c -d:release --app:staticlib --nimMainPrefix:ClonimRuntime \ |
| 70 | 70 | --hints:off --warnings:off --nimcache:lib/nimcache-release \ |
| 71 | 71 | -o:lib/libclonim_runtime.a src/runtime_lib.nim |
| 72 | - nim c -d:release --hints:off --warnings:off \ | |
| 72 | + nim c -d:release -d:releaseCompiler --hints:off --warnings:off \ | |
| 73 | 73 | -o:bin/clonim src/clonim.nim |
| 74 | 74 | |
| 75 | 75 | - name: Package release |
| 76 | - env: | |
| 77 | - ARCHIVE_ROOT: clonim-linux-x86_64 | |
| 78 | 76 | run: | |
| 79 | - install -Dm755 bin/clonim "dist/$ARCHIVE_ROOT/bin/clonim" | |
| 80 | - install -Dm644 lib/libclonim_runtime.a \ | |
| 81 | - "dist/$ARCHIVE_ROOT/lib/libclonim_runtime.a" | |
| 82 | - install -Dm644 lib/libclonim_runtime_debug.a \ | |
| 83 | - "dist/$ARCHIVE_ROOT/lib/libclonim_runtime_debug.a" | |
| 84 | - install -Dm644 src/app_runtime.nim \ | |
| 85 | - "dist/$ARCHIVE_ROOT/src/app_runtime.nim" | |
| 86 | - install -Dm644 src/runtime_types.nim \ | |
| 87 | - "dist/$ARCHIVE_ROOT/src/runtime_types.nim" | |
| 88 | - cp -R stdlib "dist/$ARCHIVE_ROOT/stdlib" | |
| 89 | - cp README.md "dist/$ARCHIVE_ROOT/README.md" | |
| 90 | - tar -C dist -czf "dist/$ARCHIVE_ROOT.tar.gz" "$ARCHIVE_ROOT" | |
| 77 | + install -Dm755 bin/clonim dist/clonim-linux-x86_64 | |
| 78 | + install -Dm644 lib/libclonim_runtime.a dist/libclonim_runtime.a | |
| 91 | 79 | cd dist |
| 92 | - sha256sum "$ARCHIVE_ROOT.tar.gz" > "$ARCHIVE_ROOT.tar.gz.sha256" | |
| 80 | + sha256sum clonim-linux-x86_64 libclonim_runtime.a > SHA256SUMS | |
| 93 | 81 | |
| 94 | 82 | - name: Upload workflow artifact |
| 95 | 83 | uses: actions/upload-artifact@v4 |
| 96 | 84 | with: |
| 97 | 85 | name: clonim-${{ steps.release.outputs.tag }}-linux-x86_64 |
| 98 | 86 | path: | |
| 99 | - dist/clonim-linux-x86_64.tar.gz | |
| 100 | - dist/clonim-linux-x86_64.tar.gz.sha256 | |
| 87 | + dist/clonim-linux-x86_64 | |
| 88 | + dist/libclonim_runtime.a | |
| 89 | + dist/SHA256SUMS | |
| 101 | 90 | if-no-files-found: error |
| 102 | 91 | retention-days: 90 |
| 103 | 92 | |
| @@ -109,11 +98,13 @@ jobs: | ||
| 109 | 98 | body: | |
| 110 | 99 | Linux x86_64 release of clonim. |
| 111 | 100 | |
| 112 | - The archive contains the compiler, its matched private static | |
| 113 | - runtime archives, runtime interface, and clonim standard library. | |
| 101 | + Download `clonim-linux-x86_64` and `libclonim_runtime.a` into the | |
| 102 | + same directory. Generated programs statically link the runtime and | |
| 103 | + are standalone. Nim must be installed as the native-code backend. | |
| 114 | 104 | draft: false |
| 115 | 105 | prerelease: false |
| 116 | 106 | files: | |
| 117 | - dist/clonim-linux-x86_64.tar.gz | |
| 118 | - dist/clonim-linux-x86_64.tar.gz.sha256 | |
| 107 | + dist/clonim-linux-x86_64 | |
| 108 | + dist/libclonim_runtime.a | |
| 109 | + dist/SHA256SUMS | |
| 119 | 110 | fail_on_unmatched_files: true |
| @@ -69,35 +69,24 @@ jobs: | |||
| 69 | nim c -d:release --app:staticlib --nimMainPrefix:ClonimRuntime \ | 69 | nim c -d:release --app:staticlib --nimMainPrefix:ClonimRuntime \ |
| 70 | --hints:off --warnings:off --nimcache:lib/nimcache-release \ | 70 | --hints:off --warnings:off --nimcache:lib/nimcache-release \ |
| 71 | -o:lib/libclonim_runtime.a src/runtime_lib.nim | 71 | -o:lib/libclonim_runtime.a src/runtime_lib.nim |
| 72 | - nim c -d:release --hints:off --warnings:off \ | 72 | + nim c -d:release -d:releaseCompiler --hints:off --warnings:off \ |
| 73 | -o:bin/clonim src/clonim.nim | 73 | -o:bin/clonim src/clonim.nim |
| 74 | 74 | ||
| 75 | - name: Package release | 75 | - name: Package release |
| 76 | - env: | ||
| 77 | - ARCHIVE_ROOT: clonim-linux-x86_64 | ||
| 78 | run: | | 76 | run: | |
| 79 | - install -Dm755 bin/clonim "dist/$ARCHIVE_ROOT/bin/clonim" | 77 | + install -Dm755 bin/clonim dist/clonim-linux-x86_64 |
| 80 | - install -Dm644 lib/libclonim_runtime.a \ | 78 | + install -Dm644 lib/libclonim_runtime.a dist/libclonim_runtime.a |
| 81 | - "dist/$ARCHIVE_ROOT/lib/libclonim_runtime.a" | ||
| 82 | - install -Dm644 lib/libclonim_runtime_debug.a \ | ||
| 83 | - "dist/$ARCHIVE_ROOT/lib/libclonim_runtime_debug.a" | ||
| 84 | - install -Dm644 src/app_runtime.nim \ | ||
| 85 | - "dist/$ARCHIVE_ROOT/src/app_runtime.nim" | ||
| 86 | - install -Dm644 src/runtime_types.nim \ | ||
| 87 | - "dist/$ARCHIVE_ROOT/src/runtime_types.nim" | ||
| 88 | - cp -R stdlib "dist/$ARCHIVE_ROOT/stdlib" | ||
| 89 | - cp README.md "dist/$ARCHIVE_ROOT/README.md" | ||
| 90 | - tar -C dist -czf "dist/$ARCHIVE_ROOT.tar.gz" "$ARCHIVE_ROOT" | ||
| 91 | cd dist | 79 | cd dist |
| 92 | - sha256sum "$ARCHIVE_ROOT.tar.gz" > "$ARCHIVE_ROOT.tar.gz.sha256" | 80 | + sha256sum clonim-linux-x86_64 libclonim_runtime.a > SHA256SUMS |
| 93 | 81 | ||
| 94 | - name: Upload workflow artifact | 82 | - name: Upload workflow artifact |
| 95 | uses: actions/upload-artifact@v4 | 83 | uses: actions/upload-artifact@v4 |
| 96 | with: | 84 | with: |
| 97 | name: clonim-${{ steps.release.outputs.tag }}-linux-x86_64 | 85 | name: clonim-${{ steps.release.outputs.tag }}-linux-x86_64 |
| 98 | path: | | 86 | path: | |
| 99 | - dist/clonim-linux-x86_64.tar.gz | 87 | + dist/clonim-linux-x86_64 |
| 100 | - dist/clonim-linux-x86_64.tar.gz.sha256 | 88 | + dist/libclonim_runtime.a |
| 89 | + dist/SHA256SUMS | ||
| 101 | if-no-files-found: error | 90 | if-no-files-found: error |
| 102 | retention-days: 90 | 91 | retention-days: 90 |
| 103 | 92 | ||
| @@ -109,11 +98,13 @@ jobs: | |||
| 109 | body: | | 98 | body: | |
| 110 | Linux x86_64 release of clonim. | 99 | Linux x86_64 release of clonim. |
| 111 | 100 | ||
| 112 | - The archive contains the compiler, its matched private static | 101 | + Download `clonim-linux-x86_64` and `libclonim_runtime.a` into the |
| 113 | - runtime archives, runtime interface, and clonim standard library. | 102 | + same directory. Generated programs statically link the runtime and |
| 103 | + are standalone. Nim must be installed as the native-code backend. | ||
| 114 | draft: false | 104 | draft: false |
| 115 | prerelease: false | 105 | prerelease: false |
| 116 | files: | | 106 | files: | |
| 117 | - dist/clonim-linux-x86_64.tar.gz | 107 | + dist/clonim-linux-x86_64 |
| 118 | - dist/clonim-linux-x86_64.tar.gz.sha256 | 108 | + dist/libclonim_runtime.a |
| 109 | + dist/SHA256SUMS | ||
| 119 | fail_on_unmatched_files: true | 110 | fail_on_unmatched_files: true |
modified
README.md +6 -7 | @@ -23,13 +23,12 @@ and flags slowdowns above 10% versus the latest compatible run. Requires Jolt | ||
| 23 | 23 | and a clean working tree. Use `just bench-store 15` to change the threshold; |
| 24 | 24 | see [benchmark history](bench/README.md) for metrics and exit codes. |
| 25 | 25 | |
| 26 | -`just release` also builds clonim's private static runtime archives. Generated | |
| 27 | -programs link the matching debug or release archive, so their finished binaries | |
| 28 | -are standalone. Version tags matching `v*` trigger the release workflow, which | |
| 29 | -runs the test suite and publishes a Linux x86_64 bundle plus its SHA-256 file to | |
| 30 | -GitHub Releases. The bundle contains the compiler, both internal runtime | |
| 31 | -archives, their small Nim interface, and the clonim source-level standard | |
| 32 | -library; users still need Nim installed as the native-code backend. | |
| 26 | +`just release` builds the compiler and its private static runtime. Version tags | |
| 27 | +matching `v*` trigger the release workflow, which publishes the Linux x86_64 | |
| 28 | +compiler and `libclonim_runtime.a` as individual assets (plus `SHA256SUMS`). Put | |
| 29 | +the compiler and archive in the same directory. Generated programs statically | |
| 30 | +link the runtime and are standalone; users still need Nim installed as the | |
| 31 | +native-code backend. | |
| 33 | 32 | |
| 34 | 33 | Source-level libraries are loaded explicitly. Use |
| 35 | 34 | `(require '[clonim.core :refer [now-ms]])` to load `stdlib/clonim/core.clj`. Host-dependent operations remain small runtime primitives; for |
| @@ -23,13 +23,12 @@ and flags slowdowns above 10% versus the latest compatible run. Requires Jolt | |||
| 23 | and a clean working tree. Use `just bench-store 15` to change the threshold; | 23 | and a clean working tree. Use `just bench-store 15` to change the threshold; |
| 24 | see [benchmark history](bench/README.md) for metrics and exit codes. | 24 | see [benchmark history](bench/README.md) for metrics and exit codes. |
| 25 | 25 | ||
| 26 | -`just release` also builds clonim's private static runtime archives. Generated | 26 | +`just release` builds the compiler and its private static runtime. Version tags |
| 27 | -programs link the matching debug or release archive, so their finished binaries | 27 | +matching `v*` trigger the release workflow, which publishes the Linux x86_64 |
| 28 | -are standalone. Version tags matching `v*` trigger the release workflow, which | 28 | +compiler and `libclonim_runtime.a` as individual assets (plus `SHA256SUMS`). Put |
| 29 | -runs the test suite and publishes a Linux x86_64 bundle plus its SHA-256 file to | 29 | +the compiler and archive in the same directory. Generated programs statically |
| 30 | -GitHub Releases. The bundle contains the compiler, both internal runtime | 30 | +link the runtime and are standalone; users still need Nim installed as the |
| 31 | -archives, their small Nim interface, and the clonim source-level standard | 31 | +native-code backend. |
| 32 | -library; users still need Nim installed as the native-code backend. | ||
| 33 | 32 | ||
| 34 | Source-level libraries are loaded explicitly. Use | 33 | Source-level libraries are loaded explicitly. Use |
| 35 | `(require '[clonim.core :refer [now-ms]])` to load `stdlib/clonim/core.clj`. Host-dependent operations remain small runtime primitives; for | 34 | `(require '[clonim.core :refer [now-ms]])` to load `stdlib/clonim/core.clj`. Host-dependent operations remain small runtime primitives; for |
modified
justfile +1 -1 | @@ -14,7 +14,7 @@ runtime-libs: | ||
| 14 | 14 | |
| 15 | 15 | # Build with optimisations on (compiler and, via -d:release, the programs it emits) |
| 16 | 16 | release: runtime-libs |
| 17 | - nim c -d:release --hints:off --warnings:off -o:{{bin}} src/clonim.nim | |
| 17 | + nim c -d:release -d:releaseCompiler --hints:off --warnings:off -o:{{bin}} src/clonim.nim | |
| 18 | 18 | |
| 19 | 19 | # Run every example against tests/<name>.expected |
| 20 | 20 | test: build |
| @@ -14,7 +14,7 @@ runtime-libs: | |||
| 14 | 14 | ||
| 15 | # Build with optimisations on (compiler and, via -d:release, the programs it emits) | 15 | # Build with optimisations on (compiler and, via -d:release, the programs it emits) |
| 16 | release: runtime-libs | 16 | release: runtime-libs |
| 17 | - nim c -d:release --hints:off --warnings:off -o:{{bin}} src/clonim.nim | 17 | + nim c -d:release -d:releaseCompiler --hints:off --warnings:off -o:{{bin}} src/clonim.nim |
| 18 | 18 | ||
| 19 | # Run every example against tests/<name>.expected | 19 | # Run every example against tests/<name>.expected |
| 20 | test: build | 20 | test: build |
modified
src/clonim.nim +34 -0 | @@ -6,6 +6,29 @@ | ||
| 6 | 6 | import std/[hashes, os, osproc, sequtils, strutils, times] |
| 7 | 7 | import runtime, compiler |
| 8 | 8 | |
| 9 | +when defined(releaseCompiler): | |
| 10 | + const | |
| 11 | + EmbeddedAppRuntime = staticRead("app_runtime.nim") | |
| 12 | + EmbeddedRuntimeTypes = staticRead("runtime_types.nim") | |
| 13 | + EmbeddedCoreStdlib = staticRead("../stdlib/clonim/core.clj") | |
| 14 | + | |
| 15 | + proc embeddedRoot(): string = | |
| 16 | + ## Materialize the compiler-only inputs under a content-keyed cache. The | |
| 17 | + ## runtime implementation remains the separately shipped static archive. | |
| 18 | + var h: Hash = hash(EmbeddedAppRuntime) | |
| 19 | + h = h !& hash(EmbeddedRuntimeTypes) | |
| 20 | + h = h !& hash(EmbeddedCoreStdlib) | |
| 21 | + result = getTempDir() / "clonim-runtime" / $(!$h) | |
| 22 | + let files = [ | |
| 23 | + (result / "src" / "app_runtime.nim", EmbeddedAppRuntime), | |
| 24 | + (result / "src" / "runtime_types.nim", EmbeddedRuntimeTypes), | |
| 25 | + (result / "stdlib" / "clonim" / "core.clj", EmbeddedCoreStdlib), | |
| 26 | + ] | |
| 27 | + for (path, contents) in files: | |
| 28 | + createDir(path.parentDir) | |
| 29 | + if not fileExists(path) or getFileSize(path) != contents.len: | |
| 30 | + writeFile(path, contents) | |
| 31 | + | |
| 9 | 32 | proc usage() = |
| 10 | 33 | echo """clonim — a Clojure compiler hosted on Nim |
| 11 | 34 | |
| @@ -23,6 +46,8 @@ options: | ||
| 23 | 46 | |
| 24 | 47 | proc srcDir(): string = |
| 25 | 48 | ## Where generated programs find the private runtime interface. |
| 49 | + when defined(releaseCompiler): | |
| 50 | + return embeddedRoot() / "src" | |
| 26 | 51 | for cand in [getAppDir(), getAppDir().parentDir / "src", |
| 27 | 52 | getAppDir().parentDir.parentDir / "src"]: |
| 28 | 53 | if fileExists(cand / "app_runtime.nim"): return cand |
| @@ -31,6 +56,11 @@ proc srcDir(): string = | ||
| 31 | 56 | proc runtimeLib(release: bool): string = |
| 32 | 57 | ## Release archives place the private runtime beside bin/. A source checkout |
| 33 | 58 | ## builds the same archive into lib/ on first use. |
| 59 | + when defined(releaseCompiler): | |
| 60 | + let shipped = getAppDir() / "libclonim_runtime.a" | |
| 61 | + if fileExists(shipped): return shipped | |
| 62 | + raise newException(IOError, | |
| 63 | + "missing runtime library beside compiler: " & shipped) | |
| 34 | 64 | let libName = (if release: "libclonim_runtime.a" else: "libclonim_runtime_debug.a") |
| 35 | 65 | let installed = getAppDir().parentDir / "lib" / libName |
| 36 | 66 | let source = srcDir() / "runtime_lib.nim" |
| @@ -83,6 +113,10 @@ proc main() = | ||
| 83 | 113 | var outBin = "" |
| 84 | 114 | var verbose = false |
| 85 | 115 | var release = cmd == "build" |
| 116 | + when defined(releaseCompiler): | |
| 117 | + # The distributed compiler ships one release-mode runtime archive. Nim's | |
| 118 | + # debug and release modes are not ABI-compatible, so `run` uses it too. | |
| 119 | + release = true | |
| 86 | 120 | var sourceRoots: seq[string] = @[] |
| 87 | 121 | var i = 2 |
| 88 | 122 | while i < argv.len: |
| @@ -6,6 +6,29 @@ | |||
| 6 | import std/[hashes, os, osproc, sequtils, strutils, times] | 6 | import std/[hashes, os, osproc, sequtils, strutils, times] |
| 7 | import runtime, compiler | 7 | import runtime, compiler |
| 8 | 8 | ||
| 9 | +when defined(releaseCompiler): | ||
| 10 | + const | ||
| 11 | + EmbeddedAppRuntime = staticRead("app_runtime.nim") | ||
| 12 | + EmbeddedRuntimeTypes = staticRead("runtime_types.nim") | ||
| 13 | + EmbeddedCoreStdlib = staticRead("../stdlib/clonim/core.clj") | ||
| 14 | + | ||
| 15 | + proc embeddedRoot(): string = | ||
| 16 | + ## Materialize the compiler-only inputs under a content-keyed cache. The | ||
| 17 | + ## runtime implementation remains the separately shipped static archive. | ||
| 18 | + var h: Hash = hash(EmbeddedAppRuntime) | ||
| 19 | + h = h !& hash(EmbeddedRuntimeTypes) | ||
| 20 | + h = h !& hash(EmbeddedCoreStdlib) | ||
| 21 | + result = getTempDir() / "clonim-runtime" / $(!$h) | ||
| 22 | + let files = [ | ||
| 23 | + (result / "src" / "app_runtime.nim", EmbeddedAppRuntime), | ||
| 24 | + (result / "src" / "runtime_types.nim", EmbeddedRuntimeTypes), | ||
| 25 | + (result / "stdlib" / "clonim" / "core.clj", EmbeddedCoreStdlib), | ||
| 26 | + ] | ||
| 27 | + for (path, contents) in files: | ||
| 28 | + createDir(path.parentDir) | ||
| 29 | + if not fileExists(path) or getFileSize(path) != contents.len: | ||
| 30 | + writeFile(path, contents) | ||
| 31 | + | ||
| 9 | proc usage() = | 32 | proc usage() = |
| 10 | echo """clonim — a Clojure compiler hosted on Nim | 33 | echo """clonim — a Clojure compiler hosted on Nim |
| 11 | 34 | ||
| @@ -23,6 +46,8 @@ options: | |||
| 23 | 46 | ||
| 24 | proc srcDir(): string = | 47 | proc srcDir(): string = |
| 25 | ## Where generated programs find the private runtime interface. | 48 | ## Where generated programs find the private runtime interface. |
| 49 | + when defined(releaseCompiler): | ||
| 50 | + return embeddedRoot() / "src" | ||
| 26 | for cand in [getAppDir(), getAppDir().parentDir / "src", | 51 | for cand in [getAppDir(), getAppDir().parentDir / "src", |
| 27 | getAppDir().parentDir.parentDir / "src"]: | 52 | getAppDir().parentDir.parentDir / "src"]: |
| 28 | if fileExists(cand / "app_runtime.nim"): return cand | 53 | if fileExists(cand / "app_runtime.nim"): return cand |
| @@ -31,6 +56,11 @@ proc srcDir(): string = | |||
| 31 | proc runtimeLib(release: bool): string = | 56 | proc runtimeLib(release: bool): string = |
| 32 | ## Release archives place the private runtime beside bin/. A source checkout | 57 | ## Release archives place the private runtime beside bin/. A source checkout |
| 33 | ## builds the same archive into lib/ on first use. | 58 | ## builds the same archive into lib/ on first use. |
| 59 | + when defined(releaseCompiler): | ||
| 60 | + let shipped = getAppDir() / "libclonim_runtime.a" | ||
| 61 | + if fileExists(shipped): return shipped | ||
| 62 | + raise newException(IOError, | ||
| 63 | + "missing runtime library beside compiler: " & shipped) | ||
| 34 | let libName = (if release: "libclonim_runtime.a" else: "libclonim_runtime_debug.a") | 64 | let libName = (if release: "libclonim_runtime.a" else: "libclonim_runtime_debug.a") |
| 35 | let installed = getAppDir().parentDir / "lib" / libName | 65 | let installed = getAppDir().parentDir / "lib" / libName |
| 36 | let source = srcDir() / "runtime_lib.nim" | 66 | let source = srcDir() / "runtime_lib.nim" |
| @@ -83,6 +113,10 @@ proc main() = | |||
| 83 | var outBin = "" | 113 | var outBin = "" |
| 84 | var verbose = false | 114 | var verbose = false |
| 85 | var release = cmd == "build" | 115 | var release = cmd == "build" |
| 116 | + when defined(releaseCompiler): | ||
| 117 | + # The distributed compiler ships one release-mode runtime archive. Nim's | ||
| 118 | + # debug and release modes are not ABI-compatible, so `run` uses it too. | ||
| 119 | + release = true | ||
| 86 | var sourceRoots: seq[string] = @[] | 120 | var sourceRoots: seq[string] = @[] |
| 87 | var i = 2 | 121 | var i = 2 |
| 88 | while i < argv.len: | 122 | while i < argv.len: |