diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6b2ea4..f479903 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,9 +10,13 @@ jobs: compile: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: VirtusLab/scala-cli-setup@v1 - - run: scala-cli compile . + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4 + with: + distribution: temurin + java-version: 17 + - uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1 + - run: sbt compile build-linux: if: github.event_name == 'push' || github.event_name == 'pull_request' @@ -26,14 +30,14 @@ jobs: target: aarch64-linux runs-on: ${{ matrix.runner }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Build in Alpine container run: | ./build-with-container.sh - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: comport-${{ matrix.target }} path: comport @@ -50,15 +54,19 @@ jobs: target: aarch64-macos runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: VirtusLab/scala-cli-setup@v1 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4 + with: + distribution: temurin + java-version: 17 + - uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1 - name: Build native binary run: | ./build.sh - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: comport-${{ matrix.target }} path: comport diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9270d64..0c91d50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: target: aarch64-linux runs-on: ${{ matrix.runner }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 - name: Extract version from tag id: version @@ -24,19 +24,10 @@ jobs: - name: Build in Alpine container run: | - docker run --rm -v "$PWD":/work -w /work alpine:latest sh -c ' - apk add --no-cache bash curl clang lld musl-dev openjdk17-jre-headless && - curl -fLo /usr/local/bin/coursier https://github.com/coursier/launchers/raw/master/coursier.jar && - chmod +x /usr/local/bin/coursier && - coursier launch scala-cli -- --power package . -o comport -f \ - --native-mode release-fast \ - --native-lto thin \ - --native-gc commix \ - --native-linking "-static" - ' + ./build-with-container.sh - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: comport-${{ steps.version.outputs.version }}-${{ matrix.target }} path: comport @@ -51,8 +42,12 @@ jobs: target: aarch64-macos runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v4 - - uses: VirtusLab/scala-cli-setup@v1 + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-java@cf277c60eb25467037889841efdb72551f06f6c3 # v4 + with: + distribution: temurin + java-version: 17 + - uses: sbt/setup-sbt@8feba82adc7f01ddcf8165b86f778bdb5b82cebc # v1 - name: Extract version from tag id: version @@ -60,13 +55,10 @@ jobs: - name: Build native binary run: | - scala-cli --power package . -o comport -f \ - --native-mode release-fast \ - --native-lto full \ - --native-gc commix + ./build.sh - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: comport-${{ steps.version.outputs.version }}-${{ matrix.target }} path: comport @@ -82,7 +74,7 @@ jobs: run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" - name: Download all artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 with: path: artifacts @@ -96,7 +88,7 @@ jobs: done - name: Create GitHub Release - uses: softprops/action-gh-release@v2 + uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 with: name: v${{ steps.version.outputs.version }} generate_release_notes: true diff --git a/.gitignore b/.gitignore index b135188..22c6cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,10 @@ .bsp/ .metals/ -comport -Comport +# sbt +target/ +project/target/ +project/project/ + +/comport +/Comport diff --git a/Dockerfile b/Dockerfile index 0456b4d..1556f96 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,6 @@ FROM alpine:latest # libc++-dev is for exception handling RUN apk add --no-cache bash curl clang libc++-dev alpine-sdk lld musl-dev openjdk17-jre-headless RUN curl -fLo /usr/local/bin/coursier https://github.com/coursier/launchers/raw/master/coursier.jar && chmod +x /usr/local/bin/coursier -RUN coursier launch scala-cli +RUN coursier install sbt ENV PATH="$PATH:/root/.local/share/coursier/bin" WORKDIR /work diff --git a/README.md b/README.md index d1128a8..d615f70 100644 --- a/README.md +++ b/README.md @@ -32,14 +32,15 @@ sudo mv comport /usr/local/bin/ ### Build from source -Requires [Scala CLI](https://scala-cli.virtuslab.org/). +Requires [sbt](https://www.scala-sbt.org/) (2.x), JDK 17+, and Clang/LLVM +for Scala Native linking. ```sh # Run directly -scala-cli run . +sbt run -# Build native binary -scala-cli --power package . -o comport --native-mode release-fast --native-gc commix +# Build native binary (produces ./comport) +./build.sh ``` ## Usage diff --git a/build-with-container.sh b/build-with-container.sh index 42924f8..aabb40f 100755 --- a/build-with-container.sh +++ b/build-with-container.sh @@ -4,4 +4,4 @@ set -eux set pipefail docker build -t comport-builder . -docker run --rm -v "$PWD":/work --rm -e SCALA_CLI_LAUNCH='coursier launch scala-cli --' -e LINKFLAGS=-static comport-builder:latest sh /work/build.sh +docker run --rm -v "$PWD":/work -e LINKFLAGS=-static comport-builder:latest sh /work/build.sh diff --git a/build.sbt b/build.sbt new file mode 100644 index 0000000..de8b31b --- /dev/null +++ b/build.sbt @@ -0,0 +1,24 @@ +import scala.scalanative.build.* + +enablePlugins(ScalaNativePlugin) + +name := "comport" +organization := "dev.capslock" +scalaVersion := "3.8.2" +scalacOptions += "-no-indent" + +libraryDependencies ++= Seq( + "com.lihaoyi" %% "mainargs" % "0.7.8", + "com.lihaoyi" %% "os-lib" % "0.11.8", + "org.virtuslab" %% "scala-yaml" % "0.3.3" +) + +nativeConfig ~= { cfg => + val extraLinkOpts = + sys.env.getOrElse("LINKFLAGS", "").split("\\s+").filter(_.nonEmpty).toSeq + cfg + .withMode(Mode.releaseFast) + .withLTO(LTO.full) + .withGC(GC.commix) + .withLinkingOptions(cfg.linkingOptions ++ extraLinkOpts) +} diff --git a/build.sh b/build.sh index 8627f65..76e62cb 100755 --- a/build.sh +++ b/build.sh @@ -1,16 +1,20 @@ #!/bin/sh -# Build script using scala-cli. Overwrites `./comport` if exists. +# Build script using sbt. Overwrites `./comport` if exists. +# LINKFLAGS (whitespace-separated) is picked up by build.sbt and appended +# to nativeConfig.linkingOptions (used e.g. for `-static` in the Alpine +# container build). set -eux set pipefail LINKFLAGS=${LINKFLAGS:-} -COURSIER=${COURSIER:-cs} -SCALA_CLI_LAUNCH=${SCALA_CLI_LAUNCH:-scala-cli} +SBT_LAUNCH=${SBT_LAUNCH:-sbt} -${SCALA_CLI_LAUNCH} --power package . -o comport -f \ - --native-mode release-fast \ - --native-lto full \ - --native-gc commix \ - --native-linking "${LINKFLAGS}" +export LINKFLAGS + +# --server forces the JVM launcher and skips sbtn (the thin native client). +# sbt 2's sbtn is glibc-linked and does not run on Alpine/musl. +${SBT_LAUNCH} --server -Dsbt.color=never nativeLink + +cp target/out/native0.5/scala-3.8.2/comport/comport ./comport diff --git a/project/build.properties b/project/build.properties new file mode 100644 index 0000000..3e39c25 --- /dev/null +++ b/project/build.properties @@ -0,0 +1 @@ +sbt.version=2.0.2 diff --git a/project/plugins.sbt b/project/plugins.sbt new file mode 100644 index 0000000..a4fc4a7 --- /dev/null +++ b/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("org.scala-native" % "sbt-scala-native" % "0.5.12") diff --git a/comport.scala b/src/main/scala/dev/capslock/comport/Main.scala similarity index 96% rename from comport.scala rename to src/main/scala/dev/capslock/comport/Main.scala index 32d7be6..9f27eb9 100644 --- a/comport.scala +++ b/src/main/scala/dev/capslock/comport/Main.scala @@ -1,9 +1,4 @@ -//> using platform native -//> using scala 3.8.2 -//> using options -no-indent -rewrite -//> using dep com.lihaoyi::mainargs::0.7.8 -//> using dep com.lihaoyi::os-lib::0.11.8 -//> using dep org.virtuslab::scala-yaml::0.3.3 +package dev.capslock.comport import mainargs.Flag import mainargs.ParserForMethods