Skip to content

Commit 2397f5a

Browse files
authored
Allow compilation on Scala 3 (#14)
* Move scala-native-p to scopt * Move scala-native-ld to scopt * Simplify ConfigConverterTest - remove redundant default calls * Remove unnecessary comments and run scalafmt * Remove no longer necessary structures * Remove patching mechanizm * Allow compilation with Scala3 To allow this, used scalatest version was updated. * Add scala 3 testing to CI and fix tests * Add missing option names * Include scalatest only for unit tests * scalafmt fix * Pack correct scalalib for used scala version * Fix scalalib resolution for Scala 3
1 parent b895b50 commit 2397f5a

File tree

15 files changed

+399
-258
lines changed

15 files changed

+399
-258
lines changed

.github/workflows/CI.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ jobs:
77
fail-fast: false
88
matrix:
99
OS: [ubuntu-18.04, windows-2019]
10-
SN: [0.4.2]
10+
scala: [2.12.15, 2.13.7, 3.1.0]
1111
steps:
1212
- uses: actions/checkout@v2
1313
- uses: olafurpg/setup-scala@v13
1414
- name: Test
1515
run: >
16-
sbt 'set cli/scalaNativeVersion := "${{matrix.SN}}"'
16+
sbt 'set cli/scalaVersion := "${{matrix.scala}}"'
1717
+cli/test
1818
+cliScriptedTests/scripted
1919
shell: bash

build.sbt

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,50 @@
11
val crossScalaVersions212 = (13 to 15).map(v => s"2.12.$v")
22
val crossScalaVersions213 = (4 to 7).map(v => s"2.13.$v")
3+
val crossScalaVersions3 = Seq("3.1.0")
34
val latestsScalaVersions =
4-
Seq(crossScalaVersions212.last, crossScalaVersions213.last)
5+
Seq(crossScalaVersions212, crossScalaVersions213, crossScalaVersions3).map(
6+
_.last
7+
)
58

69
def scalaReleasesForBinaryVersion(v: String): Seq[String] = v match {
710
case "2.12" => crossScalaVersions212
811
case "2.13" => crossScalaVersions213
12+
case "3" => crossScalaVersions3
913
case ver =>
1014
throw new IllegalArgumentException(
1115
s"Unsupported binary scala version `${ver}`"
1216
)
1317
}
1418

19+
def scalaStdlibForBinaryVersion(
20+
nativeBinVer: String,
21+
scalaBinVer: String
22+
): Seq[String] = {
23+
def depPattern(lib: String, v: String) =
24+
s"${lib}_native${nativeBinVer}_${v}"
25+
val scalalib = "scalalib"
26+
val scala3lib = "scala3lib"
27+
val commonLibs = Seq(
28+
"nativelib",
29+
"clib",
30+
"posixlib",
31+
"windowslib",
32+
"javalib",
33+
"auxlib"
34+
)
35+
scalaBinVer match {
36+
case "2.12" | "2.13" =>
37+
(commonLibs :+ scalalib).map(depPattern(_, scalaBinVer))
38+
case "3" =>
39+
(commonLibs :+ scala3lib).map(depPattern(_, scalaBinVer)) :+
40+
depPattern(scalalib, "2.13")
41+
case ver =>
42+
throw new IllegalArgumentException(
43+
s"Unsupported binary scala version `${ver}`"
44+
)
45+
}
46+
}
47+
1548
val scalaNativeVersion =
1649
settingKey[String]("Version of Scala Native for which to build to CLI")
1750

@@ -57,8 +90,8 @@ lazy val cli = project
5790
scalacOptions += "-Ywarn-unused:imports",
5891
libraryDependencies ++= Seq(
5992
"org.scala-native" %% "tools" % scalaNativeVersion.value,
60-
"com.github.alexarchambault" %% "case-app" % "2.1.0-M10",
61-
"org.scalatest" %% "scalatest" % "3.1.1" % Test
93+
"com.github.scopt" %% "scopt" % "4.0.1",
94+
"org.scalatest" %% "scalatest" % "3.2.10" % Test
6295
),
6396
buildInfoKeys := Seq[BuildInfoKey](
6497
"nativeVersion" -> scalaNativeVersion.value
@@ -108,23 +141,19 @@ lazy val cliPackSettings = Def.settings(
108141
val scalaNativeOrg = organization.value
109142
val scalaBinVer = scalaBinaryVersion.value
110143
val snVer = scalaNativeVersion.value
144+
val nativeBinVer =
145+
ScalaNativeCrossVersion.binaryVersion(snVer.stripSuffix("-SNAPSHOT"))
111146

112147
val scalaFullVers = scalaReleasesForBinaryVersion(scalaBinVer)
113148
val cliAssemblyJar = assembly.value
114149

150+
val scalaStdLibraryModuleIDs =
151+
scalaStdlibForBinaryVersion(nativeBinVer, scalaBinVer)
152+
115153
// Standard modules needed for linking of Scala Native
116-
val stdLibModuleIDs = Seq(
117-
"nativelib",
118-
"clib",
119-
"posixlib",
120-
"windowslib",
121-
"javalib",
122-
"auxlib",
123-
"scalalib"
124-
).map { lib =>
125-
val nativeBinVersion = ScalaNativeCrossVersion.binaryVersion(snVer)
126-
scalaNativeOrg % s"${lib}_native${nativeBinVersion}_${scalaBinVer}" % snVer
127-
}
154+
val stdLibModuleIDs = scalaStdLibraryModuleIDs.map(
155+
scalaNativeOrg % _ % snVer
156+
)
128157
val compilerPluginModuleIDs =
129158
scalaFullVers.map(v => scalaNativeOrg % s"nscplugin_$v" % snVer)
130159
val allModuleIDs = (stdLibModuleIDs ++ compilerPluginModuleIDs).toVector
@@ -134,7 +163,9 @@ lazy val cliPackSettings = Def.settings(
134163
val retrieveDir = s.cacheDirectory / "cli-lib-jars"
135164
val lm = {
136165
import sbt.librarymanagement.ivy._
137-
val ivyConfig = InlineIvyConfiguration().withLog(log)
166+
val ivyConfig = InlineIvyConfiguration()
167+
.withResolvers(resolvers.value.toVector)
168+
.withLog(log)
138169
IvyDependencyResolution(ivyConfig)
139170
}
140171
val dummyModuleName =
@@ -190,7 +221,7 @@ lazy val cliPackSettings = Def.settings(
190221
.replaceAllLiterally("@SCALANATIVE_VER@", snVer)
191222
.replaceAllLiterally(
192223
"@SCALANATIVE_BIN_VER@",
193-
ScalaNativeCrossVersion.binaryVersion(snVer)
224+
ScalaNativeCrossVersion.binaryVersion(snVer.stripSuffix("-SNAPSHOT"))
194225
)
195226
val dest = trgBin / scriptFile.getName
196227
IO.write(dest, processedContent)

cli/src/main/scala/scala/scalanative/cli/ScalaNativeLd.scala

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,59 @@ package scala.scalanative.cli
33
import scala.scalanative.build.Build
44
import scala.scalanative.util.Scope
55
import scala.scalanative.cli.utils.ConfigConverter
6-
import scala.scalanative.cli.utils.NativeConfigParserImplicits._
76
import scala.scalanative.cli.options.LinkerOptions
8-
import caseapp.core.app.CaseApp
9-
import caseapp.core.RemainingArgs
107
import scala.scalanative.cli.options.BuildInfo
8+
import scala.scalanative.cli.options.ConfigOptions
9+
import scala.scalanative.cli.options.NativeConfigOptions
1110

12-
object ScalaNativeLd extends CaseApp[LinkerOptions] {
11+
object ScalaNativeLd {
1312

14-
override def ignoreUnrecognized: Boolean = true
13+
def main(args: Array[String]): Unit = {
14+
val parser = new scopt.OptionParser[LinkerOptions]("scala-native-ld") {
15+
override def errorOnUnknownArgument = false
16+
head("scala-native-ld", BuildInfo.nativeVersion)
17+
arg[String]("classpath")
18+
.hidden()
19+
.optional()
20+
.unbounded()
21+
.action((x, c) => c.copy(classpath = c.classpath :+ x))
1522

16-
def run(options: LinkerOptions, args: RemainingArgs) = {
17-
if (options.misc.version) {
18-
println(BuildInfo.nativeVersion)
19-
} else if (options.config.main.isEmpty) {
23+
ConfigOptions.set(this)
24+
NativeConfigOptions.set(this)
25+
26+
note("Logger options:")
27+
opt[Unit]("verbose")
28+
.abbr("v")
29+
.optional()
30+
.unbounded()
31+
.action((x, c) => c.copy(verbose = c.verbose + 1))
32+
.text(
33+
"Increase verbosity of internal logger. Can be specified multiple times."
34+
)
35+
36+
note("Help options:")
37+
help('h', "help")
38+
.text("Print this usage text and exit.")
39+
version("version")
40+
.text("Print scala-native-cli version and exit.")
41+
}
42+
parser.parse(args, LinkerOptions()) match {
43+
case Some(config) =>
44+
runLd(config)
45+
sys.exit(0)
46+
case _ =>
47+
// arguments are of bad format, scopt will have displayed errors automatically
48+
sys.exit(1)
49+
}
50+
}
51+
52+
def runLd(options: LinkerOptions) = {
53+
if (options.config.main.isEmpty) {
2054
println("Required option not specified: --main")
21-
exit(1)
55+
sys.exit(1)
2256
} else {
23-
val (ignoredArgs, classpath) = args.all.partition(_.startsWith("-"))
57+
val (ignoredArgs, classpath) =
58+
options.classpath.partition(_.startsWith("-"))
2459
ignoredArgs.foreach { arg =>
2560
println(s"Unrecognised argument: ${arg}")
2661
}
@@ -30,7 +65,7 @@ object ScalaNativeLd extends CaseApp[LinkerOptions] {
3065
buildOptionsMaybe match {
3166
case Left(thrown) =>
3267
System.err.println(thrown.getMessage())
33-
exit(1)
68+
sys.exit(1)
3469
case Right(buildOptions) =>
3570
Scope { implicit scope =>
3671
Build.build(buildOptions.config, buildOptions.outpath)

cli/src/main/scala/scala/scalanative/cli/ScalaNativeP.scala

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package scala.scalanative.cli
22

3-
import caseapp.core.app.CaseApp
4-
import caseapp.core.RemainingArgs
53
import java.nio.file.Paths
64
import java.io.File
75
import scala.scalanative.util.Scope
@@ -16,20 +14,47 @@ import scala.scalanative.nir.Defn
1614
import scala.annotation.tailrec
1715
import java.nio.ByteBuffer
1816

19-
object ScalaNativeP extends CaseApp[PrinterOptions] {
17+
object ScalaNativeP {
2018

21-
def run(options: PrinterOptions, args: RemainingArgs): Unit = {
22-
if (options.misc.version) {
23-
println(BuildInfo.nativeVersion)
24-
exit(0)
19+
def main(args: Array[String]): Unit = {
20+
21+
val parser = new scopt.OptionParser[PrinterOptions]("scala-native-p") {
22+
override def errorOnUnknownArgument = false
23+
24+
head("scala-native-p", BuildInfo.nativeVersion)
25+
arg[String]("Class names")
26+
.hidden()
27+
.optional()
28+
.unbounded()
29+
.action((x, c) => c.copy(classNames = c.classNames :+ x))
30+
31+
note("Help options:")
32+
help('h', "help")
33+
.text("Print this usage text and exit.")
34+
version("version")
35+
.text("Print scala-native-cli version and exit.")
36+
37+
note("Other options:")
38+
PrinterOptions.set(this)
2539
}
2640

27-
if (args.all.isEmpty) {
41+
parser.parse(args, PrinterOptions()) match {
42+
case Some(config) =>
43+
runPrinter(config)
44+
sys.exit(0)
45+
case _ =>
46+
// arguments are of bad format, scopt will have displayed errors automatically
47+
sys.exit(1)
48+
}
49+
}
50+
51+
private def runPrinter(options: PrinterOptions): Unit = {
52+
if (options.classNames.isEmpty) {
2853
if (options.fromPath)
2954
System.err.println("Required NIR file not specified.")
3055
else
3156
System.err.println("Required class/object not specified.")
32-
exit(1)
57+
sys.exit(1)
3358
}
3459

3560
val (classpath, ignoredPaths) =
@@ -41,8 +66,8 @@ object ScalaNativeP extends CaseApp[PrinterOptions] {
4166
System.err.println(s"Ignoring non existing path: $path")
4267
}
4368

44-
if (options.fromPath) printFromFiles(classpath, args.all)
45-
else printFromNames(classpath, args.all)
69+
if (options.fromPath) printFromFiles(classpath, options.classNames)
70+
else printFromNames(classpath, options.classNames)
4671
}
4772

4873
private def printFromNames(
@@ -118,7 +143,7 @@ object ScalaNativeP extends CaseApp[PrinterOptions] {
118143

119144
private def fail(msg: String): Nothing = {
120145
Console.err.println(msg)
121-
exit(1)
146+
sys.exit(1)
122147
}
123148

124149
}
Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
package scala.scalanative.cli.options
22

3-
import caseapp._
3+
import scopt.OptionParser
44

55
case class ConfigOptions(
6-
@Group("Config")
7-
@HelpMessage("Required main class.")
8-
@ValueDescription("<main>")
96
main: Option[String] = None,
10-
@Group("Config")
11-
@ExtraName("o")
12-
@HelpMessage(
13-
"Path of the resulting output binary. [./scala-native-out]"
14-
)
15-
@ValueDescription("<output-path>")
167
outpath: String = "scala-native-out",
17-
@Group("Config")
18-
@HelpMessage("Scala Native working directory. [.]")
19-
@ValueDescription("<path-to-directory>")
208
workdir: String = "."
219
)
10+
11+
object ConfigOptions {
12+
def set(parser: OptionParser[LinkerOptions]) = {
13+
parser.note("Config options:")
14+
parser
15+
.opt[String]("main")
16+
.valueName("<main>")
17+
.optional()
18+
.action((x, c) => c.copy(config = c.config.copy(main = Some(x))))
19+
.text("Required main class.")
20+
parser
21+
.opt[String]('o', "outpath")
22+
.valueName("<output-path>")
23+
.optional()
24+
.action((x, c) => c.copy(config = c.config.copy(outpath = x)))
25+
.text("Path of the resulting output binary. [./scala-native-out]")
26+
parser
27+
.opt[String]("workdir")
28+
.valueName("<path-to-directory>")
29+
.optional()
30+
.action((x, c) => c.copy(config = c.config.copy(workdir = x)))
31+
.text("Scala Native working directory. [.]")
32+
}
33+
}
Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
package scala.scalanative.cli.options
22

3-
import caseapp._
4-
5-
@AppName("ScalaNativeLd")
6-
@ProgName("scala-native-ld")
7-
@ArgsName("classpath")
83
case class LinkerOptions(
9-
@Recurse
10-
config: ConfigOptions,
11-
@Recurse
12-
nativeConfig: NativeConfigOptions,
13-
@Recurse
14-
logger: LoggerOptions,
15-
@Recurse
16-
misc: MiscOptions
4+
classpath: List[String] = Nil,
5+
config: ConfigOptions = ConfigOptions(),
6+
nativeConfig: NativeConfigOptions = NativeConfigOptions(),
7+
verbose: Int = 0
178
)

cli/src/main/scala/scala/scalanative/cli/options/LoggerOptions.scala

Lines changed: 0 additions & 12 deletions
This file was deleted.

cli/src/main/scala/scala/scalanative/cli/options/MiscOptions.scala

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)