Skip to content

Commit

Permalink
Cross compile scala-native-cli with Scala Native
Browse files Browse the repository at this point in the history
Co-authored-by: Tomasz Godzik <[email protected]>
  • Loading branch information
jchyb and tgodzik committed Sep 19, 2024
1 parent a8baa8b commit f99af17
Show file tree
Hide file tree
Showing 390 changed files with 1,241 additions and 256 deletions.
27 changes: 25 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,32 @@ jobs:
- run:
# for GitOps tests
git config --global user.email "[email protected]" && git config --global user.name "scalafmt"
- run: TEST="2.12" sbt ci-test
- run: TEST="2.12" sbt ci-test-jvm
shell: bash
- run: TEST="2.13" sbt ci-test
- run: TEST="2.13" sbt ci-test-jvm
shell: bash
test-scala-native:
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up JVM
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: 'temurin'
cache: 'sbt'
- run:
# for GitOps tests
git config --global user.email "[email protected]" && git config --global user.name "scalafmt"
- run: TEST="2.12" sbt ci-test-native
shell: bash
- run: TEST="2.13" sbt ci-test-native
shell: bash
community-test:
strategy:
Expand Down
247 changes: 141 additions & 106 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import scala.scalanative.build._

import Dependencies._
import sbtcrossproject.CrossPlugin.autoImport.crossProject

Expand Down Expand Up @@ -30,17 +32,16 @@ inThisBuild(List(
crossScalaVersions := List(scala213, scala212),
resolvers ++= Resolver.sonatypeOssRepos("releases"),
resolvers ++= Resolver.sonatypeOssRepos("snapshots"),
libraryDependencies ++=
List(munit.value % Test, scalacheck % Test, scalametaTestkit % Test),
testFrameworks += new TestFramework("munit.Framework"),
))

name := "scalafmtRoot"
publish / skip := true

addCommandAlias("native-image", "cli/nativeImage")
addCommandAlias("scala-native", "cliNative/compile;cliNative/nativeLink")

commands += Command.command("ci-test") { s =>
commands += Command.command("ci-test-jvm") { s =>
val scalaVersion = sys.env.get("TEST") match {
case Some("2.12") => scala212
case _ => scala213
Expand All @@ -50,40 +51,50 @@ commands += Command.command("ci-test") { s =>
docsTest :: s
}

lazy val dynamic = project.in(file("scalafmt-dynamic")).settings(
moduleName := "scalafmt-dynamic",
description := "Implementation of scalafmt-interfaces",
buildInfoSettings,
buildInfoPackage := "org.scalafmt.dynamic",
buildInfoObject := "BuildInfo",
libraryDependencies ++= List(
"io.get-coursier" % "interface" % "0.0.17",
"com.typesafe" % "config" % "1.4.3",
munit.value % Test,
scalametaTestkit % Test,
),
scalacOptions ++= scalacJvmOptions.value,
).dependsOn(interfaces, sysops.jvm).dependsOn(core.jvm % "test")
commands += Command.command("ci-test-native") { s =>
val scalaVersion = sys.env.get("TEST") match {
case Some("2.12") => scala212
case _ => scala213
}
s"++$scalaVersion" :: "testsNative/test" :: s
}

lazy val dynamic = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-dynamic")).settings(
moduleName := "scalafmt-dynamic",
description := "Implementation of scalafmt-interfaces",
buildInfoSettings,
buildInfoPackage := "org.scalafmt.dynamic",
buildInfoObject := "BuildInfo",
libraryDependencies ++= List(
"io.get-coursier" % "interface" % "0.0.17",
"com.typesafe" % "config" % "1.4.3",
munit.value % Test,
scalametaTestkit.value % Test,
),
scalacOptions ++= scalacJvmOptions.value,
).dependsOn(interfaces, sysops).dependsOn(core % "test")
.enablePlugins(BuildInfoPlugin)

lazy val interfaces = project.in(file("scalafmt-interfaces")).settings(
moduleName := "scalafmt-interfaces",
description :=
"Dependency-free, pure Java public interfaces to integrate with Scalafmt through a build tool or editor plugin.",
crossVersion := CrossVersion.disabled,
autoScalaLibrary := false,
Compile / resourceGenerators += Def.task {
val out = (Compile / managedResourceDirectories).value.head /
"scalafmt.properties"
val props = new java.util.Properties()
props.put("version", version.value)
IO.write(props, "scalafmt properties", out)
List(out)
},
)
lazy val interfaces = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-interfaces")).settings(
moduleName := "scalafmt-interfaces",
description :=
"Dependency-free, pure Java public interfaces to integrate with Scalafmt through a build tool or editor plugin.",
crossVersion := CrossVersion.disabled,
autoScalaLibrary := false,
Compile / resourceGenerators += Def.task {
val out = (Compile / managedResourceDirectories).value.head /
"scalafmt.properties"
val props = new java.util.Properties()
props.put("version", version.value)
IO.write(props, "scalafmt properties", out)
List(out)
},
)

lazy val sysops = crossProject(JVMPlatform).withoutSuffixFor(JVMPlatform)
.in(file("scalafmt-sysops")).settings(
lazy val sysops = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-sysops")).settings(
moduleName := "scalafmt-sysops",
description := "Scalafmt systems operations",
scalacOptions ++= scalacJvmOptions.value,
Expand All @@ -98,48 +109,62 @@ lazy val sysops = crossProject(JVMPlatform).withoutSuffixFor(JVMPlatform)
},
)

