From baeb22cf55c902ab1de353a2241877b8972439c4 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Fri, 9 Jun 2023 08:30:09 +0100 Subject: [PATCH 01/10] Support nativeTarget to build Scala Native static/shared libraries --- .../scala/cli/commands/package0/Package.scala | 154 ++++++++++++++---- .../scala/scala/cli/commands/run/Run.scala | 9 +- .../commands/shared/ScalaNativeOptions.scala | 5 + .../cli/commands/shared/SharedOptions.scala | 3 +- .../directives/ScalaNative.scala | 9 +- .../integration/PackageTestDefinitions.scala | 44 ++++- .../scala/build/options/PackageType.scala | 34 ++-- .../build/options/ScalaNativeOptions.scala | 37 ++++- 8 files changed, 242 insertions(+), 53 deletions(-) diff --git a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala index 0bf9e3af37..5e095795fa 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala @@ -43,6 +43,10 @@ import scala.cli.packaging.{Library, NativeImage} import scala.cli.util.ArgHelpers.* import scala.cli.util.ConfigDbUtils import scala.util.Properties +import scala.build.options.ScalaNativeOptions +import scala.build.options.ScalaNativeTarget +import scala.deriving.Mirror +import scala.build.options.PackageType.Native object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { override def name = "package" @@ -85,6 +89,19 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { configDb.get(Keys.actions).getOrElse(None) ) + def detectNativePackageType( + platform: Platform, + sn: ScalaNativeOptions + ): Option[Native & scala.deriving.Mirror.Singleton] = + Option.when(platform == Platform.Native) { + import ScalaNativeTarget.* + sn.buildTargetStr.flatMap(fromString).map { + case Application => PackageType.Native.Application + case LibraryDynamic => PackageType.Native.LibraryDynamic + case LibraryStatic => PackageType.Native.LibraryStatic + } + }.flatten + if (options.watch.watchMode) { var expectedModifyEpochSecondOpt = Option.empty[Long] val watcher = Build.watch( @@ -101,12 +118,15 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { ) { res => res.orReport(logger).map(_.main).foreach { case s: Build.Successful => - s.copyOutput(options.shared) val mtimeDestPath = doPackage( logger = logger, outputOpt = options.output.filter(_.nonEmpty), force = options.force, - forcedPackageTypeOpt = options.forcedPackageTypeOpt, + forcedPackageTypeOpt = + options.forcedPackageTypeOpt orElse detectNativePackageType( + s.options.platform.value, + s.options.scalaNativeOptions + ), build = s, extraArgs = args.unparsed, expectedModifyEpochSecondOpt = expectedModifyEpochSecondOpt, @@ -146,7 +166,11 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { logger = logger, outputOpt = options.output.filter(_.nonEmpty), force = options.force, - forcedPackageTypeOpt = options.forcedPackageTypeOpt, + forcedPackageTypeOpt = + options.forcedPackageTypeOpt orElse detectNativePackageType( + s.options.platform.value, + s.options.scalaNativeOptions + ), build = s, extraArgs = args.unparsed, expectedModifyEpochSecondOpt = None, @@ -199,7 +223,14 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { lazy val validPackageScalaJS = Seq(PackageType.LibraryJar, PackageType.SourceJar, PackageType.DocJar) lazy val validPackageScalaNative = - Seq(PackageType.LibraryJar, PackageType.SourceJar, PackageType.DocJar) + Seq( + PackageType.LibraryJar, + PackageType.SourceJar, + PackageType.DocJar, + PackageType.Native.Application, + PackageType.Native.LibraryDynamic, + PackageType.Native.LibraryStatic + ) forcedPackageTypeOpt -> build.options.platform.value match { case (Some(forcedPackageType), _) => Right(forcedPackageType) @@ -226,7 +257,8 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { else Left(new MalformedCliInputError( s"Unsupported package type: $basePackageType for Scala Native." )) - validatedPackageType.getOrElse(Right(PackageType.Native)) + + validatedPackageType.getOrElse(Right(PackageType.Native.Application)) case _ => Right(basePackageTypeOpt.getOrElse(PackageType.Bootstrap)) } } @@ -234,36 +266,54 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { // TODO When possible, call alreadyExistsCheck() before compiling stuff def extension = packageType match { - case PackageType.LibraryJar => ".jar" - case PackageType.SourceJar => ".jar" - case PackageType.DocJar => ".jar" - case _: PackageType.Assembly => ".jar" - case PackageType.Spark => ".jar" - case PackageType.Js => ".js" - case PackageType.Debian => ".deb" - case PackageType.Dmg => ".dmg" - case PackageType.Pkg => ".pkg" - case PackageType.Rpm => ".rpm" - case PackageType.Msi => ".msi" - case PackageType.Native if Properties.isWin => ".exe" + case PackageType.LibraryJar => ".jar" + case PackageType.SourceJar => ".jar" + case PackageType.DocJar => ".jar" + case _: PackageType.Assembly => ".jar" + case PackageType.Spark => ".jar" + case PackageType.Js => ".js" + case PackageType.Debian => ".deb" + case PackageType.Dmg => ".dmg" + case PackageType.Pkg => ".pkg" + case PackageType.Rpm => ".rpm" + case PackageType.Msi => ".msi" + + case PackageType.Native.Application => + if Properties.isWin then ".exe" else "" + case PackageType.Native.LibraryDynamic => + if Properties.isWin then ".dll" else if Properties.isMac then ".dylib" else ".so" + case PackageType.Native.LibraryStatic => + if Properties.isWin then ".lib" else ".a" + case PackageType.GraalVMNativeImage if Properties.isWin => ".exe" case _ if Properties.isWin => ".bat" case _ => "" } def defaultName = packageType match { - case PackageType.LibraryJar => "library.jar" - case PackageType.SourceJar => "source.jar" - case PackageType.DocJar => "scaladoc.jar" - case _: PackageType.Assembly => "app.jar" - case PackageType.Spark => "job.jar" - case PackageType.Js => "app.js" - case PackageType.Debian => "app.deb" - case PackageType.Dmg => "app.dmg" - case PackageType.Pkg => "app.pkg" - case PackageType.Rpm => "app.rpm" - case PackageType.Msi => "app.msi" - case PackageType.Native if Properties.isWin => "app.exe" + case PackageType.LibraryJar => "library.jar" + case PackageType.SourceJar => "source.jar" + case PackageType.DocJar => "scaladoc.jar" + case _: PackageType.Assembly => "app.jar" + case PackageType.Spark => "job.jar" + case PackageType.Js => "app.js" + case PackageType.Debian => "app.deb" + case PackageType.Dmg => "app.dmg" + case PackageType.Pkg => "app.pkg" + case PackageType.Rpm => "app.rpm" + case PackageType.Msi => "app.msi" + + case PackageType.Native.Application => + if Properties.isWin then "app.exe" else "app" + + case PackageType.Native.LibraryDynamic => + if Properties.isWin then "library.dll" + else if Properties.isMac then "library.dylib" + else "library.so" + + case PackageType.Native.LibraryStatic => + if Properties.isWin then "library.lib" else "library.a" + case PackageType.GraalVMNativeImage if Properties.isWin => "app.exe" case _ if Properties.isWin => "app.bat" case _ => "app" @@ -399,8 +449,20 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { case PackageType.Js => value(buildJs(build, destPath, mainClassOpt, logger)) - case PackageType.Native => - val cachedDest = value(buildNative(build, value(mainClass), logger)) + case tpe: PackageType.Native => + import PackageType.Native.* + val mainClassO = + tpe match + case Application => Some(value(mainClass)) + case _ => None + + val cachedDest = value(buildNative( + build = build, + mainClass = mainClassO, + targetType = tpe, + destPath = Some(destPath), + logger = logger + )) if (force) os.copy.over(cachedDest, destPath, createFolders = true) else os.copy(cachedDest, destPath, createFolders = true) destPath @@ -667,7 +729,14 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { case Platform.JVM => value(bootstrap(build, appPath, mainClass, () => Right(()), logger)) case Platform.JS => buildJs(build, appPath, Some(mainClass), logger) case Platform.Native => - val dest = value(buildNative(build, mainClass, logger)) + val dest = + value(buildNative( + build = build, + mainClass = Some(mainClass), + targetType = PackageType.Native.Application, + destPath = None, + logger = logger + )) os.copy(dest, appPath) } @@ -995,7 +1064,9 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { def buildNative( build: Build.Successful, - mainClass: String, + mainClass: Option[String], // when building a static/dynamic library, we don't need a main class + targetType: PackageType.Native, + destPath: Option[os.Path], logger: Logger ): Either[BuildException, os.Path] = either { val dest = build.inputs.nativeWorkDir / s"main${if (Properties.isWin) ".exe" else ""}" @@ -1016,9 +1087,24 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { Nil val pythonCliOptions = pythonLdFlags.flatMap(f => Seq("--linking-option", f)).toList + val libraryLinkingOptions: Seq[String] = + Option.when(targetType != PackageType.Native.Application) { + /* If we are building a library, we make sure to change the name + that the linker will put into the loading path - otherwise + the built library will depend on some internal path within .scala-build + */ + + destPath.flatMap(_.lastOpt).toSeq.flatMap { filename => + Seq("--linking-option", s"-Wl,-install_name,$filename") + } + }.toSeq.flatten + + import PackageType.Native.* + val allCliOptions = pythonCliOptions ++ cliOptions ++ - Seq("--main", mainClass) + libraryLinkingOptions ++ + mainClass.toSeq.flatMap(m => Seq("--main", m)) val nativeWorkDir = build.inputs.nativeWorkDir os.makeDir.all(nativeWorkDir) diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index bf0358d5a6..2f73d21e95 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -31,6 +31,7 @@ import scala.cli.packaging.Library.fullClassPathMaybeAsJar import scala.cli.util.ArgHelpers.* import scala.cli.util.ConfigDbUtils import scala.util.{Properties, Try} +import scala.build.options.PackageType object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { override def group: String = HelpCommandGroup.Main.toString @@ -663,7 +664,13 @@ object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { mainClass: String, logger: Logger )(f: os.Path => T): Either[BuildException, T] = - Package.buildNative(build, mainClass, logger).map(f) + Package.buildNative( + build = build, + mainClass = Some(mainClass), + targetType = PackageType.Native.Application, + destPath = None, + logger = logger + ).map(f) final class PythonDetectionError(cause: Throwable) extends BuildException( s"Error detecting Python environment: ${cause.getMessage}", diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala index 871f49c4aa..18e53e8d90 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala @@ -61,6 +61,11 @@ final case class ScalaNativeOptions( @Tag(tags.implementation) nativeCompileDefaults: Option[Boolean] = None, //TODO does it even work when we default it to true while handling? + @Group(HelpGroup.ScalaNative.toString) + @HelpMessage("Build target type") + @Tag(tags.should) + nativeTarget: Option[String] = None, + @Group(HelpGroup.ScalaNative.toString) @HelpMessage("Embed resources into the Scala Native binary (can be read with the Java resources API)") @Tag(tags.should) 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 395e82d567..e55394a5e7 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 @@ -266,7 +266,8 @@ final case class SharedOptions( nativeLinking, nativeLinkingDefaults, nativeCompile, - nativeCompileDefaults + nativeCompileDefaults, + embedResources ) } diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala index 47ada42944..e86a8ae9c8 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala @@ -26,7 +26,8 @@ import scala.cli.commands.SpecificationLevel | |`//> using nativeClangPP` _value_ | - |`//> using nativeEmbedResources` _true|false_""".stripMargin + |`//> using nativeEmbedResources` _true|false_ + """.stripMargin.trim ) @DirectiveDescription("Add Scala Native options") @DirectiveLevel(SpecificationLevel.SHOULD) @@ -41,7 +42,8 @@ final case class ScalaNative( nativeClang: Option[String] = None, @DirectiveName("nativeClangPp") nativeClangPP: Option[String] = None, - nativeEmbedResources: Option[Boolean] = None + nativeEmbedResources: Option[Boolean] = None, + nativeTarget: Option[String] = None, ) extends HasBuildOptions { // format: on def buildOptions: Either[BuildException, BuildOptions] = { @@ -54,7 +56,8 @@ final case class ScalaNative( linkingOptions = nativeLinking, clang = nativeClang, clangpp = nativeClangPP, - embedResources = nativeEmbedResources + embedResources = nativeEmbedResources, + buildTargetStr = nativeTarget ) val buildOpt = BuildOptions(scalaNativeOptions = nativeOptions) Right(buildOpt) diff --git a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala index b089205487..be690f7e0a 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala @@ -469,10 +469,52 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) } } - if (!Properties.isWin && actualScalaVersion.startsWith("2.13")) + def libraryNativeTest(shared: Boolean = false): Unit = { + val fileName = "simple.sc" + val nativeTarget = if (shared) "dynamic" else "static" + val inputs = TestInputs( + os.rel / fileName -> + s""" + |//> using platform scala-native + |//> using nativeTarget $nativeTarget + |import scala.scalanative.unsafe._ + |object myLib{ + | @exported + | def addLongs(l: Long, r: Long): Long = l + r + | @exported("mylib_addInts") + | def addInts(l: Int, r: Int): Int = l + r + |}""".stripMargin + ) + val destName = { + val ext = + if (!shared) + if (Properties.isWin) ".lib" else ".a" + else if (Properties.isWin) ".dll" + else if (Properties.isMac) ".dylib" + else ".so" + fileName.stripSuffix(".sc") + ext + } + + inputs.fromRoot { root => + os.proc(TestUtil.cli, "--power", "package", extraOptions, fileName).call( + cwd = root, + stdin = os.Inherit, + stdout = os.Inherit + ) + + val library = root / destName + expect(os.isFile(library)) + } + } + + if (!Properties.isWin && actualScalaVersion.startsWith("2.13")) { test("simple native") { simpleNativeTest() } + test("dynamic and static library native") { + libraryNativeTest() + } + } test("assembly") { val fileName = "simple.sc" diff --git a/modules/options/src/main/scala/scala/build/options/PackageType.scala b/modules/options/src/main/scala/scala/build/options/PackageType.scala index 288ab5ea79..4733696fed 100644 --- a/modules/options/src/main/scala/scala/build/options/PackageType.scala +++ b/modules/options/src/main/scala/scala/build/options/PackageType.scala @@ -25,9 +25,18 @@ object PackageType { case object Spark extends PackageType { override def runnable = Some(false) } - case object Js extends PackageType - case object Native extends PackageType { - override def runnable = Some(true) + case object Js extends PackageType + sealed trait Native extends PackageType + object Native { + case object Application extends Native { + override def runnable = Some(true) + } + case object LibraryDynamic extends Native { + override def runnable = Some(false) + } + case object LibraryStatic extends Native { + override def runnable = Some(false) + } } case object Docker extends PackageType { override def runnable = None @@ -50,14 +59,17 @@ object PackageType { "doc" -> DocJar, "spark" -> Spark, "js" -> Js, - "native" -> Native, - "docker" -> Docker, - "graalvm" -> GraalVMNativeImage, - "deb" -> Debian, - "dmg" -> Dmg, - "pkg" -> Pkg, - "rpm" -> Rpm, - "msi" -> Msi + // TODO: handle more types here? + "native" -> Native.Application, + "native-dynamic" -> Native.LibraryDynamic, + "native-static" -> Native.LibraryStatic, + "docker" -> Docker, + "graalvm" -> GraalVMNativeImage, + "deb" -> Debian, + "dmg" -> Dmg, + "pkg" -> Pkg, + "rpm" -> Rpm, + "msi" -> Msi ) private lazy val map = mapping.toMap def parse(input: String): Option[PackageType] = 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 415a9650a5..ae7db00b7b 100644 --- a/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala +++ b/modules/options/src/main/scala/scala/build/options/ScalaNativeOptions.scala @@ -9,6 +9,24 @@ import scala.build.internal.Constants import scala.scalanative.build.LTO import scala.scalanative.{build => sn} +enum ScalaNativeTarget: + case Application, LibraryDynamic, LibraryStatic + + def toBuildTarget: sn.BuildTarget = + this match + case Application => sn.BuildTarget.application + case LibraryDynamic => sn.BuildTarget.libraryDynamic + case libraryStatic => sn.BuildTarget.libraryStatic + +object ScalaNativeTarget: + import ScalaNativeTarget.* + def fromString(str: String): Option[ScalaNativeTarget] = + str match + case "application" | "app" => Some(Application) + case "library-dynamic" | "dynamic" | "shared" => Some(LibraryDynamic) + case "library-static" | "static" => Some(LibraryStatic) + case _ => None + final case class ScalaNativeOptions( version: Option[String] = None, modeStr: Option[String] = None, @@ -20,13 +38,27 @@ final case class ScalaNativeOptions( linkingDefaults: Option[Boolean] = None, compileOptions: List[String] = Nil, compileDefaults: Option[Boolean] = None, - embedResources: Option[Boolean] = None + embedResources: Option[Boolean] = None, + buildTargetStr: Option[String] = None ) { def finalVersion = version.map(_.trim).filter(_.nonEmpty).getOrElse(Constants.scalaNativeVersion) def numeralVersion = SNNumeralVersion.parse(finalVersion) + def target(): Option[ScalaNativeTarget] = + buildTargetStr.flatMap(ScalaNativeTarget.fromString) + + private def targetCliOption(): List[String] = + import ScalaNativeTarget.* + val targ = target().map { + case Application => "application" + case LibraryDynamic => "library-dynamic" + case LibraryStatic => "library-static" + } + + targ.toList.flatMap(opt => List("--build-target", opt)) + private def gc(): sn.GC = gcStr.map(_.trim).filter(_.nonEmpty) match { case Some("default") | None => sn.Discover.GC() @@ -123,7 +155,8 @@ final case class ScalaNativeOptions( clangppCliOption() ++ linkingCliOptions() ++ compileCliOptions() ++ - resourcesCliOptions(resourcesExist) + resourcesCliOptions(resourcesExist) ++ + targetCliOption() } From 474ee14cd099ca05c822ff3faf3e9a6456bbcac1 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Tue, 13 Jun 2023 19:38:51 +0100 Subject: [PATCH 02/10] Address PR comments --- .../scala/cli/commands/package0/Package.scala | 54 +++++++------------ .../scala/scala/cli/commands/run/Run.scala | 3 +- .../integration/PackageTestDefinitions.scala | 12 ++++- .../scala/build/options/PackageType.scala | 19 +++---- website/docs/reference/cli-options.md | 4 ++ .../reference/scala-command/cli-options.md | 6 +++ .../scala-command/runner-specification.md | 36 +++++++++++++ 7 files changed, 85 insertions(+), 49 deletions(-) diff --git a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala index 5e095795fa..48045b8294 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala @@ -26,7 +26,8 @@ import scala.build.interactive.InteractiveFileOps import scala.build.internal.Util.* import scala.build.internal.resource.NativeResourceMapper import scala.build.internal.{Runner, ScalaJsLinkerConfig} -import scala.build.options.{BuildOptions, JavaOpt, PackageType, Platform} +import scala.build.options.PackageType.Native +import scala.build.options.{BuildOptions, JavaOpt, PackageType, Platform, ScalaNativeTarget} import scala.cli.CurrentParams import scala.cli.commands.OptionsHelper.* import scala.cli.commands.doc.Doc @@ -43,10 +44,6 @@ import scala.cli.packaging.{Library, NativeImage} import scala.cli.util.ArgHelpers.* import scala.cli.util.ConfigDbUtils import scala.util.Properties -import scala.build.options.ScalaNativeOptions -import scala.build.options.ScalaNativeTarget -import scala.deriving.Mirror -import scala.build.options.PackageType.Native object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { override def name = "package" @@ -89,19 +86,6 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { configDb.get(Keys.actions).getOrElse(None) ) - def detectNativePackageType( - platform: Platform, - sn: ScalaNativeOptions - ): Option[Native & scala.deriving.Mirror.Singleton] = - Option.when(platform == Platform.Native) { - import ScalaNativeTarget.* - sn.buildTargetStr.flatMap(fromString).map { - case Application => PackageType.Native.Application - case LibraryDynamic => PackageType.Native.LibraryDynamic - case LibraryStatic => PackageType.Native.LibraryStatic - } - }.flatten - if (options.watch.watchMode) { var expectedModifyEpochSecondOpt = Option.empty[Long] val watcher = Build.watch( @@ -118,15 +102,12 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { ) { res => res.orReport(logger).map(_.main).foreach { case s: Build.Successful => + s.copyOutput(options.shared) val mtimeDestPath = doPackage( logger = logger, outputOpt = options.output.filter(_.nonEmpty), force = options.force, - forcedPackageTypeOpt = - options.forcedPackageTypeOpt orElse detectNativePackageType( - s.options.platform.value, - s.options.scalaNativeOptions - ), + forcedPackageTypeOpt = options.forcedPackageTypeOpt, build = s, extraArgs = args.unparsed, expectedModifyEpochSecondOpt = expectedModifyEpochSecondOpt, @@ -166,11 +147,7 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { logger = logger, outputOpt = options.output.filter(_.nonEmpty), force = options.force, - forcedPackageTypeOpt = - options.forcedPackageTypeOpt orElse detectNativePackageType( - s.options.platform.value, - s.options.scalaNativeOptions - ), + forcedPackageTypeOpt = options.forcedPackageTypeOpt, build = s, extraArgs = args.unparsed, expectedModifyEpochSecondOpt = None, @@ -250,13 +227,22 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { )) validatedPackageType.getOrElse(Right(PackageType.Js)) case (_, Platform.Native) => + val specificNativePackageType = + import ScalaNativeTarget.* + build.options.scalaNativeOptions.buildTargetStr.flatMap(fromString).map { + case Application => PackageType.Native.Application + case LibraryDynamic => PackageType.Native.LibraryDynamic + case LibraryStatic => PackageType.Native.LibraryStatic + } + val validatedPackageType = - for (basePackageType <- basePackageTypeOpt) - yield - if (validPackageScalaNative.contains(basePackageType)) Right(basePackageType) - else Left(new MalformedCliInputError( - s"Unsupported package type: $basePackageType for Scala Native." - )) + for + basePackageType <- specificNativePackageType orElse basePackageTypeOpt + yield + if (validPackageScalaNative.contains(basePackageType)) Right(basePackageType) + else Left(new MalformedCliInputError( + s"Unsupported package type: $basePackageType for Scala Native." + )) validatedPackageType.getOrElse(Right(PackageType.Native.Application)) case _ => Right(basePackageTypeOpt.getOrElse(PackageType.Bootstrap)) diff --git a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala index 2f73d21e95..a1b28e3908 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/run/Run.scala @@ -15,7 +15,7 @@ import scala.build.errors.BuildException import scala.build.input.{Inputs, ScalaCliInvokeData, SubCommand} import scala.build.internal.util.ConsoleUtils.ScalaCliConsole import scala.build.internal.{Constants, Runner, ScalaJsLinkerConfig} -import scala.build.options.{BuildOptions, JavaOpt, Platform, ScalacOpt} +import scala.build.options.{BuildOptions, JavaOpt, PackageType, Platform, ScalacOpt} import scala.cli.CurrentParams import scala.cli.commands.package0.Package import scala.cli.commands.publish.ConfigUtil.* @@ -31,7 +31,6 @@ import scala.cli.packaging.Library.fullClassPathMaybeAsJar import scala.cli.util.ArgHelpers.* import scala.cli.util.ConfigDbUtils import scala.util.{Properties, Try} -import scala.build.options.PackageType object Run extends ScalaCommand[RunOptions] with BuildCommandHelpers { override def group: String = HelpCommandGroup.Main.toString diff --git a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala index be690f7e0a..7890555265 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala @@ -511,9 +511,17 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) test("simple native") { simpleNativeTest() } - test("dynamic and static library native") { - libraryNativeTest() + test("dynamic library native") { + libraryNativeTest(shared = true) } + + // To produce a static library, `LLVM_BIN` environment variable needs to be + // present (for `llvm-ar` utility) + if (sys.env.contains("LLVM_BIN")) + test("shared library native") { + libraryNativeTest(shared = false) + } + } test("assembly") { diff --git a/modules/options/src/main/scala/scala/build/options/PackageType.scala b/modules/options/src/main/scala/scala/build/options/PackageType.scala index 4733696fed..126c777d7b 100644 --- a/modules/options/src/main/scala/scala/build/options/PackageType.scala +++ b/modules/options/src/main/scala/scala/build/options/PackageType.scala @@ -59,17 +59,14 @@ object PackageType { "doc" -> DocJar, "spark" -> Spark, "js" -> Js, - // TODO: handle more types here? - "native" -> Native.Application, - "native-dynamic" -> Native.LibraryDynamic, - "native-static" -> Native.LibraryStatic, - "docker" -> Docker, - "graalvm" -> GraalVMNativeImage, - "deb" -> Debian, - "dmg" -> Dmg, - "pkg" -> Pkg, - "rpm" -> Rpm, - "msi" -> Msi + "native" -> Native.Application, + "docker" -> Docker, + "graalvm" -> GraalVMNativeImage, + "deb" -> Debian, + "dmg" -> Dmg, + "pkg" -> Pkg, + "rpm" -> Rpm, + "msi" -> Msi ) private lazy val map = mapping.toMap def parse(input: String): Option[PackageType] = diff --git a/website/docs/reference/cli-options.md b/website/docs/reference/cli-options.md index 4371e51f88..34eae82372 100644 --- a/website/docs/reference/cli-options.md +++ b/website/docs/reference/cli-options.md @@ -1337,6 +1337,10 @@ List of compile options [Internal] Use default compile options +### `--native-target` + +Build target type + ### `--embed-resources` Embed resources into the Scala Native binary (can be read with the Java resources API) diff --git a/website/docs/reference/scala-command/cli-options.md b/website/docs/reference/scala-command/cli-options.md index 7f34a860d7..5493cbc18c 100644 --- a/website/docs/reference/scala-command/cli-options.md +++ b/website/docs/reference/scala-command/cli-options.md @@ -852,6 +852,12 @@ List of compile options Use default compile options +### `--native-target` + +`SHOULD have` per Scala Runner specification + +Build target type + ### `--embed-resources` `SHOULD have` per Scala Runner specification diff --git a/website/docs/reference/scala-command/runner-specification.md b/website/docs/reference/scala-command/runner-specification.md index 6334e0cbf4..b3bb25d19e 100644 --- a/website/docs/reference/scala-command/runner-specification.md +++ b/website/docs/reference/scala-command/runner-specification.md @@ -180,6 +180,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -896,6 +900,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -1429,6 +1437,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -1988,6 +2000,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -2566,6 +2582,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -3120,6 +3140,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -3711,6 +3735,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -4347,6 +4375,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) @@ -5196,6 +5228,10 @@ Extra options passed to `clang` verbatim during linking List of compile options +**--native-target** + +Build target type + **--embed-resources** Embed resources into the Scala Native binary (can be read with the Java resources API) From 00619ab1840900695e12b2a2fff9813f929d5581 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Tue, 13 Jun 2023 19:46:16 +0100 Subject: [PATCH 03/10] Update directives docs --- .../scala/build/preprocessing/directives/ScalaNative.scala | 2 ++ website/docs/reference/directives.md | 2 ++ website/docs/reference/scala-command/directives.md | 2 ++ 3 files changed, 6 insertions(+) diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala index e86a8ae9c8..5422f3b90a 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala @@ -27,6 +27,8 @@ import scala.cli.commands.SpecificationLevel |`//> using nativeClangPP` _value_ | |`//> using nativeEmbedResources` _true|false_ + | + |`//> using nativeTarget` _application|library-dynamic|library-static_ """.stripMargin.trim ) @DirectiveDescription("Add Scala Native options") diff --git a/website/docs/reference/directives.md b/website/docs/reference/directives.md index 8167a87348..00097adeaf 100644 --- a/website/docs/reference/directives.md +++ b/website/docs/reference/directives.md @@ -300,6 +300,8 @@ Add Scala Native options `//> using nativeEmbedResources` _true|false_ +`//> using nativeTarget` _application|library-dynamic|library-static_ + #### Examples `//> using nativeVersion 0.4.0` diff --git a/website/docs/reference/scala-command/directives.md b/website/docs/reference/scala-command/directives.md index 80a6d0c1a0..a8dd7b7fc1 100644 --- a/website/docs/reference/scala-command/directives.md +++ b/website/docs/reference/scala-command/directives.md @@ -236,6 +236,8 @@ Add Scala Native options `//> using nativeEmbedResources` _true|false_ +`//> using nativeTarget` _application|library-dynamic|library-static_ + #### Examples `//> using nativeVersion 0.4.0` From 9977f72f208d9c8fb29a5f6dc9d6b9c4eb69a296 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Tue, 13 Jun 2023 19:48:21 +0100 Subject: [PATCH 04/10] formatting --- .../scala/scala/cli/integration/PackageTestDefinitions.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala index 7890555265..c27e9c1759 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala @@ -514,8 +514,8 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) test("dynamic library native") { libraryNativeTest(shared = true) } - - // To produce a static library, `LLVM_BIN` environment variable needs to be + + // To produce a static library, `LLVM_BIN` environment variable needs to be // present (for `llvm-ar` utility) if (sys.env.contains("LLVM_BIN")) test("shared library native") { From 844be51947363916fe500a1858b33fc0b3a8a28d Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Thu, 5 Oct 2023 11:27:18 +0100 Subject: [PATCH 05/10] Handle linux-specific linker option --- .../src/main/scala/scala/cli/commands/package0/Package.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala index 657a282a97..18e8cb51f8 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala @@ -1123,7 +1123,9 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { */ destPath.flatMap(_.lastOpt).toSeq.flatMap { filename => - Seq("--linking-option", s"-Wl,-install_name,$filename") + val linkerOption= + if Properties.isLinux then s"-Wl,-soname,$filename" else s"-Wl,-install_name,$filename" + Seq("--linking-option", linkerOption) } }.toSeq.flatten From e80ce2f32ce50f22568d4c0a6b5a8430b68e10a5 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Thu, 5 Oct 2023 12:36:08 +0100 Subject: [PATCH 06/10] Fix old test --- modules/cli/src/test/scala/cli/tests/PackageTests.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/cli/src/test/scala/cli/tests/PackageTests.scala b/modules/cli/src/test/scala/cli/tests/PackageTests.scala index 84d18f350d..9ef7c28126 100644 --- a/modules/cli/src/test/scala/cli/tests/PackageTests.scala +++ b/modules/cli/src/test/scala/cli/tests/PackageTests.scala @@ -92,7 +92,7 @@ class PackageTests extends munit.FunSuite { val build = maybeFirstBuild.orThrow.successfulOpt.get val packageType = Package.resolvePackageType(build, None).orThrow - expect(packageType == PackageType.Native) + expect(packageType == PackageType.Native.Application) } } From 3117a3ebd20e6c2a847284103566fe2087ab21c9 Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Thu, 5 Oct 2023 12:39:06 +0100 Subject: [PATCH 07/10] Remove dirty merge --- .../scala/cli/commands/package0/Package.scala | 95 ------------------- 1 file changed, 95 deletions(-) diff --git a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala index 18e8cb51f8..900975b182 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala @@ -195,102 +195,7 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { .map(_ => None) } else { -// <<<<<<< HEAD -// val packageType: PackageType = value { -// val basePackageTypeOpt = build.options.notForBloopOptions.packageOptions.packageTypeOpt -// lazy val validPackageScalaJS = -// Seq(PackageType.LibraryJar, PackageType.SourceJar, PackageType.DocJar) -// lazy val validPackageScalaNative = -// Seq( -// PackageType.LibraryJar, -// PackageType.SourceJar, -// PackageType.DocJar, -// PackageType.Native.Application, -// PackageType.Native.LibraryDynamic, -// PackageType.Native.LibraryStatic -// ) - -// forcedPackageTypeOpt -> build.options.platform.value match { -// case (Some(forcedPackageType), _) => Right(forcedPackageType) -// case (_, _) if build.options.notForBloopOptions.packageOptions.isDockerEnabled => -// for (basePackageType <- basePackageTypeOpt) -// Left(new MalformedCliInputError( -// s"Unsupported package type: $basePackageType for Docker." -// )) -// Right(PackageType.Docker) -// case (_, Platform.JS) => -// val validatedPackageType = -// for (basePackageType <- basePackageTypeOpt) -// yield -// if (validPackageScalaJS.contains(basePackageType)) Right(basePackageType) -// else Left(new MalformedCliInputError( -// s"Unsupported package type: $basePackageType for Scala.js." -// )) -// validatedPackageType.getOrElse(Right(PackageType.Js)) -// case (_, Platform.Native) => -// val specificNativePackageType = -// import ScalaNativeTarget.* -// build.options.scalaNativeOptions.buildTargetStr.flatMap(fromString).map { -// case Application => PackageType.Native.Application -// case LibraryDynamic => PackageType.Native.LibraryDynamic -// case LibraryStatic => PackageType.Native.LibraryStatic -// } - -// val validatedPackageType = -// for -// basePackageType <- specificNativePackageType orElse basePackageTypeOpt -// yield -// if (validPackageScalaNative.contains(basePackageType)) Right(basePackageType) -// else Left(new MalformedCliInputError( -// s"Unsupported package type: $basePackageType for Scala Native." -// )) - -// validatedPackageType.getOrElse(Right(PackageType.Native.Application)) -// case _ => Right(basePackageTypeOpt.getOrElse(PackageType.Bootstrap)) -// } -// } - -// ||||||| 9283e8749 -// val packageType: PackageType = value { -// val basePackageTypeOpt = build.options.notForBloopOptions.packageOptions.packageTypeOpt -// lazy val validPackageScalaJS = -// Seq(PackageType.LibraryJar, PackageType.SourceJar, PackageType.DocJar) -// lazy val validPackageScalaNative = -// Seq(PackageType.LibraryJar, PackageType.SourceJar, PackageType.DocJar) - -// forcedPackageTypeOpt -> build.options.platform.value match { -// case (Some(forcedPackageType), _) => Right(forcedPackageType) -// case (_, _) if build.options.notForBloopOptions.packageOptions.isDockerEnabled => -// for (basePackageType <- basePackageTypeOpt) -// Left(new MalformedCliInputError( -// s"Unsupported package type: $basePackageType for Docker." -// )) -// Right(PackageType.Docker) -// case (_, Platform.JS) => -// val validatedPackageType = -// for (basePackageType <- basePackageTypeOpt) -// yield -// if (validPackageScalaJS.contains(basePackageType)) Right(basePackageType) -// else Left(new MalformedCliInputError( -// s"Unsupported package type: $basePackageType for Scala.js." -// )) -// validatedPackageType.getOrElse(Right(PackageType.Js)) -// case (_, Platform.Native) => -// val validatedPackageType = -// for (basePackageType <- basePackageTypeOpt) -// yield -// if (validPackageScalaNative.contains(basePackageType)) Right(basePackageType) -// else Left(new MalformedCliInputError( -// s"Unsupported package type: $basePackageType for Scala Native." -// )) -// validatedPackageType.getOrElse(Right(PackageType.Native)) -// case _ => Right(basePackageTypeOpt.getOrElse(PackageType.Bootstrap)) -// } -// } - -// ======= val packageType: PackageType = value(resolvePackageType(build, forcedPackageTypeOpt)) -// >>>>>>> main // TODO When possible, call alreadyExistsCheck() before compiling stuff def extension = packageType match { From f9d754bf585024b1e09cc12a70ee04c1c012b8c4 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Mon, 9 Oct 2023 15:51:08 +0200 Subject: [PATCH 08/10] Fix the command line option for passing the native target & add a relevant test --- .../scala/cli/commands/package0/Package.scala | 4 +- .../cli/commands/shared/SharedOptions.scala | 3 +- .../integration/PackageTestDefinitions.scala | 23 ++++++++--- .../RunScriptTestDefinitions.scala | 38 ++++++++++--------- 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala index 900975b182..c87c0f08e1 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/package0/Package.scala @@ -1028,8 +1028,8 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers { */ destPath.flatMap(_.lastOpt).toSeq.flatMap { filename => - val linkerOption= - if Properties.isLinux then s"-Wl,-soname,$filename" else s"-Wl,-install_name,$filename" + val linkerOption = + if Properties.isLinux then s"-Wl,-soname,$filename" else s"-Wl,-install_name,$filename" Seq("--linking-option", linkerOption) } }.toSeq.flatten 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 a1b2f0fc83..45fd3dac9c 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 @@ -273,7 +273,8 @@ final case class SharedOptions( nativeLinkingDefaults, nativeCompile, nativeCompileDefaults, - embedResources + embedResources, + nativeTarget ) } diff --git a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala index c27e9c1759..0615d60ba5 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala @@ -469,14 +469,17 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) } } - def libraryNativeTest(shared: Boolean = false): Unit = { - val fileName = "simple.sc" - val nativeTarget = if (shared) "dynamic" else "static" + def libraryNativeTest( + shared: Boolean = false, + commandLineShared: Option[Boolean] = None + ): Unit = { + val fileName = "simple.sc" + val directiveNativeTarget = if (shared) "dynamic" else "static" val inputs = TestInputs( os.rel / fileName -> s""" |//> using platform scala-native - |//> using nativeTarget $nativeTarget + |//> using nativeTarget $directiveNativeTarget |import scala.scalanative.unsafe._ |object myLib{ | @exported @@ -495,8 +498,14 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) fileName.stripSuffix(".sc") + ext } + val nativeTargetOpts = commandLineShared match { + case Some(true) => Seq("--native-target", "shared") + case Some(false) => Seq("--native-target", "dynamic") + case None => Seq.empty + } + inputs.fromRoot { root => - os.proc(TestUtil.cli, "--power", "package", extraOptions, fileName).call( + os.proc(TestUtil.cli, "--power", "package", extraOptions, nativeTargetOpts, fileName).call( cwd = root, stdin = os.Inherit, stdout = os.Inherit @@ -515,6 +524,10 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) libraryNativeTest(shared = true) } + test("dynamic library native override from command line") { + libraryNativeTest(shared = false, commandLineShared = Some(false)) + } + // To produce a static library, `LLVM_BIN` environment variable needs to be // present (for `llvm-ar` utility) if (sys.env.contains("LLVM_BIN")) diff --git a/modules/integration/src/test/scala/scala/cli/integration/RunScriptTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/RunScriptTestDefinitions.scala index ceef5e05b5..87b3018f63 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/RunScriptTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/RunScriptTestDefinitions.scala @@ -522,26 +522,30 @@ trait RunScriptTestDefinitions { _: RunTestDefinitions => test("script wrappers satisfy strict compiler flags") { val inputs = TestInputs( os.rel / "strictClassWrapper.sc" -> - """//> using scala 3.3.1 - |//> using options -Werror -Wnonunit-statement -Wunused:all -Wvalue-discard - |//> using options -Yno-experimental -Ysafe-init -deprecation -feature -language:strictEquality - |//> using options -new-syntax -old-syntax -unchecked -no-indent - | - |println(strictObjectWrapper.Foo(42).x) - |""".stripMargin, - + """//> using scala 3.3.1 + |//> using options -Werror -Wnonunit-statement -Wunused:all -Wvalue-discard + |//> using options -Yno-experimental -Ysafe-init -deprecation -feature -language:strictEquality + |//> using options -new-syntax -old-syntax -unchecked -no-indent + | + |println(strictObjectWrapper.Foo(42).x) + |""".stripMargin, os.rel / "strictObjectWrapper.sc" -> - """//> using objectWrapper - |//> using scala 3.3.1 - |//> using options -Werror -Wnonunit-statement -Wunused:all -Wvalue-discard - |//> using options -Yno-experimental -Ysafe-init -deprecation -feature -language:strictEquality - |//> using options -new-syntax -old-syntax -unchecked -no-indent - | - |case class Foo(x: Int) - |""".stripMargin + """//> using objectWrapper + |//> using scala 3.3.1 + |//> using options -Werror -Wnonunit-statement -Wunused:all -Wvalue-discard + |//> using options -Yno-experimental -Ysafe-init -deprecation -feature -language:strictEquality + |//> using options -new-syntax -old-syntax -unchecked -no-indent + | + |case class Foo(x: Int) + |""".stripMargin ) inputs.fromRoot { root => - val p = os.proc(TestUtil.cli, "--power", "strictClassWrapper.sc", "strictObjectWrapper.sc").call(cwd = root) + val p = os.proc( + TestUtil.cli, + "--power", + "strictClassWrapper.sc", + "strictObjectWrapper.sc" + ).call(cwd = root) expect(p.out.trim() == "42") } } From c17c9a16df3b3b4fc7b4c42af2a8f9594f9ba716 Mon Sep 17 00:00:00 2001 From: Piotr Chabelski Date: Tue, 10 Oct 2023 09:09:34 +0200 Subject: [PATCH 09/10] Fix test --- .../scala/cli/integration/PackageTestDefinitions.scala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala index 0615d60ba5..fc60511e25 100644 --- a/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala +++ b/modules/integration/src/test/scala/scala/cli/integration/PackageTestDefinitions.scala @@ -490,7 +490,7 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) ) val destName = { val ext = - if (!shared) + if (!shared && !commandLineShared.getOrElse(false)) if (Properties.isWin) ".lib" else ".a" else if (Properties.isWin) ".dll" else if (Properties.isMac) ".dylib" @@ -499,8 +499,8 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) } val nativeTargetOpts = commandLineShared match { - case Some(true) => Seq("--native-target", "shared") - case Some(false) => Seq("--native-target", "dynamic") + case Some(true) => Seq("--native-target", "dynamic") + case Some(false) => Seq("--native-target", "static") case None => Seq.empty } @@ -525,7 +525,7 @@ abstract class PackageTestDefinitions(val scalaVersionOpt: Option[String]) } test("dynamic library native override from command line") { - libraryNativeTest(shared = false, commandLineShared = Some(false)) + libraryNativeTest(shared = false, commandLineShared = Some(true)) } // To produce a static library, `LLVM_BIN` environment variable needs to be From e85b3ba33e71592823dbc61df863f7792f7d740a Mon Sep 17 00:00:00 2001 From: Anton Sviridov Date: Wed, 11 Oct 2023 12:01:04 +0100 Subject: [PATCH 10/10] Apply suggestions from code review Co-authored-by: Maciej Gajek <61919032+MaciejG604@users.noreply.github.com> --- .../scala/scala/cli/commands/shared/ScalaNativeOptions.scala | 1 + .../scala/build/preprocessing/directives/ScalaNative.scala | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala b/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala index 18e53e8d90..52395d05ef 100644 --- a/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala +++ b/modules/cli/src/main/scala/scala/cli/commands/shared/ScalaNativeOptions.scala @@ -64,6 +64,7 @@ final case class ScalaNativeOptions( @Group(HelpGroup.ScalaNative.toString) @HelpMessage("Build target type") @Tag(tags.should) + @ValueDescription("app|static|dynamic") nativeTarget: Option[String] = None, @Group(HelpGroup.ScalaNative.toString) diff --git a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala index 6c67b01ad9..72ec0f4d7e 100644 --- a/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala +++ b/modules/directives/src/main/scala/scala/build/preprocessing/directives/ScalaNative.scala @@ -45,7 +45,7 @@ final case class ScalaNative( @DirectiveName("nativeClangPp") nativeClangPP: Option[String] = None, nativeEmbedResources: Option[Boolean] = None, - nativeTarget: Option[String] = None, + nativeTarget: Option[String] = None, ) extends HasBuildOptions { // format: on def buildOptions: Either[BuildException, BuildOptions] = {