From 1063cdf73bd7e786b960ac0c28c5e130059d463b Mon Sep 17 00:00:00 2001 From: Scala Steward Date: Wed, 17 Apr 2024 23:21:44 +0000 Subject: [PATCH 01/15] Update test-runner, tools to 0.5.1 --- project/deps.sc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/deps.sc b/project/deps.sc index 35c09a3108..abeb4871c2 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -96,7 +96,7 @@ object Deps { def jsoniterScala = "2.23.2" def jsoniterScalaJava8 = "2.13.5.2" def scalaMeta = "4.9.3" - def scalaNative = "0.4.17" + def scalaNative = "0.5.1" def scalaPackager = "0.1.29" def signingCli = "0.2.3" def signingCliJvmVersion = 17 From 5bee114f25f8ef3938055698adace3fc82ab2182 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 12 Apr 2024 13:53:02 +0200 Subject: [PATCH 02/15] Fix Scala Native tests to use 0.5.* syntax --- .../RunScalaNativeTestDefinitions.scala | 111 +++++++++--------- 1 file changed, 53 insertions(+), 58 deletions(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala index d991428e42..95dc6ac78a 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala @@ -6,27 +6,41 @@ import scala.cli.integration.TestUtil.removeAnsiColors import scala.util.Properties trait RunScalaNativeTestDefinitions { _: RunTestDefinitions => + + def simpleNativeScriptCode( + message: String, + wrapMessage: String => String = m => s"c\"$m\"" + ): String = + if (actualScalaVersion.startsWith("3")) + s"""import scala.scalanative.libc._ + |import scala.scalanative.unsafe._ + | + |Zone { + | val io = StdioHelpers(stdio) + | io.printf(c"%s$platformNl", ${wrapMessage(message)}) + |} + |""".stripMargin + else + s"""import scala.scalanative.libc._ + |import scala.scalanative.unsafe._ + | + |Zone.acquire { implicit z => + | val io = StdioHelpers(stdio) + | io.printf(c"%s$platformNl", ${wrapMessage(message)}) + |} + |""".stripMargin + def simpleNativeTests(): Unit = { val fileName = "simple.sc" val message = "Hello" - val inputs = TestInputs( - os.rel / fileName -> - s"""import scala.scalanative.libc._ - |import scala.scalanative.unsafe._ - | - |Zone { implicit z => - | val io = StdioHelpers(stdio) - | io.printf(c"%s$platformNl", c"$message") - |} - |""".stripMargin - ) - inputs.fromRoot { root => - val output = - os.proc(TestUtil.cli, extraOptions, fileName, "--native", "-q") - .call(cwd = root) - .out.trim() - expect(output == message) - } + TestInputs(os.rel / fileName -> simpleNativeScriptCode(message)) + .fromRoot { root => + val output = + os.proc(TestUtil.cli, extraOptions, fileName, "--native") + .call(cwd = root) + .out.trim() + expect(output == message) + } } test("simple script native") { @@ -59,26 +73,16 @@ trait RunScalaNativeTestDefinitions { _: RunTestDefinitions => test("simple script native command") { val fileName = "simple.sc" val message = "Hello" - val inputs = TestInputs( - os.rel / fileName -> - s"""import scala.scalanative.libc._ - |import scala.scalanative.unsafe._ - | - |Zone { implicit z => - | val io = StdioHelpers(stdio) - | io.printf(c"%s$platformNl", c"$message") - |} - |""".stripMargin - ) - inputs.fromRoot { root => - val output = - os.proc(TestUtil.cli, extraOptions, fileName, "--native", "--command") - .call(cwd = root) - .out.trim() - val command = output.linesIterator.toVector.filter(!_.startsWith("[")) - val actualOutput = os.proc(command).call(cwd = root).out.trim() - expect(actualOutput == message) - } + TestInputs(os.rel / fileName -> simpleNativeScriptCode(message)) + .fromRoot { root => + val output = + os.proc(TestUtil.cli, extraOptions, fileName, "--native", "--command") + .call(cwd = root) + .out.trim() + val command = output.linesIterator.toVector.filter(!_.startsWith("[")) + val actualOutput = os.proc(command).call(cwd = root).out.trim() + expect(actualOutput == message) + } } test("Resource embedding in Scala Native") { @@ -195,27 +199,18 @@ trait RunScalaNativeTestDefinitions { _: RunTestDefinitions => def multipleScriptsNative(): Unit = { val message = "Hello" - val inputs = TestInputs( - os.rel / "messages.sc" -> + TestInputs(os.rel / "print.sc" -> + simpleNativeScriptCode("messages.msg", m => s"toCString($m)")) + .add(os.rel / "messages.sc" -> s"""def msg = "$message" - |""".stripMargin, - os.rel / "print.sc" -> - s"""import scala.scalanative.libc._ - |import scala.scalanative.unsafe._ - | - |Zone { implicit z => - | val io = StdioHelpers(stdio) - | io.printf(c"%s$platformNl", toCString(messages.msg)) - |} - |""".stripMargin - ) - inputs.fromRoot { root => - val output = - os.proc(TestUtil.cli, extraOptions, "print.sc", "messages.sc", "--native", "-q") - .call(cwd = root) - .out.trim() - expect(output == message) - } + |""".stripMargin) + .fromRoot { root => + val output = + os.proc(TestUtil.cli, extraOptions, "print.sc", "messages.sc", "--native") + .call(cwd = root) + .out.trim() + expect(output == message) + } } test("Multiple scripts native") { From 53915870e9fc7e894fb8bcfc27641e3eaf9d04cc Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Thu, 18 Apr 2024 11:04:16 +0200 Subject: [PATCH 03/15] Fix reference docs --- website/docs/reference/cli-options.md | 2 +- .../reference/scala-command/cli-options.md | 2 +- .../scala-command/runner-specification.md | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 2cdd87c2c8..1ec7695f96 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -1352,7 +1352,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` ### `--native-version` -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). ### `--native-mode` diff --git a/website/docs/reference/scala-command/cli-options.md b/website/docs/reference/scala-command/cli-options.md index d5e8eb0a77..c9f49a7a18 100644 --- a/website/docs/reference/scala-command/cli-options.md +++ b/website/docs/reference/scala-command/cli-options.md @@ -838,7 +838,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` `SHOULD have` per Scala Runner specification -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). ### `--native-mode` diff --git a/website/docs/reference/scala-command/runner-specification.md b/website/docs/reference/scala-command/runner-specification.md index 0a8e1502b8..73606fd85a 100644 --- a/website/docs/reference/scala-command/runner-specification.md +++ b/website/docs/reference/scala-command/runner-specification.md @@ -174,7 +174,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -935,7 +935,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -1500,7 +1500,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -2091,7 +2091,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -2701,7 +2701,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -3287,7 +3287,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -3910,7 +3910,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -4584,7 +4584,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** @@ -5489,7 +5489,7 @@ Enable Scala Native. To show more options for Scala Native pass `--help-native` **--native-version** -Set the Scala Native version (0.4.17 by default). +Set the Scala Native version (0.5.1 by default). **--native-mode** From d19858e8c70f515c97c1366ef1ca2621a8919afb Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 19 Apr 2024 14:33:47 +0200 Subject: [PATCH 04/15] Downgrade Scala Native default version to 0.4.17 when used with Scala Toolkit and/or Typelevel Toolkit --- build.sc | 2 + .../cli/commands/shared/SharedOptions.scala | 56 ++++++++----- .../preprocessing/directives/Toolkit.scala | 82 +++++++++++++------ .../RunScalaNativeTestDefinitions.scala | 70 ++++++++++++---- .../build/options/SNNumeralVersion.scala | 3 +- .../build/options/ScalaNativeOptions.scala | 15 +++- project/deps.sc | 30 ++++--- 7 files changed, 180 insertions(+), 78 deletions(-) diff --git a/build.sc b/build.sc index 379e00cb3a..5a8dd69f09 100644 --- a/build.sc +++ b/build.sc @@ -442,9 +442,11 @@ trait Core extends ScalaCliCrossSbtModule | def toolkitName = "${Deps.toolkit.dep.module.name.value}" | def toolkitTestName = "${Deps.toolkitTest.dep.module.name.value}" | def toolkitDefaultVersion = "${Deps.toolkitVersion}" + | def toolkitMaxScalaNative = "${Deps.Versions.maxScalaNativeForToolkit}" | | def typelevelOrganization = "${Deps.typelevelToolkit.dep.module.organization.value}" | def typelevelToolkitDefaultVersion = "${Deps.typelevelToolkitVersion}" + | def typelevelToolkitMaxScalaNative = "${Deps.Versions.maxScalaNativeForTypelevelToolkit}" | | def defaultScalaVersion = "${Scala.defaultUser}" | def defaultScala212Version = "${Scala.scala212}" diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala index 6e92307fcc..3d7988ab09 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala @@ -265,21 +265,25 @@ final case class SharedOptions( ) } - private def scalaNativeOptions(opts: ScalaNativeOptions): options.ScalaNativeOptions = { + private def scalaNativeOptions( + opts: ScalaNativeOptions, + maxDefaultScalaNativeVersions: List[String] + ): options.ScalaNativeOptions = { import opts._ options.ScalaNativeOptions( - nativeVersion, - nativeMode, - nativeLto, - nativeGc, - nativeClang, - nativeClangpp, - nativeLinking, - nativeLinkingDefaults, - nativeCompile, - nativeCompileDefaults, - embedResources, - nativeTarget + version = nativeVersion, + modeStr = nativeMode, + ltoStr = nativeLto, + gcStr = nativeGc, + clang = nativeClang, + clangpp = nativeClangpp, + linkingOptions = nativeLinking, + linkingDefaults = nativeLinkingDefaults, + compileOptions = nativeCompile, + compileDefaults = nativeCompileDefaults, + embedResources = embedResources, + buildTargetStr = nativeTarget, + maxDefaultNativeVersions = maxDefaultScalaNativeVersions ) } @@ -324,7 +328,9 @@ final case class SharedOptions( s"""[${Console.YELLOW}warn${Console.RESET}] Jars with the ${ScalaCliConsole.GRAY}*-sources.jar${Console.RESET} name suffix are assumed to be source jars. |The following jars were assumed to be source jars and will be treated as such: $assumedSourceJarsString""".stripMargin ) - val resolvedToolkitDependency = SharedOptions.resolveToolkitDependency(withToolkit, logger) + val (resolvedToolkitDependency, toolkitMaxDefaultScalaNativeVersions) = + SharedOptions.resolveToolkitDependencyAndScalaNativeVersionReqs(withToolkit, logger) + val snOpts = scalaNativeOptions(native, toolkitMaxDefaultScalaNativeVersions.toList) bo.BuildOptions( sourceGeneratorOptions = bo.SourceGeneratorOptions( useBuildInfo = sourceGenerator.useBuildInfo, @@ -382,7 +388,7 @@ final case class SharedOptions( forceObjectWrapper = objectWrapper ), scalaJsOptions = scalaJsOptions(js), - scalaNativeOptions = scalaNativeOptions(native), + scalaNativeOptions = snOpts, javaOptions = value(scala.cli.commands.util.JvmUtils.javaOptions(jvm)), jmhOptions = bo.JmhOptions( addJmhDependencies = @@ -727,10 +733,10 @@ object SharedOptions { // TODO: remove this state after resolving https://github.com/VirtusLab/scala-cli/issues/2658 private val loggedDeprecatedToolkitWarning: AtomicBoolean = AtomicBoolean(false) - private def resolveToolkitDependency( + private def resolveToolkitDependencyAndScalaNativeVersionReqs( toolkitVersion: Option[String], logger: Logger - ): Seq[Positioned[AnyDependency]] = { + ): (Seq[Positioned[AnyDependency]], Seq[String]) = { if ( (toolkitVersion.contains("latest") || toolkitVersion.contains(Toolkit.typelevel + ":latest") @@ -743,7 +749,19 @@ object SharedOptions { ) ) - toolkitVersion.toList.map(Positioned.commandLine) - .flatMap(Toolkit.resolveDependenciesWithRequirements(_).map(_.value)) + val (dependencies, toolkitDefaults) = + toolkitVersion.toList.map(Positioned.commandLine) + .flatMap(Toolkit.resolveDependenciesWithRequirements(_).map((wbr, td) => wbr.value -> td)) + .unzip + val maxScalaNativeVersions = + toolkitDefaults.flatMap { + case Toolkit.ToolkitDefaults(isScalaToolkitDefault, isTypelevelToolkitDefault) => + val st = if (isScalaToolkitDefault) Seq(Constants.toolkitMaxScalaNative) else Nil + val tlt = + if (isTypelevelToolkitDefault) Seq(Constants.typelevelToolkitMaxScalaNative) else Nil + st ++ tlt + case _ => Nil + } + dependencies -> maxScalaNativeVersions } } diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala index c34da0957e..6188f302fd 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala @@ -12,6 +12,7 @@ import scala.build.options.{ BuildOptions, BuildRequirements, ClassPathOptions, + ScalaNativeOptions, Scope, ShadowingSeq, WithBuildRequirements @@ -42,19 +43,32 @@ final case class Toolkit( object Toolkit { val typelevel = "typelevel" + val scala = "scala" object TypelevelToolkit { def unapply(s: Option[String]): Boolean = s.contains(typelevel) || s.contains(Constants.typelevelOrganization) } + object ScalaToolkit { + def unapply(s: Option[String]): Boolean = + s.isEmpty || s.contains(Constants.toolkitOrganization) || s.contains(scala) + } + + case class ToolkitDefaults( + isScalaToolkitDefault: Boolean = false, + isTypelevelToolkitDefault: Boolean = false + ) + /** @param toolkitCoords * the toolkit coordinates * @return * the `toolkit` and `toolkit-test` dependencies with the appropriate build requirements */ - def resolveDependenciesWithRequirements(toolkitCoords: Positioned[String]) - : List[WithBuildRequirements[Positioned[DependencyLike[NameAttributes, NameAttributes]]]] = + def resolveDependenciesWithRequirements(toolkitCoords: Positioned[String]): List[( + WithBuildRequirements[Positioned[DependencyLike[NameAttributes, NameAttributes]]], + ToolkitDefaults + )] = toolkitCoords match case Positioned(positions, coords) => val tokens = coords.split(':') @@ -62,22 +76,27 @@ object Toolkit { def isDefault = rawVersion == "default" val notDefaultVersion = if rawVersion == "latest" then "latest.release" else rawVersion val flavor = tokens.dropRight(1).headOption - val (org, v) = flavor match { - case TypelevelToolkit() => Constants.typelevelOrganization -> { + val (org, v, trv: ToolkitDefaults) = flavor match { + case TypelevelToolkit() => ( + Constants.typelevelOrganization, if isDefault then Constants.typelevelToolkitDefaultVersion - else notDefaultVersion - } - case Some(org) => org -> notDefaultVersion - case None => Constants.toolkitOrganization -> { + else notDefaultVersion, + ToolkitDefaults(isTypelevelToolkitDefault = isDefault) + ) + case ScalaToolkit() | None => + ( + Constants.toolkitOrganization, if isDefault then Constants.toolkitDefaultVersion - else notDefaultVersion - } + else notDefaultVersion, + ToolkitDefaults(isScalaToolkitDefault = isDefault) + ) + case Some(org) => (org, notDefaultVersion, ToolkitDefaults()) } List( Positioned(positions, dep"$org::${Constants.toolkitName}::$v,toolkit") - .withEmptyRequirements, + .withEmptyRequirements -> trv, Positioned(positions, dep"$org::${Constants.toolkitTestName}::$v,toolkit") - .withScopeRequirement(Scope.Test) + .withScopeRequirement(Scope.Test) -> trv ) val handler: DirectiveHandler[Toolkit] = DirectiveHandler.derive @@ -105,20 +124,33 @@ object Toolkit { ): List[Either[BuildException, WithBuildRequirements[BuildOptions]]] = t .toList .flatMap(resolveDependenciesWithRequirements) // resolve dependencies - .map { case WithBuildRequirements(requirements, positionedDep) => - positionedDep - .withBuildRequirements { - if requirements.scope.isEmpty then // if the scope is not set, set it to the default - requirements.copy(scope = defaultScope.map(_.asScopeRequirement)) - else requirements - } - .map { dep => - BuildOptions( - classPathOptions = ClassPathOptions( - extraDependencies = ShadowingSeq.from(List(dep)) + .map { + case ( + WithBuildRequirements(requirements, positionedDep), + ToolkitDefaults(isScalaToolkitDefault, isTypelevelToolkitDefault) + ) => + val scalaToolkitMaxNativeVersions = + if isScalaToolkitDefault then List(Constants.toolkitMaxScalaNative) else Nil + val typelevelToolkitMaxNativeVersions = + if isTypelevelToolkitDefault then List(Constants.typelevelToolkitMaxScalaNative) else Nil + val maxNativeVersions = + (scalaToolkitMaxNativeVersions ++ typelevelToolkitMaxNativeVersions).distinct + positionedDep + .withBuildRequirements { + if requirements.scope.isEmpty then // if the scope is not set, set it to the default + requirements.copy(scope = defaultScope.map(_.asScopeRequirement)) + else requirements + } + .map { dep => + BuildOptions( + classPathOptions = ClassPathOptions( + extraDependencies = ShadowingSeq.from(List(dep)) + ), + scalaNativeOptions = ScalaNativeOptions( + maxDefaultNativeVersions = maxNativeVersions + ) ) - ) - } + } } .groupBy(_.requirements.scope.map(_.scope)) .toList diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala index 95dc6ac78a..9b3a5ac7be 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala @@ -297,23 +297,59 @@ trait RunScalaNativeTestDefinitions { _: RunTestDefinitions => } if (!actualScalaVersion.startsWith("2.12")) - test("native defaults & toolkit default") { - TestInputs( - os.rel / "toolkit.scala" -> - """//> using toolkit default - |//> using toolkit typelevel:default - | - |//> using platform native - | - |import cats.effect._ - | - |object Hello extends IOApp.Simple { - | def run = IO.println(os.pwd) - |} - |""".stripMargin - ).fromRoot { root => - val result = os.proc(TestUtil.cli, "run", "toolkit.scala", extraOptions).call(cwd = root) - expect(result.out.trim() == root.toString) + for { + useDirectives <- Seq(true, false) + titleStr = if (useDirectives) "with directives" else "with command line args" + } { + test(s"native & typelevel toolkit defaults $titleStr") { + val expectedMessage = "Hello" + val cmdLineOpts = + if (useDirectives) Nil + else Seq("--toolkit", "typelevel:default", "--native") + val directivesStr = + if (useDirectives) + """//> using toolkit typelevel:default + |//> using platform native + |""".stripMargin + else "" + TestInputs( + os.rel / "toolkit.scala" -> + s"""$directivesStr + |import cats.effect._ + | + |object Hello extends IOApp.Simple { + | def run = IO.println("$expectedMessage") + |} + |""".stripMargin + ).fromRoot { root => + val result = os.proc(TestUtil.cli, "run", "toolkit.scala", cmdLineOpts, extraOptions) + .call(cwd = root) + expect(result.out.trim() == expectedMessage) + } + } + + test(s"native & scala toolkit defaults $titleStr") { + val cmdLineOpts = + if (useDirectives) Nil + else Seq("--toolkit", "default", "--native") + val directivesStr = + if (useDirectives) + """//> using toolkit default + |//> using platform native + |""".stripMargin + else "" + TestInputs( + os.rel / "toolkit.scala" -> + s"""$directivesStr + |object Hello extends App { + | println(os.pwd) + |} + |""".stripMargin + ).fromRoot { root => + val result = os.proc(TestUtil.cli, "run", "toolkit.scala", cmdLineOpts, extraOptions) + .call(cwd = root) + expect(result.out.trim() == root.toString) + } } } } diff --git a/modules/options/src/main/scala/scala/build/options/SNNumeralVersion.scala b/modules/options/src/main/scala/scala/build/options/SNNumeralVersion.scala index a7e86ad66a..0e27e5f9bf 100644 --- a/modules/options/src/main/scala/scala/build/options/SNNumeralVersion.scala +++ b/modules/options/src/main/scala/scala/build/options/SNNumeralVersion.scala @@ -15,7 +15,8 @@ case class SNNumeralVersion(major: Int, minor: Int, patch: Int) { } object SNNumeralVersion { - private val VersionPattern = raw"(\d+)\.(\d+)\.(\d+)(\-.*)?".r + implicit val ordering: Ordering[SNNumeralVersion] = Ordering.by(v => (v.major, v.minor, v.patch)) + private val VersionPattern = raw"(\d+)\.(\d+)\.(\d+)(\-.*)?".r // tags/suffixes are not included or compared since they usually // should offer no feature compatibility improvements diff --git a/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala b/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala index d5f2d8d8c9..5552b9bc20 100644 --- a/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala @@ -39,12 +39,21 @@ final case class ScalaNativeOptions( compileOptions: List[String] = Nil, compileDefaults: Option[Boolean] = None, embedResources: Option[Boolean] = None, - buildTargetStr: Option[String] = None + buildTargetStr: Option[String] = None, + maxDefaultNativeVersions: List[String] = Nil ) { - def finalVersion = version.map(_.trim).filter(_.nonEmpty).getOrElse(Constants.scalaNativeVersion) + def defaultMaxVersion: Option[String] = + maxDefaultNativeVersions + .map(v => v -> SNNumeralVersion.parse(v)) + .minByOption(_._2) + .map(_._1) - def numeralVersion = SNNumeralVersion.parse(finalVersion) + def finalVersion: String = version.map(_.trim).filter(_.nonEmpty) + .orElse(defaultMaxVersion) + .getOrElse(Constants.scalaNativeVersion) + + def numeralVersion: Option[SNNumeralVersion] = SNNumeralVersion.parse(finalVersion) def target(): Option[ScalaNativeTarget] = buildTargetStr.flatMap(ScalaNativeTarget.fromString) diff --git a/project/deps.sc b/project/deps.sc index abeb4871c2..a894875ad9 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -89,19 +89,23 @@ object InternalDeps { object Deps { object Versions { // jni-utils version may need to be sync-ed when bumping the coursier version - def coursierDefault = "2.1.9" - def coursier = coursierDefault - def coursierCli = coursierDefault - def coursierM1Cli = coursierDefault - def jsoniterScala = "2.23.2" - def jsoniterScalaJava8 = "2.13.5.2" - def scalaMeta = "4.9.3" - def scalaNative = "0.5.1" - def scalaPackager = "0.1.29" - def signingCli = "0.2.3" - def signingCliJvmVersion = 17 - def javaClassName = "0.1.3" - def bloop = "1.5.16-sc-2" + def coursierDefault = "2.1.9" + def coursier = coursierDefault + def coursierCli = coursierDefault + def coursierM1Cli = coursierDefault + def jsoniterScala = "2.23.2" + def jsoniterScalaJava8 = "2.13.5.2" + def scalaMeta = "4.9.3" + def scalaNative04 = "0.4.17" + def scalaNative05 = "0.5.1" + def scalaNative = scalaNative05 + def maxScalaNativeForToolkit = scalaNative04 + def maxScalaNativeForTypelevelToolkit = scalaNative04 + def scalaPackager = "0.1.29" + def signingCli = "0.2.3" + def signingCliJvmVersion = 17 + def javaClassName = "0.1.3" + def bloop = "1.5.16-sc-2" } // DO NOT hardcode a Scala version in this dependency string // This dependency is used to ensure that Ammonite is available for Scala versions From 1056138875045ed5cb41181d3f027b6ae998f6c6 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 19 Apr 2024 15:35:28 +0200 Subject: [PATCH 05/15] Fix printed Scala Native platform default version --- .../src/main/scala/scala/build/options/BuildOptions.scala | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index 92b191bd37..cb3c4eb222 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -66,9 +66,7 @@ final case class BuildOptions( val scalaJsVersion = scalaJsOptions.version.getOrElse(Constants.scalaJsVersion) s"Scala.js $scalaJsVersion" case Platform.Native => - val scalaNativeVersion = - scalaNativeOptions.version.getOrElse(Constants.scalaNativeVersion) - s"Scala Native $scalaNativeVersion" + s"Scala Native ${scalaNativeOptions.finalVersion}" } Seq(s"Scala ${scalaParams0.scalaVersion}", platform0) case None => From bf9606f46f8ae43bf03d45170dd7d7a9ce14aed2 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Fri, 19 Apr 2024 15:57:54 +0200 Subject: [PATCH 06/15] Downgrade default Scala Native version to 0.4.17 for ScalaPy --- build.sc | 1 + .../cli/commands/shared/SharedOptions.scala | 8 ++++-- .../preprocessing/directives/Python.scala | 6 ++++- .../preprocessing/directives/Toolkit.scala | 10 +------ .../RunScalaPyTestDefinitions.scala | 27 ++++++++++++++----- project/deps.sc | 1 + 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/build.sc b/build.sc index 5a8dd69f09..49deda5308 100644 --- a/build.sc +++ b/build.sc @@ -475,6 +475,7 @@ trait Core extends ScalaCliCrossSbtModule | def libsodiumjniVersion = "${Deps.libsodiumjni.dep.version}" | | def scalaPyVersion = "${Deps.scalaPy.dep.version}" + | def scalaPyMaxScalaNative = "${Deps.Versions.maxScalaNativeForScalaPy}" | | def giter8Organization = "${Deps.giter8.dep.module.organization.value}" | def giter8Name = "${Deps.giter8.dep.module.name.value}" diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala index 3d7988ab09..941a2d3892 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala @@ -330,7 +330,12 @@ final case class SharedOptions( ) val (resolvedToolkitDependency, toolkitMaxDefaultScalaNativeVersions) = SharedOptions.resolveToolkitDependencyAndScalaNativeVersionReqs(withToolkit, logger) - val snOpts = scalaNativeOptions(native, toolkitMaxDefaultScalaNativeVersions.toList) + val scalapyMaxDefaultScalaNativeVersions = + if sharedPython.python.contains(true) then List(Constants.scalaPyMaxScalaNative) + else Nil + val maxDefaultScalaNativeVersions = + toolkitMaxDefaultScalaNativeVersions.toList ++ scalapyMaxDefaultScalaNativeVersions + val snOpts = scalaNativeOptions(native, maxDefaultScalaNativeVersions) bo.BuildOptions( sourceGeneratorOptions = bo.SourceGeneratorOptions( useBuildInfo = sourceGenerator.useBuildInfo, @@ -760,7 +765,6 @@ object SharedOptions { val tlt = if (isTypelevelToolkitDefault) Seq(Constants.typelevelToolkitMaxScalaNative) else Nil st ++ tlt - case _ => Nil } dependencies -> maxScalaNativeVersions } diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala index 92c22a8b19..7f14de4d12 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala @@ -2,7 +2,8 @@ package scala.build.preprocessing.directives import scala.build.directives.* import scala.build.errors.BuildException -import scala.build.options.{BuildOptions, PostBuildOptions} +import scala.build.internal.Constants +import scala.build.options.{BuildOptions, PostBuildOptions, ScalaNativeOptions} import scala.build.preprocessing.ScopePath import scala.cli.commands.SpecificationLevel @@ -17,6 +18,9 @@ final case class Python( val options = BuildOptions( notForBloopOptions = PostBuildOptions( python = Some(true) + ), + scalaNativeOptions = ScalaNativeOptions( + maxDefaultNativeVersions = List(Constants.scalaPyMaxScalaNative) ) ) Right(options) diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala index 6188f302fd..5bdd4c3b5d 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala @@ -8,15 +8,7 @@ import scala.build.errors.BuildException import scala.build.internal.Constants import scala.build.options.BuildRequirements.ScopeRequirement import scala.build.options.WithBuildRequirements.* -import scala.build.options.{ - BuildOptions, - BuildRequirements, - ClassPathOptions, - ScalaNativeOptions, - Scope, - ShadowingSeq, - WithBuildRequirements -} +import scala.build.options._ import scala.cli.commands.SpecificationLevel @DirectiveGroupName("Toolkit") diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala index a1a8fa921c..7dc6049bc5 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala @@ -46,10 +46,20 @@ trait RunScalaPyTestDefinitions { _: RunTestDefinitions => scalapyTest(useDirective = true) } - def scalapyNativeTest(): Unit = { + def scalapyNativeTest(useDirectives: Boolean): Unit = { + val maybeDirectives = + if (useDirectives) + """//> using python + |//> using platform native + |""".stripMargin + else "" + val maybeCliArg = + if (useDirectives) Nil + else Seq("--python", "--native") val inputs = TestInputs( os.rel / "helloscalapy.sc" -> - s"""$maybeScalapyPrefix + s"""$maybeDirectives + |$maybeScalapyPrefix |import py.SeqConverters |py.local { | val len = py.Dynamic.global.len(List(0, 2, 3).toPythonProxy) @@ -60,7 +70,7 @@ trait RunScalaPyTestDefinitions { _: RunTestDefinitions => inputs.fromRoot { root => val res = - os.proc(TestUtil.cli, "--power", "run", extraOptions, ".", "--python", "--native").call( + os.proc(TestUtil.cli, "--power", "run", extraOptions, ".", maybeCliArg).call( cwd = root ) val output = res.out.trim() @@ -77,10 +87,15 @@ trait RunScalaPyTestDefinitions { _: RunTestDefinitions => // disabled on Windows for now, for context, see // https://github.com/VirtusLab/scala-cli/pull/1270#issuecomment-1237904394 - if (!Properties.isWin) - test("scalapy native") { - scalapyNativeTest() + if (!Properties.isWin) { + test("scalapy native with directives") { + scalapyNativeTest(useDirectives = true) + } + + test("scalapy native with CLI args") { + scalapyNativeTest(useDirectives = false) } + } def pythonAndScalaSourcesTest(native: Boolean): Unit = { val tq = "\"\"\"" diff --git a/project/deps.sc b/project/deps.sc index a894875ad9..ee0ef36b6e 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -101,6 +101,7 @@ object Deps { def scalaNative = scalaNative05 def maxScalaNativeForToolkit = scalaNative04 def maxScalaNativeForTypelevelToolkit = scalaNative04 + def maxScalaNativeForScalaPy = scalaNative04 def scalaPackager = "0.1.29" def signingCli = "0.2.3" def signingCliJvmVersion = 17 From fe52f789efa180c95c3fb027c7d1de7b87b4743c Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 10:58:34 +0200 Subject: [PATCH 07/15] Downgrade Scala Native version to 0.4.17 in `scalacheck` from `cats` tests --- .../scala/scala/cli/integration/TestTestDefinitions.scala | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala index 6df0a98aa5..ac247aff49 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala @@ -96,8 +96,9 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr val successfulScalaCheckFromCatsNativeInputs: TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using scala "2.13.8" - |//> using platform "native" + """//> using scala 2.13 + |//> using platform native + |//> using nativeVersion 0.4.17 |//> using dep "org.typelevel::cats-kernel-laws::2.8.0" | |import org.scalacheck._ From a78c0780a219b2f2ca2578809740f97c33bb9bd4 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 11:12:38 +0200 Subject: [PATCH 08/15] Bump test frameworks in integration tests to versions supporting Scala Native 0.5.x --- .../cli/integration/TestTestDefinitions.scala | 381 +++++++++--------- 1 file changed, 192 insertions(+), 189 deletions(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala index ac247aff49..9fece857a2 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala @@ -13,8 +13,11 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr protected lazy val baseExtraOptions: Seq[String] = TestUtil.extraOptions ++ jvmOptions private lazy val extraOptions: Seq[String] = scalaVersionArgs ++ baseExtraOptions - def successfulTestInputs(directivesString: String = "//> using dep org.scalameta::munit::0.7.29") - : TestInputs = TestInputs( + private val munitVersion = "1.0.0-M12" + private val utestVersion = "0.8.3" + + def successfulTestInputs(directivesString: String = + s"//> using dep org.scalameta::munit::$munitVersion"): TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> s"""$directivesString | @@ -29,69 +32,69 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr val failingTestInputs: TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "org.scalameta::munit::0.7.29" - | - |class MyTests extends munit.FunSuite { - | test("foo") { - | assert(2 + 2 == 5, "Hello from " + "tests") - | } - |} - |""".stripMargin + s"""//> using dep org.scalameta::munit::$munitVersion + | + |class MyTests extends munit.FunSuite { + | test("foo") { + | assert(2 + 2 == 5, "Hello from " + "tests") + | } + |} + |""".stripMargin ) val successfulUtestInputs: TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "com.lihaoyi::utest::0.7.10" - |import utest._ - | - |object MyTests extends TestSuite { - | val tests = Tests { - | test("foo") { - | assert(2 + 2 == 4) - | println("Hello from " + "tests") - | } - | } - |} - |""".stripMargin + s"""//> using dep com.lihaoyi::utest::$utestVersion + |import utest._ + | + |object MyTests extends TestSuite { + | val tests = Tests { + | test("foo") { + | assert(2 + 2 == 4) + | println("Hello from " + "tests") + | } + | } + |} + |""".stripMargin ) val successfulUtestJsInputs: TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "com.lihaoyi::utest::0.7.10" - |import utest._ - |import scala.scalajs.js - | - |object MyTests extends TestSuite { - | val tests = Tests { - | test("foo") { - | assert(2 + 2 == 4) - | val console = js.Dynamic.global.console - | console.log("Hello from " + "tests") - | } - | } - |} - |""".stripMargin + s"""//> using dep com.lihaoyi::utest::$utestVersion + |import utest._ + |import scala.scalajs.js + | + |object MyTests extends TestSuite { + | val tests = Tests { + | test("foo") { + | assert(2 + 2 == 4) + | val console = js.Dynamic.global.console + | console.log("Hello from " + "tests") + | } + | } + |} + |""".stripMargin ) val successfulUtestNativeInputs: TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "com.lihaoyi::utest::0.7.10" - |import utest._ - |import scala.scalanative.libc._ - |import scala.scalanative.unsafe._ - | - |object MyTests extends TestSuite { - | val tests = Tests { - | test("foo") { - | assert(2 + 2 == 4) - | Zone { implicit z => - | val io = StdioHelpers(stdio) - | io.printf(c"%s %s\n", c"Hello from", c"tests") - | } - | } - | } - |} - |""".stripMargin + s"""//> using dep com.lihaoyi::utest::$utestVersion + |import utest._ + |import scala.scalanative.libc._ + |import scala.scalanative.unsafe._ + | + |object MyTests extends TestSuite { + | val tests = Tests { + | test("foo") { + | assert(2 + 2 == 4) + | Zone { implicit z => + | val io = StdioHelpers(stdio) + | io.printf(c"%s %s", c"Hello from", c"tests") + | } + | } + | } + |} + |""".stripMargin ) val successfulScalaCheckFromCatsNativeInputs: TestInputs = TestInputs( @@ -130,25 +133,25 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr val severalTestsInputs: TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "org.scalameta::munit::0.7.29" - | - |class MyTests extends munit.FunSuite { - | test("foo") { - | assert(2 + 2 == 4) - | println("Hello from " + "tests1") - | } - |} - |""".stripMargin, + s"""//> using dep org.scalameta::munit::$munitVersion + | + |class MyTests extends munit.FunSuite { + | test("foo") { + | assert(2 + 2 == 4) + | println("Hello from " + "tests1") + | } + |} + |""".stripMargin, os.rel / "OtherTests.test.scala" -> - """//> using dep "org.scalameta::munit::0.7.29" - | - |class OtherTests extends munit.FunSuite { - | test("bar") { - | assert(1 + 1 == 2) - | println("Hello from " + "tests2") - | } - |} - |""".stripMargin + s"""//> using dep org.scalameta::munit::$munitVersion + | + |class OtherTests extends munit.FunSuite { + | test("bar") { + | assert(1 + 1 == 2) + | println("Hello from " + "tests2") + | } + |} + |""".stripMargin ) val successfulWeaverInputs: TestInputs = TestInputs( @@ -167,63 +170,63 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr val successfulESModuleTestInputs: TestInputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "org.scalameta::munit::0.7.29" - |//> using jsModuleKind "esmodule" - |import scala.scalajs.js - |import scala.scalajs.js.annotation._ - | - |@js.native - |@JSImport("console", JSImport.Namespace) - |object console extends js.Object { - | def log(msg: js.Any): Unit = js.native - |} - | - |class MyTests extends munit.FunSuite { - | test("foo") { - | assert(2 + 2 == 4) - | console.log("Hello from " + "tests") - | } - |} - |""".stripMargin + s"""//> using dep org.scalameta::munit::$munitVersion + |//> using jsModuleKind esmodule + |import scala.scalajs.js + |import scala.scalajs.js.annotation._ + | + |@js.native + |@JSImport("console", JSImport.Namespace) + |object console extends js.Object { + | def log(msg: js.Any): Unit = js.native + |} + | + |class MyTests extends munit.FunSuite { + | test("foo") { + | assert(2 + 2 == 4) + | console.log("Hello from " + "tests") + | } + |} + |""".stripMargin ) val successfulMarkdownTestInputs: TestInputs = TestInputs( os.rel / "Test.md" -> - """# Example Markdown File - |This is an example for how Scala test code can be run from a Markdown file. - | - |## Example Snippet - |```scala test - |//> using dep "org.scalameta::munit:0.7.29" - | - |class Test extends munit.FunSuite { - | test("foo") { - | assert(2 + 2 == 4) - | println("Hello from tests") - | } - |} - |``` - | - |""".stripMargin + s"""# Example Markdown File + |This is an example for how Scala test code can be run from a Markdown file. + | + |## Example Snippet + |```scala test + |//> using dep org.scalameta::munit:$munitVersion + | + |class Test extends munit.FunSuite { + | test("foo") { + | assert(2 + 2 == 4) + | println("Hello from tests") + | } + |} + |``` + | + |""".stripMargin ) val failingMarkdownTestInputs: TestInputs = TestInputs( os.rel / "Test.md" -> - """# Example Markdown File - |This is an example for how Scala test code can be run from a Markdown file. - | - |## Example Snippet - |```scala test - |//> using dep "org.scalameta::munit:0.7.29" - | - |class Test extends munit.FunSuite { - | test("foo") { - | assert(2 + 2 == 5, "Hello from tests") - | } - |} - |``` - | - |""".stripMargin + s"""# Example Markdown File + |This is an example for how Scala test code can be run from a Markdown file. + | + |## Example Snippet + |```scala test + |//> using dep org.scalameta::munit:$munitVersion + | + |class Test extends munit.FunSuite { + | test("foo") { + | assert(2 + 2 == 5, "Hello from tests") + | } + |} + |``` + | + |""".stripMargin ) test("successful test") { @@ -263,19 +266,19 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr test("run only one test from munit") { val inputs: TestInputs = TestInputs( os.rel / "MyTests.scala" -> - """//> using dep "org.scalameta::munit::0.7.29" - |package test - | - |class MyTests extends munit.FunSuite { - | test("foo") { - | assert(2 + 2 == 5, "foo") - | } - | test("bar") { - | assert(2 + 3 == 5) - | println("Hello from bar") - | } - |} - |""".stripMargin + s"""//> using dep org.scalameta::munit::$munitVersion + |package test + | + |class MyTests extends munit.FunSuite { + | test("foo") { + | assert(2 + 2 == 5, "foo") + | } + | test("bar") { + | assert(2 + 3 == 5) + | println("Hello from bar") + | } + |} + |""".stripMargin ) inputs.fromRoot { root => val res = @@ -297,32 +300,32 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr test("run only one test from utest") { val inputs: TestInputs = TestInputs( os.rel / "FooTests.test.scala" -> - """//> using dep "com.lihaoyi::utest::0.7.10" - |package tests.foo - |import utest._ - | - |object FooTests extends TestSuite { - | val tests = Tests { - | test("foo") { - | assert(2 + 2 == 5) - | } - | } - |} - |""".stripMargin, + s"""//> using dep com.lihaoyi::utest::$utestVersion + |package tests.foo + |import utest._ + | + |object FooTests extends TestSuite { + | val tests = Tests { + | test("foo") { + | assert(2 + 2 == 5) + | } + | } + |} + |""".stripMargin, os.rel / "BarTests.test.scala" -> - """//> using dep "com.lihaoyi::utest::0.7.10" - |package tests.bar - |import utest._ - | - |object BarTests extends TestSuite { - | val tests = Tests { - | test("bar") { - | assert(2 + 2 == 4) - | println("Hello from bar") - | } - | } - |} - |""".stripMargin + s"""//> using dep com.lihaoyi::utest::$utestVersion + |package tests.bar + |import utest._ + | + |object BarTests extends TestSuite { + | val tests = Tests { + | test("bar") { + | assert(2 + 2 == 4) + | println("Hello from bar") + | } + | } + |} + |""".stripMargin ) inputs.fromRoot { root => val res = @@ -398,15 +401,15 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr test("failing test return code when compiling error") { val inputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "org.scalameta::munit::0.7.29" - | - |class SomeTest extends munit.FunSuite { - | test("failig") { - | val s: String = 1 - | assert(true == true) - | } - |} - |""".stripMargin + s"""//> using dep org.scalameta::munit::$munitVersion + | + |class SomeTest extends munit.FunSuite { + | test("failig") { + | val s: String = 1 + | assert(true == true) + | } + |} + |""".stripMargin ) inputs.fromRoot { root => val res = os.proc(TestUtil.cli, "test", extraOptions, ".").call(cwd = root, check = false) @@ -494,7 +497,7 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr test(s"test framework arguments $platformName") { val inputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "org.scalatest::scalatest::3.2.9" + """//> using dep org.scalatest::scalatest::3.2.18 |import org.scalatest._ |import org.scalatest.flatspec._ |import org.scalatest.matchers._ @@ -536,20 +539,20 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr test(s"custom test framework $platformName") { val inputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "com.lihaoyi::utest::0.7.10" - | - |package mytests - |import utest._ - | - |object MyTests extends TestSuite { - | val tests = Tests { - | test("foo") { - | assert(2 + 2 == 4) - | println("Hello from " + "tests") - | } - | } - |} - |""".stripMargin, + s"""//> using dep com.lihaoyi::utest::$utestVersion + | + |package mytests + |import utest._ + | + |object MyTests extends TestSuite { + | val tests = Tests { + | test("foo") { + | assert(2 + 2 == 4) + | println("Hello from " + "tests") + | } + | } + |} + |""".stripMargin, os.rel / "CustomFramework.test.scala" -> """package custom | @@ -586,10 +589,10 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr test(s"Fail if no tests were run $platformName") { val inputs = TestInputs( os.rel / "MyTests.test.scala" -> - """//> using dep "org.scalameta::munit::0.7.29" - | - |object MyTests - |""".stripMargin + s"""//> using dep org.scalameta::munit::$munitVersion + | + |object MyTests + |""".stripMargin ) inputs.fromRoot { root => @@ -625,7 +628,7 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr val inputs = { var inputs0 = TestInputs( os.rel / "MyTests.scala" -> - s"""//> using dep "org.scalameta::munit::0.7.29" + s"""//> using dep org.scalameta::munit::$munitVersion |//> using platform $platforms | |class MyTests extends munit.FunSuite { @@ -683,8 +686,8 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr def jsDomTest(): Unit = { val inputs = TestInputs( os.rel / "JsDom.test.scala" -> - s"""//> using dep "com.lihaoyi::utest::0.7.10" - |//> using dep "org.scala-js::scalajs-dom::2.1.0" + s"""//> using dep com.lihaoyi::utest::$utestVersion + |//> using dep "org.scala-js::scalajs-dom::2.2.0" | |import utest._ | From ac40e489a79ed819447a295e2644a01a7b882aaf Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 11:24:14 +0200 Subject: [PATCH 09/15] Downgrade Scala Native to 0.4.17 in `scalatest` integration tests --- .../cli/integration/TestTestDefinitions.scala | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala index 9fece857a2..06ecc4b404 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/TestTestDefinitions.scala @@ -487,7 +487,7 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr val maybeJs = Seq("JS" -> Seq("--js")) val maybeNative = if (actualScalaVersion.startsWith("2.")) - Seq("Native" -> Seq("--native")) + Seq("native" -> Seq("--native")) else Nil Seq("JVM" -> Nil) ++ maybeJs ++ maybeNative @@ -510,8 +510,14 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr |""".stripMargin ) inputs.fromRoot { root => - val baseRes = os.proc(TestUtil.cli, "test", extraOptions, platformArgs, ".") - .call(cwd = root, check = false) + val scalaTestExtraArgs = + if (platformName == "native") + // FIXME: revert to using default Scala Native version when scalatest supports 0.5.x + Seq("--native-version", "0.4.17") + else Nil + val baseRes = + os.proc(TestUtil.cli, "test", extraOptions, platformArgs, scalaTestExtraArgs, ".") + .call(cwd = root, check = false) if (baseRes.exitCode != 0) { println(baseRes.out.text()) fail("scala-cli test falied", clues(baseRes.exitCode)) @@ -525,7 +531,16 @@ abstract class TestTestDefinitions extends ScalaCliSuite with TestScalaVersionAr .getOrElse(???) expect(!baseShouldThingLine.contains("millisecond")) - val res = os.proc(TestUtil.cli, "test", extraOptions, platformArgs, ".", "--", "-oD") + val res = os.proc( + TestUtil.cli, + "test", + extraOptions, + platformArgs, + scalaTestExtraArgs, + ".", + "--", + "-oD" + ) .call(cwd = root) val output = res.out.text() expect(output.contains("A thing")) From 12cdf52a9a07fedcfe79f9ebec92a6bf2fa9470f Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 12:53:04 +0200 Subject: [PATCH 10/15] Fix native packager tests --- .../test/scala/scala/cli/integration/NativePackagerTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/NativePackagerTests.scala b/modules/integration/src/test/scala/scala/cli/integration/NativePackagerTests.scala index 6cbbf44739..8a0927ce67 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/NativePackagerTests.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/NativePackagerTests.scala @@ -375,7 +375,7 @@ class NativePackagerTests extends ScalaCliSuite { helloWorldFileName, "--native", "-S", - "2.13.6", + "2.13", "--docker", "--docker-image-repository", imageRepository, From 471b102237318f126dfe42cc182c592cee83c081 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 13:00:43 +0200 Subject: [PATCH 11/15] Fix docs & gifs tests to support Scala Native 0.5.x --- gifs/scenarios/universal_tool.sh | 4 ++-- website/docs/commands/package.md | 2 +- website/docs/commands/run.md | 2 +- .../introduction/instant-startup-scala-scripts.md | 12 ++++++------ 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gifs/scenarios/universal_tool.sh b/gifs/scenarios/universal_tool.sh index 507333aee2..f16508841a 100755 --- a/gifs/scenarios/universal_tool.sh +++ b/gifs/scenarios/universal_tool.sh @@ -12,7 +12,7 @@ if [[ -z "${ASCIINEMA_REC}" ]]; then # Warm up scala-cli echo "println(1)" | scala-cli - echo "println(1)" | scala-cli --js - && - echo "println(1)" | scala-cli --native -S 2.13.6 - + echo "println(1)" | scala-cli --native -S 2.13 - # or do other preparation (e.g. create code) else @@ -38,7 +38,7 @@ object Native extends App { EOF pe "# Scala Native works only with Scala 2.x so far" - pe "scala-cli --native -S 2.13.6 native.scala" + pe "scala-cli --native -S 2.13 native.scala" doSleep 3 echo " " && echo "ok" > status.txt diff --git a/website/docs/commands/package.md b/website/docs/commands/package.md index f8a6ec1af6..0dc585248b 100644 --- a/website/docs/commands/package.md +++ b/website/docs/commands/package.md @@ -309,7 +309,7 @@ object Hello { ```bash -scala-cli --power package --native HelloNative.scala -S 2.13.6 -o hello +scala-cli --power package --native HelloNative.scala -S 2.13 -o hello file hello ``` diff --git a/website/docs/commands/run.md b/website/docs/commands/run.md index cd6a0748ec..4e0577ffef 100644 --- a/website/docs/commands/run.md +++ b/website/docs/commands/run.md @@ -252,7 +252,7 @@ the [Scala Native requirements](https://scala-native.readthedocs.io/en/latest/us need to be [installed](/install#scala-native) for this to work: ```bash -scala-cli Hello.scala --native -S 2.13.6 +scala-cli Hello.scala --native -S 2.13 ``` It is also possible to achieve it using `--platform` option: diff --git a/website/docs/cookbooks/introduction/instant-startup-scala-scripts.md b/website/docs/cookbooks/introduction/instant-startup-scala-scripts.md index d392292ffe..ca8679d878 100644 --- a/website/docs/cookbooks/introduction/instant-startup-scala-scripts.md +++ b/website/docs/cookbooks/introduction/instant-startup-scala-scripts.md @@ -44,8 +44,8 @@ scala-cli size-higher-than.scala -- dir 20 ``` ```text -Compiling project (Scala 3.1.1, JVM) -Compiled project (Scala 3.1.1, JVM) +Compiling project (Scala 3.4.1, JVM) +Compiled project (Scala 3.4.1, JVM) /Users/user/Documents/workspace/dir/large-file.txt ``` @@ -55,8 +55,8 @@ We can fix that by either running with a `—-native` option, or, in this case, by including an additional using directive: ```scala compile title=size-higher-than.scala -//> using scala 3.1.1 -//> using dep com.lihaoyi::os-lib::0.8.1 +//> using scala 3 +//> using dep com.lihaoyi::os-lib::0.10.0 //> using platform scala-native @main @@ -81,8 +81,8 @@ We can make the runtime itself even faster, using various Scala Native optimizat We pass these using a `-–native-mode` scala-cli option or, like previously, by adding a using directive: ```scala compile title=size-higher-than.scala -//> using scala 3.1.1 -//> using dep com.lihaoyi::os-lib::0.8.1 +//> using scala 3 +//> using dep com.lihaoyi::os-lib::0.10.0 //> using platform scala-native //> using nativeMode release-full From 62c4ecdf1dc2a28e03a839c5b069a5c6334e279a Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 14:00:51 +0200 Subject: [PATCH 12/15] Fix export tests to support Scala Native 0.5.x syntax --- .../scala/cli/integration/ExportTestProjects.scala | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala b/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala index 0f9302c039..d2c849b3f3 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala @@ -100,8 +100,8 @@ object ExportTestProjects { val nl = "\\n" val testFile = if (scalaVersion.startsWith("3.")) - s"""//> using scala "$scalaVersion" - |//> using platform "scala-native" + s"""//> using scala $scalaVersion + |//> using platform scala-native | |import scala.scalanative.libc._ |import scala.scalanative.unsafe._ @@ -109,14 +109,14 @@ object ExportTestProjects { |object Test: | def main(args: Array[String]): Unit = | val message = "Hello from " + "exported Scala CLI project" + "$nl" - | Zone { implicit z => + | Zone { | val io = StdioHelpers(stdio) | io.printf(c"%s", toCString(message)) | } |""".stripMargin else - s"""//> using scala "$scalaVersion" - |//> using platform "scala-native" + s"""//> using scala $scalaVersion + |//> using platform scala-native | |import scala.scalanative.libc._ |import scala.scalanative.unsafe._ @@ -124,7 +124,7 @@ object ExportTestProjects { |object Test { | def main(args: Array[String]): Unit = { | val message = "Hello from " + "exported Scala CLI project" + "$nl" - | Zone { implicit z => + | Zone.acquire { implicit z => | val io = StdioHelpers(stdio) | io.printf(c"%s", toCString(message)) | } From 2c12e994bc1f9018902facee83b8f70f44bab2d1 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 14:20:31 +0200 Subject: [PATCH 13/15] Downgrade Scala Native default version to 0.4.17 for Mill export --- build.sc | 1 + .../main/scala/scala/cli/commands/export0/Export.scala | 10 +++++++++- .../scala/cli/exportCmd/MillProjectDescriptor.scala | 6 ++---- .../cli/integration/ExportCommonTestDefinitions.scala | 3 --- .../cli/integration/ExportMillTestDefinitions.scala | 5 +++++ .../cli/integration/ExportSbtTestDefinitions.scala | 4 ++++ .../scala/cli/integration/ExportTestProjects.scala | 6 +++--- project/deps.sc | 1 + 8 files changed, 25 insertions(+), 11 deletions(-) diff --git a/build.sc b/build.sc index 49deda5308..9d4cb0ef8f 100644 --- a/build.sc +++ b/build.sc @@ -433,6 +433,7 @@ trait Core extends ScalaCliCrossSbtModule | def ammoniteVersion = "${Deps.ammonite.dep.version}" | def millVersion = "${InternalDeps.Versions.mill}" | def lefouMillwRef = "${InternalDeps.Versions.lefouMillwRef}" + | def maxScalaNativeForMillExport = "${Deps.Versions.maxScalaNativeForMillExport}" | | def scalafmtOrganization = "${Deps.scalafmtCli.dep.module.organization.value}" | def scalafmtName = "${Deps.scalafmtCli.dep.module.name.value}" diff --git a/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala b/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala index bf2736681d..b692f9da2e 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala @@ -148,7 +148,15 @@ object Export extends ScalaCommand[ExportOptions] { val inputs = options.shared.inputs(args.all).orExit(logger) CurrentParams.workspaceOpt = Some(inputs.workspace) val baseOptions = - initialBuildOptions.copy(mainClass = options.mainClass.mainClass.filter(_.nonEmpty)) + initialBuildOptions + .copy( + scalaNativeOptions = initialBuildOptions.scalaNativeOptions.copy( + maxDefaultNativeVersions = + if shouldExportToMill then List(Constants.maxScalaNativeForMillExport) + else Nil + ), + mainClass = options.mainClass.mainClass.filter(_.nonEmpty) + ) val (sourcesMain, optionsMain0) = prepareBuild( diff --git a/modules/cli/src/main/scala/scala/cli/exportCmd/MillProjectDescriptor.scala b/modules/cli/src/main/scala/scala/cli/exportCmd/MillProjectDescriptor.scala index 313c7fa45e..8bef41d2bd 100644 --- a/modules/cli/src/main/scala/scala/cli/exportCmd/MillProjectDescriptor.scala +++ b/modules/cli/src/main/scala/scala/cli/exportCmd/MillProjectDescriptor.scala @@ -70,10 +70,8 @@ final case class MillProjectDescriptor( ) } - private def scalaNativeSettings(options: ScalaNativeOptions): MillProject = { - val scalaNativeVersion = Some(options.version.getOrElse(Constants.scalaNativeVersion)) - MillProject(scalaNativeVersion = scalaNativeVersion) - } + private def scalaNativeSettings(options: ScalaNativeOptions): MillProject = + MillProject(scalaNativeVersion = Some(options.finalVersion)) private def dependencySettings( mainOptions: BuildOptions, diff --git a/modules/integration/src/test/scala/scala/cli/integration/ExportCommonTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/ExportCommonTestDefinitions.scala index c648cf88bb..7aec73f0e3 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/ExportCommonTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/ExportCommonTestDefinitions.scala @@ -96,9 +96,6 @@ trait ExportCommonTestDefinitions { _: ScalaCliSuite & TestScalaVersionArgs => test("Scala.js") { simpleTest(ExportTestProjects.jsTest(actualScalaVersion)) } - test("Scala Native") { - simpleTest(ExportTestProjects.nativeTest(actualScalaVersion)) - } test("Ensure test framework NPE is not thrown when depending on logback") { logbackBugCase() } diff --git a/modules/integration/src/test/scala/scala/cli/integration/ExportMillTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/ExportMillTestDefinitions.scala index 3d4a05c656..ee26f0a06c 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/ExportMillTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/ExportMillTestDefinitions.scala @@ -96,4 +96,9 @@ abstract class ExportMillTestDefinitions extends ScalaCliSuite test("JVM with compiler plugin") { jvmTestCompilerPlugin() } + + test("Scala Native") { + // FIXME this should be adjusted to Scala Native 0.5.x syntax once Mill gets support for it + simpleTest(ExportTestProjects.nativeTest(actualScalaVersion, useNative04Syntax = true)) + } } diff --git a/modules/integration/src/test/scala/scala/cli/integration/ExportSbtTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/ExportSbtTestDefinitions.scala index fab1992572..090d9a5c8a 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/ExportSbtTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/ExportSbtTestDefinitions.scala @@ -38,4 +38,8 @@ abstract class ExportSbtTestDefinitions extends ScalaCliSuite override val runMainArgs: Seq[String] = Seq("run") override val runTestsArgs: Seq[String] = Seq("test") + + test("Scala Native") { + simpleTest(ExportTestProjects.nativeTest(actualScalaVersion)) + } } diff --git a/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala b/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala index d2c849b3f3..a67b176bfd 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/ExportTestProjects.scala @@ -96,7 +96,7 @@ object ExportTestProjects { TestInputs(os.rel / "Test.scala" -> testFile) } - def nativeTest(scalaVersion: String): TestInputs = { + def nativeTest(scalaVersion: String, useNative04Syntax: Boolean = false): TestInputs = { val nl = "\\n" val testFile = if (scalaVersion.startsWith("3.")) @@ -109,7 +109,7 @@ object ExportTestProjects { |object Test: | def main(args: Array[String]): Unit = | val message = "Hello from " + "exported Scala CLI project" + "$nl" - | Zone { + | Zone {${if (useNative04Syntax) " implicit z =>" else ""} | val io = StdioHelpers(stdio) | io.printf(c"%s", toCString(message)) | } @@ -124,7 +124,7 @@ object ExportTestProjects { |object Test { | def main(args: Array[String]): Unit = { | val message = "Hello from " + "exported Scala CLI project" + "$nl" - | Zone.acquire { implicit z => + | Zone${if (useNative04Syntax) "" else ".acquire"} { implicit z => | val io = StdioHelpers(stdio) | io.printf(c"%s", toCString(message)) | } diff --git a/project/deps.sc b/project/deps.sc index ee0ef36b6e..eedcba5f1d 100644 --- a/project/deps.sc +++ b/project/deps.sc @@ -102,6 +102,7 @@ object Deps { def maxScalaNativeForToolkit = scalaNative04 def maxScalaNativeForTypelevelToolkit = scalaNative04 def maxScalaNativeForScalaPy = scalaNative04 + def maxScalaNativeForMillExport = scalaNative04 def scalaPackager = "0.1.29" def signingCli = "0.2.3" def signingCliJvmVersion = 17 From 814c537fdc7205c71f137a00138dd9362b9cc8c7 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 14:26:53 +0200 Subject: [PATCH 14/15] Fix BuildInfo export Scala Native version --- .../src/main/scala/scala/build/info/BuildInfo.scala | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/options/src/main/scala/scala/build/info/BuildInfo.scala b/modules/options/src/main/scala/scala/build/info/BuildInfo.scala index 004825cfc7..761daf2488 100644 --- a/modules/options/src/main/scala/scala/build/info/BuildInfo.scala +++ b/modules/options/src/main/scala/scala/build/info/BuildInfo.scala @@ -144,14 +144,11 @@ object BuildInfo { ) } - private def scalaNativeSettings(options: ScalaNativeOptions): BuildInfo = { - val scalaNativeVersion = Some(options.version.getOrElse(Constants.scalaNativeVersion)) - + private def scalaNativeSettings(options: ScalaNativeOptions): BuildInfo = BuildInfo( platform = Some(Platform.Native.repr), - scalaNativeVersion = scalaNativeVersion + scalaNativeVersion = Some(options.finalVersion) ) - } private def jvmSettings(options: BuildOptions): BuildInfo = BuildInfo( From f959111d619d2be615846121bfd9ac05eab2a7e4 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 22 Apr 2024 15:06:35 +0200 Subject: [PATCH 15/15] Print a warning when Scala Native default version gets downgraded because of dependency limitations --- build.sc | 7 +++-- .../scala/cli/commands/export0/Export.scala | 9 ++++-- .../cli/commands/shared/SharedOptions.scala | 23 +++++++++++---- .../preprocessing/directives/Python.scala | 5 +++- .../preprocessing/directives/Toolkit.scala | 17 +++++++++-- .../RunScalaNativeTestDefinitions.scala | 28 +++++++++++++++++-- .../RunScalaPyTestDefinitions.scala | 17 +++++++++-- .../scala/build/options/BuildOptions.scala | 14 +++++++++- .../scala/build/options/HasHashData.scala | 6 ++++ .../build/options/ScalaNativeOptions.scala | 3 +- 10 files changed, 109 insertions(+), 20 deletions(-) diff --git a/build.sc b/build.sc index 9d4cb0ef8f..b4ec769c7f 100644 --- a/build.sc +++ b/build.sc @@ -987,6 +987,7 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests | def defaultGraalVMJavaVersion = "${deps.graalVmJavaVersion}" | def defaultGraalVMVersion = "${deps.graalVmVersion}" | def scalaPyVersion = "${Deps.scalaPy.dep.version}" + | def scalaPyMaxScalaNative = "${Deps.Versions.maxScalaNativeForScalaPy}" | def bloopVersion = "${Deps.bloopRifle.dep.version}" | def pprintVersion = "${TestDeps.pprint.dep.version}" | def munitVersion = "${TestDeps.munit.dep.version}" @@ -1002,8 +1003,10 @@ trait CliIntegration extends SbtModule with ScalaCliPublishModule with HasTests | def libsodiumVersion = "${deps.libsodiumVersion}" | def dockerArchLinuxImage = "${TestDeps.archLinuxImage}" | - | def toolkitVersion = "${Deps.toolkitVersion}" - | def typelevelToolkitVersion = "${Deps.typelevelToolkitVersion}" + | def toolkitVersion = "${Deps.toolkitVersion}" + | def toolkiMaxScalaNative = "${Deps.Versions.maxScalaNativeForToolkit}" + | def typelevelToolkitVersion = "${Deps.typelevelToolkitVersion}" + | def typelevelToolkitMaxScalaNative = "${Deps.Versions.maxScalaNativeForTypelevelToolkit}" | | def ghOrg = "$ghOrg" | def ghName = "$ghName" diff --git a/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala b/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala index b692f9da2e..b6820ad8ee 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/export0/Export.scala @@ -152,8 +152,13 @@ object Export extends ScalaCommand[ExportOptions] { .copy( scalaNativeOptions = initialBuildOptions.scalaNativeOptions.copy( maxDefaultNativeVersions = - if shouldExportToMill then List(Constants.maxScalaNativeForMillExport) - else Nil + initialBuildOptions.scalaNativeOptions.maxDefaultNativeVersions ++ + (if shouldExportToMill && Constants.scalaNativeVersion != Constants.maxScalaNativeForMillExport + then + val warningMsg = + s"Mill export does not support Scala Native ${Constants.scalaNativeVersion}, ${Constants.maxScalaNativeForMillExport} should be used instead." + List(Constants.maxScalaNativeForMillExport -> warningMsg) + else Nil) ), mainClass = options.mainClass.mainClass.filter(_.nonEmpty) ) diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala index 941a2d3892..f56f578413 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/SharedOptions.scala @@ -29,7 +29,7 @@ import scala.build.internal.{Constants, FetchExternalBinary, OsLibc, Util} import scala.build.options.ScalaVersionUtil.fileWithTtl0 import scala.build.options.{BuildOptions, ComputeVersion, Platform, ScalacOpt, ShadowingSeq} import scala.build.preprocessing.directives.ClasspathUtils.* -import scala.build.preprocessing.directives.Toolkit +import scala.build.preprocessing.directives.{Python, Toolkit} import scala.build.options as bo import scala.cli.ScalaCli import scala.cli.commands.publish.ConfigUtil.* @@ -267,7 +267,7 @@ final case class SharedOptions( private def scalaNativeOptions( opts: ScalaNativeOptions, - maxDefaultScalaNativeVersions: List[String] + maxDefaultScalaNativeVersions: List[(String, String)] ): options.ScalaNativeOptions = { import opts._ options.ScalaNativeOptions( @@ -331,7 +331,8 @@ final case class SharedOptions( val (resolvedToolkitDependency, toolkitMaxDefaultScalaNativeVersions) = SharedOptions.resolveToolkitDependencyAndScalaNativeVersionReqs(withToolkit, logger) val scalapyMaxDefaultScalaNativeVersions = - if sharedPython.python.contains(true) then List(Constants.scalaPyMaxScalaNative) + if sharedPython.python.contains(true) then + List(Constants.scalaPyMaxScalaNative -> Python.maxScalaNativeWarningMsg) else Nil val maxDefaultScalaNativeVersions = toolkitMaxDefaultScalaNativeVersions.toList ++ scalapyMaxDefaultScalaNativeVersions @@ -741,7 +742,7 @@ object SharedOptions { private def resolveToolkitDependencyAndScalaNativeVersionReqs( toolkitVersion: Option[String], logger: Logger - ): (Seq[Positioned[AnyDependency]], Seq[String]) = { + ): (Seq[Positioned[AnyDependency]], Seq[(String, String)]) = { if ( (toolkitVersion.contains("latest") || toolkitVersion.contains(Toolkit.typelevel + ":latest") @@ -761,9 +762,19 @@ object SharedOptions { val maxScalaNativeVersions = toolkitDefaults.flatMap { case Toolkit.ToolkitDefaults(isScalaToolkitDefault, isTypelevelToolkitDefault) => - val st = if (isScalaToolkitDefault) Seq(Constants.toolkitMaxScalaNative) else Nil + val st = if (isScalaToolkitDefault) + Seq(Constants.toolkitMaxScalaNative -> Toolkit.maxScalaNativeWarningMsg( + "Scala Toolkit", + Constants.toolkitMaxScalaNative + )) + else Nil val tlt = - if (isTypelevelToolkitDefault) Seq(Constants.typelevelToolkitMaxScalaNative) else Nil + if (isTypelevelToolkitDefault) + Seq(Constants.typelevelToolkitMaxScalaNative -> Toolkit.maxScalaNativeWarningMsg( + "TypeLevel Toolkit", + Constants.typelevelToolkitMaxScalaNative + )) + else Nil st ++ tlt } dependencies -> maxScalaNativeVersions diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala index 7f14de4d12..c7361f31d8 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Python.scala @@ -20,7 +20,8 @@ final case class Python( python = Some(true) ), scalaNativeOptions = ScalaNativeOptions( - maxDefaultNativeVersions = List(Constants.scalaPyMaxScalaNative) + maxDefaultNativeVersions = + List(Constants.scalaPyMaxScalaNative -> Python.maxScalaNativeWarningMsg) ) ) Right(options) @@ -29,4 +30,6 @@ final case class Python( object Python { val handler: DirectiveHandler[Python] = DirectiveHandler.derive + val maxScalaNativeWarningMsg = + s"ScalaPy does not support Scala Native ${Constants.scalaNativeVersion}, ${Constants.scalaPyMaxScalaNative} should be used instead." } diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala index 5bdd4c3b5d..8591494f92 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/Toolkit.scala @@ -37,6 +37,9 @@ object Toolkit { val typelevel = "typelevel" val scala = "scala" + def maxScalaNativeWarningMsg(toolkitName: String, maxNative: String): String = + s"$toolkitName does not support Scala Native ${Constants.scalaNativeVersion}, $maxNative should be used instead." + object TypelevelToolkit { def unapply(s: Option[String]): Boolean = s.contains(typelevel) || s.contains(Constants.typelevelOrganization) @@ -122,9 +125,19 @@ object Toolkit { ToolkitDefaults(isScalaToolkitDefault, isTypelevelToolkitDefault) ) => val scalaToolkitMaxNativeVersions = - if isScalaToolkitDefault then List(Constants.toolkitMaxScalaNative) else Nil + if isScalaToolkitDefault then + List(Constants.toolkitMaxScalaNative -> maxScalaNativeWarningMsg( + "Scala Toolkit", + Constants.toolkitMaxScalaNative + )) + else Nil val typelevelToolkitMaxNativeVersions = - if isTypelevelToolkitDefault then List(Constants.typelevelToolkitMaxScalaNative) else Nil + if isTypelevelToolkitDefault then + List(Constants.typelevelToolkitMaxScalaNative -> maxScalaNativeWarningMsg( + "TypeLevel Toolkit", + Constants.typelevelToolkitMaxScalaNative + )) + else Nil val maxNativeVersions = (scalaToolkitMaxNativeVersions ++ typelevelToolkitMaxNativeVersions).distinct positionedDep diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala index 9b3a5ac7be..0c15e21f46 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaNativeTestDefinitions.scala @@ -323,8 +323,20 @@ trait RunScalaNativeTestDefinitions { _: RunTestDefinitions => |""".stripMargin ).fromRoot { root => val result = os.proc(TestUtil.cli, "run", "toolkit.scala", cmdLineOpts, extraOptions) - .call(cwd = root) + .call(cwd = root, stderr = os.Pipe) expect(result.out.trim() == expectedMessage) + if (Constants.scalaNativeVersion != Constants.typelevelToolkitMaxScalaNative) { + val err = result.err.trim() + expect( + err.contains( + s"Scala Native default version ${Constants.scalaNativeVersion} is not supported in this build" + ) + ) + expect(err.contains(s"Using ${Constants.typelevelToolkitMaxScalaNative} instead.")) + expect(err.contains( + s"TypeLevel Toolkit does not support Scala Native ${Constants.scalaNativeVersion}" + )) + } } } @@ -347,8 +359,20 @@ trait RunScalaNativeTestDefinitions { _: RunTestDefinitions => |""".stripMargin ).fromRoot { root => val result = os.proc(TestUtil.cli, "run", "toolkit.scala", cmdLineOpts, extraOptions) - .call(cwd = root) + .call(cwd = root, stderr = os.Pipe) expect(result.out.trim() == root.toString) + if (Constants.scalaNativeVersion != Constants.toolkiMaxScalaNative) { + val err = result.err.trim() + expect( + err.contains( + s"Scala Native default version ${Constants.scalaNativeVersion} is not supported in this build" + ) + ) + expect(err.contains(s"Using ${Constants.toolkiMaxScalaNative} instead.")) + expect(err.contains( + s"Scala Toolkit does not support Scala Native ${Constants.scalaNativeVersion}" + )) + } } } } diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala index 7dc6049bc5..75e825e0a9 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScalaPyTestDefinitions.scala @@ -70,9 +70,8 @@ trait RunScalaPyTestDefinitions { _: RunTestDefinitions => inputs.fromRoot { root => val res = - os.proc(TestUtil.cli, "--power", "run", extraOptions, ".", maybeCliArg).call( - cwd = root - ) + os.proc(TestUtil.cli, "--power", "run", extraOptions, ".", maybeCliArg) + .call(cwd = root, stderr = os.Pipe) val output = res.out.trim() .linesIterator .filter { l => @@ -82,6 +81,18 @@ trait RunScalaPyTestDefinitions { _: RunTestDefinitions => .mkString(System.lineSeparator()) val expectedOutput = "Length is 3" expect(output == expectedOutput) + val err = res.err.trim() + if (Constants.scalaNativeVersion != Constants.scalaPyMaxScalaNative) { + expect( + err.contains( + s"Scala Native default version ${Constants.scalaNativeVersion} is not supported in this build" + ) + ) + expect(err.contains(s"Using ${Constants.scalaPyMaxScalaNative} instead.")) + expect( + err.contains(s"ScalaPy does not support Scala Native ${Constants.scalaNativeVersion}") + ) + } } } diff --git a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala index cb3c4eb222..09b6abda31 100644 --- a/modules/options/src/main/scala/scala/build/options/BuildOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/BuildOptions.scala @@ -418,7 +418,19 @@ final case class BuildOptions( Some(notForBloopOptions.scalaJsLinkerOptions.finalScalaJsCliVersion) else None, scalaNativeCliVersion = - if (platform.value == Platform.Native) Some(scalaNativeOptions.finalVersion) else None, + if (platform.value == Platform.Native) { + val scalaNativeFinalVersion = scalaNativeOptions.finalVersion + if scalaNativeOptions.version.isEmpty && scalaNativeFinalVersion != Constants.scalaNativeVersion + then + scalaNativeOptions.maxDefaultNativeVersions.map(_._2).distinct + .map(reason => s"[${Console.YELLOW}warn${Console.RESET}] $reason") + .foreach(reason => logger.message(reason)) + logger.message( + s"[${Console.YELLOW}warn${Console.RESET}] Scala Native default version ${Constants.scalaNativeVersion} is not supported in this build. Using $scalaNativeFinalVersion instead." + ) + Some(scalaNativeFinalVersion) + } + else None, addScalapy = if (notForBloopOptions.doSetupPython.getOrElse(false)) Some(notForBloopOptions.scalaPyVersion.getOrElse(Constants.scalaPyVersion)) diff --git a/modules/options/src/main/scala/scala/build/options/HasHashData.scala b/modules/options/src/main/scala/scala/build/options/HasHashData.scala index 9ee6d396d4..a8d2852231 100644 --- a/modules/options/src/main/scala/scala/build/options/HasHashData.scala +++ b/modules/options/src/main/scala/scala/build/options/HasHashData.scala @@ -46,6 +46,12 @@ object HasHashData: ): HasHashData[List[T]] = // shouldn't we hash index here? (name, list, update) => list.foreach(t => update(s"$name+=${hasher.hashedValue(t)}")) + given listOfTuple[T](using + hasher: HashedType[T] + ): HasHashData[List[(T, T)]] = + (name, list, update) => + list.foreach((t1, t2) => update(s"$name+=${hasher.hashedValue(t1) + hasher.hashedValue(t2)}")) + given option[T](using hasher: HashedType[T]): HasHashData[Option[T]] = (name, opt, update) => opt.foreach(t => update(s"$name=${hasher.hashedValue(t)}")) diff --git a/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala b/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala index 5552b9bc20..0ca8d2479c 100644 --- a/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala @@ -40,11 +40,12 @@ final case class ScalaNativeOptions( compileDefaults: Option[Boolean] = None, embedResources: Option[Boolean] = None, buildTargetStr: Option[String] = None, - maxDefaultNativeVersions: List[String] = Nil + maxDefaultNativeVersions: List[(String, String)] = Nil ) { def defaultMaxVersion: Option[String] = maxDefaultNativeVersions + .map(_._1) .map(v => v -> SNNumeralVersion.parse(v)) .minByOption(_._2) .map(_._1)