lazy val config = crossProject(JVMPlatform).withoutSuffixFor(JVMPlatform)
.in(file("scalafmt-config")).settings(
lazy val config = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-config")).settings(
moduleName := "scalafmt-config",
description := "Scalafmt config parsing",
scalacOptions ++= scalacJvmOptions.value,
libraryDependencies ++= Seq(metaconfig.value),
).jvmSettings(libraryDependencies ++= Seq(metaconfigTypesafe.value))
.nativeSettings(libraryDependencies ++= Seq(metaconfigSconfig.value))
// .jsSettings(
// libraryDependencies ++= Seq(
// metaconfigHocon.value,
// )
// )

lazy val core = crossProject(JVMPlatform).in(file("scalafmt-core")).settings(
moduleName := "scalafmt-core",
buildInfoSettings,
scalacOptions ++= scalacJvmOptions.value,
libraryDependencies ++= Seq(
scalameta.value,
"org.scalameta" %% "mdoc-parser" % mdocV,
// scala-reflect is an undeclared dependency of fansi, see #1252.
// Scalafmt itself does not require scala-reflect.
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
),
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => Seq()
case _ => Seq(compilerPlugin(
"org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full,
))
}
},
)
lazy val core = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-core")).settings(
moduleName := "scalafmt-core",
buildInfoSettings,
scalacOptions ++= scalacJvmOptions.value,
libraryDependencies ++= Seq(
scalameta.value,
"com.lihaoyi" %%% "fastparse" % "3.1.0",
"org.scalameta" %%% "mdoc-parser" % mdocV,
// scala-reflect is an undeclared dependency of fansi, see #1252.
// Scalafmt itself does not require scala-reflect.
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
),
libraryDependencies ++= {
CrossVersion.partialVersion(scalaVersion.value) match {
case Some((2, 13)) => Seq()
case _ => Seq(compilerPlugin(
"org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full,
))
}
},
)
// .jsSettings(
// libraryDependencies ++= List(
// scalatest.value % Test // must be here for coreJS/test to run anything
// )
// )
.jvmSettings(Test / run / fork := true).dependsOn(sysops, config)
.jvmSettings(Test / run / fork := true).dependsOn(sysops, config, macros)
.enablePlugins(BuildInfoPlugin)

lazy val coreJVM = core.jvm
// lazy val coreJS = core.js

lazy val macros = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-macros")).settings(
moduleName := "scalafmt-macros",
buildInfoSettings,
scalacOptions ++= scalacJvmOptions.value,
libraryDependencies ++= Seq(
scalameta.value,
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
),
)

import sbtassembly.AssemblyPlugin.defaultUniversalScript

Expand All @@ -156,58 +181,64 @@ val scalacJvmOptions = Def.setting {
cross ++ unused
}

lazy val cli = project.in(file("scalafmt-cli")).settings(
moduleName := "scalafmt-cli",
assembly / mainClass := Some("org.scalafmt.cli.Cli"),
assembly / assemblyOption := (assembly / assemblyOption).value
.withPrependShellScript(Some(defaultUniversalScript(shebang = false))),
assembly / assemblyJarName := "scalafmt.jar",
assembly / assemblyMergeStrategy := {
case "reflect.properties" => MergeStrategy.first
case x =>
val oldStrategy = (assembly / assemblyMergeStrategy).value
oldStrategy(x)
},
libraryDependencies ++= Seq(
"com.googlecode.java-diff-utils" % "diffutils" % "1.3.0",
"com.martiansoftware" % "nailgun-server" % "0.9.1",
"com.github.scopt" %% "scopt" % "4.1.0",
),
scalacOptions ++= scalacJvmOptions.value,
Compile / mainClass := Some("org.scalafmt.cli.Cli"),
nativeImageVersion := "22.3.0",
nativeImageInstalled := isCI,
nativeImageOptions ++= {
val isMusl = sys.env.get("NATIVE_IMAGE_MUSL").exists(_.toBoolean)
if (isMusl) Seq("--libc=musl") else Nil
},
nativeImageOptions ++= {
val isStatic = sys.env.get("NATIVE_IMAGE_STATIC").exists(_.toBoolean)
if (isStatic) Seq("--static") else Nil
},
).dependsOn(coreJVM, dynamic).enablePlugins(NativeImagePlugin)
lazy val cli = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-cli")).settings(
moduleName := "scalafmt-cli",
assembly / mainClass := Some("org.scalafmt.cli.Cli"),
assembly / assemblyOption := (assembly / assemblyOption).value
.withPrependShellScript(Some(defaultUniversalScript(shebang = false))),
assembly / assemblyJarName := "scalafmt.jar",
assembly / assemblyMergeStrategy := {
case "reflect.properties" => MergeStrategy.first
case x =>
val oldStrategy = (assembly / assemblyMergeStrategy).value
oldStrategy(x)
},
libraryDependencies ++= Seq(
"org.scalameta" %%% "munit-diff" % "1.0.2",
"com.martiansoftware" % "nailgun-server" % "0.9.1",
"com.github.scopt" %%% "scopt" % "4.1.0",
),
scalacOptions ++= scalacJvmOptions.value,
Compile / mainClass := Some("org.scalafmt.cli.Cli"),
nativeImageVersion := "22.3.0",
nativeImageInstalled := isCI,
nativeImageOptions ++= {
val isMusl = sys.env.get("NATIVE_IMAGE_MUSL").exists(_.toBoolean)
if (isMusl) Seq("--libc=musl") else Nil
},
nativeImageOptions ++= {
val isStatic = sys.env.get("NATIVE_IMAGE_STATIC").exists(_.toBoolean)
if (isStatic) Seq("--static") else Nil
},
).nativeSettings(scalaNativeNativeConfig).dependsOn(core, dynamic)
.enablePlugins(NativeImagePlugin)

lazy val tests = project.in(file("scalafmt-tests")).settings(
publish / skip := true,
libraryDependencies ++= Seq(
// Test dependencies
"com.lihaoyi" %% "scalatags" % "0.13.1",
scalametaTestkit,
munit.value,
),
scalacOptions ++= scalacJvmOptions.value,
javaOptions += "-Dfile.encoding=UTF8",
buildInfoPackage := "org.scalafmt.tests",
buildInfoKeys :=
Seq[BuildInfoKey]("resourceDirectory" -> (Test / resourceDirectory).value),
).enablePlugins(BuildInfoPlugin).dependsOn(coreJVM, dynamic, cli)
lazy val tests = crossProject(JVMPlatform, NativePlatform)
.withoutSuffixFor(JVMPlatform).in(file("scalafmt-tests")).settings(
publish / skip := true,
libraryDependencies ++= Seq(
// Test dependencies
"com.lihaoyi" %%% "scalatags" % "0.13.1",
scalametaTestkit.value,
munit.value,
),
scalacOptions ++= scalacJvmOptions.value,
buildInfoPackage := "org.scalafmt.tests",
buildInfoKeys := Seq[BuildInfoKey](
"resourceDirectory" ->
(baseDirectory.value / ".." / "shared" / "src" / "test" / "resources"),
),
).enablePlugins(BuildInfoPlugin)
.jvmSettings(javaOptions += "-Dfile.encoding=UTF8")
.dependsOn(core, dynamic, cli)

lazy val communityTests = project.in(file("scalafmt-tests-community")).settings(
publish / skip := true,
libraryDependencies ++= Seq(
// Test dependencies
"com.lihaoyi" %% "scalatags" % "0.13.1",
scalametaTestkit,
scalametaTestkit.value,
munit.value,
),
scalacOptions ++= scalacJvmOptions.value,
Expand All @@ -218,7 +249,7 @@ lazy val communityTests = project.in(file("scalafmt-tests-community")).settings(
lazy val benchmarks = project.in(file("scalafmt-benchmarks")).settings(
publish / skip := true,
moduleName := "scalafmt-benchmarks",
libraryDependencies ++= Seq(scalametaTestkit),
libraryDependencies ++= Seq(scalametaTestkit.value),
run / javaOptions ++= Seq(
"-Djava.net.preferIPv4Stack=true",
"-XX:+AggressiveOpts",
Expand All @@ -235,13 +266,13 @@ lazy val benchmarks = project.in(file("scalafmt-benchmarks")).settings(
"-Xmx2G",
"-server",
),
).dependsOn(coreJVM).enablePlugins(JmhPlugin)
).dependsOn(core.jvm).enablePlugins(JmhPlugin)

lazy val docs = project.in(file("scalafmt-docs")).settings(
crossScalaVersions := List(scala212),
publish / skip := true,
mdoc := (Compile / run).evaluated,
).dependsOn(cli, dynamic).enablePlugins(DocusaurusPlugin)
).dependsOn(cli.jvm, dynamic.jvm).enablePlugins(DocusaurusPlugin)

val V = "\\d+\\.\\d+\\.\\d+"
val ReleaseCandidate = s"($V-RC\\d+).*".r
Expand Down Expand Up @@ -270,3 +301,7 @@ lazy val buildInfoSettings: Seq[Def.Setting[_]] = Seq(
buildInfoPackage := "org.scalafmt",
buildInfoObject := "Versions",
)

lazy val scalaNativeNativeConfig = nativeConfig ~= {
_.withMode(Mode.releaseFull)
}
2 changes: 1 addition & 1 deletion docs/contributing-scalafmt.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ To build a native image of the command-line interface using

- From the project root directory,
- run `sbt cli/assembly`
- run `java -jar scalafmt-cli/target/scala-2.13/scalafmt.jar`, to execute recently built artifacts
- run `java -jar scalafmt-cli/jvm/target/scala-2.13/scalafmt.jar`, to execute recently built artifacts

## Random stuff

Expand Down
2 changes: 1 addition & 1 deletion docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ handle parse and config errors.

Here is an example how to extend `ScalafmtReporter`.

```scala mdoc:file:scalafmt-dynamic/src/main/scala/org/scalafmt/dynamic/ConsoleScalafmtReporter.scala
```scala mdoc:file:scalafmt-dynamic/jvm/src/main/scala/org/scalafmt/dynamic/ConsoleScalafmtReporter.scala

```

Expand Down
Loading

0 comments on commit f99af17

Please sign in to comment.