Skip to content

Commit dcb123d

Browse files
authored
Merge pull request #14073 from BarkingBad/passing-jvm-opts-to-scala
Fix passing jvm options
2 parents 472c8ff + 2d70b59 commit dcb123d

File tree

12 files changed

+112
-29
lines changed

12 files changed

+112
-29
lines changed

.github/workflows/ci.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ jobs:
111111

112112
- name: Cmd Tests
113113
run: |
114-
./project/scripts/sbt ";scala3-bootstrapped/compile; scala3-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test;sjsCompilerTests/test ;sbt-test/scripted scala2-compat/* ;configureIDE ;stdlib-bootstrapped/test:run ;stdlib-bootstrapped-tasty-tests/test; scala3-compiler-bootstrapped/scala3CompilerCoursierTest:test"
114+
./project/scripts/sbt ";dist/pack; scala3-bootstrapped/compile; scala3-bootstrapped/test;sjsSandbox/run;sjsSandbox/test;sjsJUnitTests/test;sjsCompilerTests/test ;sbt-test/scripted scala2-compat/* ;configureIDE ;stdlib-bootstrapped/test:run ;stdlib-bootstrapped-tasty-tests/test; scala3-compiler-bootstrapped/scala3CompilerCoursierTest:test"
115115
./project/scripts/bootstrapCmdTests
116116
117117
- name: MiMa

compiler/src/dotty/tools/MainGenericRunner.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ object MainGenericRunner {
157157
process(tail, newSettings.withResidualArgs(arg))
158158

159159
def main(args: Array[String]): Unit =
160-
val scalaOpts = envOrNone("SCALA_OPTS").toArray.flatMap(_.split(" "))
160+
val scalaOpts = envOrNone("SCALA_OPTS").toArray.flatMap(_.split(" ")).filter(_.nonEmpty)
161161
val allArgs = scalaOpts ++ args
162162
val settings = process(allArgs.toList, Settings())
163163
if settings.exitCode != 0 then System.exit(settings.exitCode)

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+3
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ trait AllScalaSettings extends CommonScalaSettings, PluginSettings, VerboseSetti
7373
)
7474

7575
val wikiSyntax: Setting[Boolean] = BooleanSetting("-Xwiki-syntax", "Retains the Scala2 behavior of using Wiki Syntax in Scaladoc.")
76+
77+
val jvmargs = PrefixSetting("-J<flag>", "-J", "Pass <flag> directly to the runtime system.")
78+
val defines = PrefixSetting("-Dproperty=value", "-D", "Pass -Dproperty=value directly to the runtime system.")
7679
end AllScalaSettings
7780

7881
/** Settings shared by compiler and scaladoc */

compiler/test-coursier/dotty/tools/coursier/CoursierScalaTests.scala

+18-4
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ class CoursierScalaTests:
6060
assertTrue(output.mkString("\n").endsWith("scriptPath.sc"))
6161
scriptPath()
6262

63+
def scriptEnvDashJDashD() =
64+
val scriptPath = scripts("/scripting").find(_.getName == "envtest.sc").get.absPath
65+
val args = scriptPath
66+
val output = CoursierScalaTests.csScalaCmd("-J-Dkey=World", args)
67+
assertEquals(output.mkString("\n"), "Hello World")
68+
scriptEnvDashJDashD()
69+
6370
def version() =
6471
val output = CoursierScalaTests.csScalaCmd("-version")
6572
assertTrue(output.mkString("\n").contains(sys.env("DOTTY_BOOTSTRAPPED_VERSION")))
@@ -75,6 +82,11 @@ class CoursierScalaTests:
7582
assertEquals(output.mkString("\n"), "Hello")
7683
run()
7784

85+
def runDashJDashD() =
86+
val output = CoursierScalaTests.csScalaCmd("-J-Dkey=World", "-classpath", scripts("/run").head.getParentFile.getParent, "-run", "run.envtest")
87+
assertEquals(output.mkString("\n"), "Hello World")
88+
runDashJDashD()
89+
7890
def notOnlyOptionsEqualsRun() =
7991
val output = CoursierScalaTests.csScalaCmd("-classpath", scripts("/run").head.getParentFile.getParent, "run.myfile")
8092
assertEquals(output.mkString("\n"), "Hello")
@@ -147,10 +159,12 @@ object CoursierScalaTests:
147159
csCmd("dotty.tools.dotc.Main", options*)
148160

149161
private def csCmd(entry: String, options: String*): List[String] =
150-
val newOptions = options match
151-
case Nil => options
152-
case _ => "--" +: options
153-
execCmd("./cs", (s"""launch "org.scala-lang:scala3-compiler_3:${sys.env("DOTTY_BOOTSTRAPPED_VERSION")}" --main-class "$entry" --property "scala.usejavacp=true"""" +: newOptions)*)
162+
val (jOpts, args) = options.partition(_.startsWith("-J"))
163+
val newOptions = args match
164+
case Nil => args
165+
case _ => "--" +: args
166+
val newJOpts = jOpts.map(s => s"--java-opt ${s.stripPrefix("-J")}").mkString(" ")
167+
execCmd("./cs", (s"""launch "org.scala-lang:scala3-compiler_3:${sys.env("DOTTY_BOOTSTRAPPED_VERSION")}" $newJOpts --main-class "$entry" --property "scala.usejavacp=true"""" +: newOptions)*)
154168

155169
/** Get coursier script */
156170
@BeforeClass def setup(): Unit =
+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package run
2+
3+
object envtest extends App:
4+
println("Hello " + sys.props("key"))

compiler/test-resources/scripting/classpathReport.sc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!dist/target/pack/bin/scala -classpath dist/target/pack/lib/*
1+
#!/usr/bin/env -S bin/scala -classpath 'dist/target/pack/lib/*'
22

33
import java.nio.file.Paths
44

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
def main(args: Array[String]): Unit =
2+
println("Hello " + util.Properties.propOrNull("key"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package run
2+
3+
object envtest extends App:
4+
println("Hello " + sys.props("key"))

compiler/test-resources/scripting/unglobClasspath.sc

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!bin/scala -classpath 'dist/target/pack/lib/*'
1+
#!/usr/bin/env -S bin/scala -classpath 'dist/target/pack/lib/*'
22

33
// won't compile unless the hashbang line sets classpath
44
import org.jline.terminal.Terminal

compiler/test/dotty/tools/scripting/BashScriptsTests.scala

+49-17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import java.nio.file.{Path, Paths, Files}
77
import scala.sys.process._
88

99
import org.junit.Test
10+
import org.junit.Assert.assertEquals
1011

1112
import vulpix.TestConfiguration
1213

@@ -28,13 +29,13 @@ class BashScriptsTests:
2829
printf("scalac path: [%s]\n", scalacPath)
2930

3031
lazy val expectedOutput = List(
31-
"arg 0:[a]",
32-
"arg 1:[b]",
33-
"arg 2:[c]",
34-
"arg 3:[-repl]",
35-
"arg 4:[-run]",
36-
"arg 5:[-script]",
37-
"arg 6:[-debug]",
32+
"arg 0:[a]",
33+
"arg 1:[b]",
34+
"arg 2:[c]",
35+
"arg 3:[-repl]",
36+
"arg 4:[-run]",
37+
"arg 5:[-script]",
38+
"arg 6:[-debug]",
3839
)
3940
lazy val testScriptArgs = Seq(
4041
"a", "b", "c", "-repl", "-run", "-script", "-debug"
@@ -56,6 +57,38 @@ class BashScriptsTests:
5657
if fail then
5758
assert(stdout == expectedOutput)
5859

60+
/* verify `dist/bin/scala` with -J setting */
61+
@Test def verifyScJProperty =
62+
val commandline = Seq(scalaPath, "-J-Dkey=World", testFiles.find(_.getName == "envtest.sc").get.absPath).mkString(" ")
63+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
64+
assertEquals(stdout.mkString("/n"), "Hello World")
65+
66+
/* verify `dist/bin/scala` with -J setting */
67+
@Test def verifyScalaJProperty =
68+
val commandline = Seq(scalaPath, "-J-Dkey=World3", testFiles.find(_.getName == "envtest.scala").get.absPath).mkString(" ")
69+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
70+
assertEquals(stdout.mkString("/n"), "Hello World3")
71+
72+
/* verify `dist/bin/scala` with -D setting */
73+
@Test def verifyScDProperty =
74+
val commandline = Seq(scalaPath, "-Dkey=World3", testFiles.find(_.getName == "envtest.sc").get.absPath).mkString(" ")
75+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
76+
assertEquals(stdout.mkString("/n"), "Hello World3")
77+
78+
/* verify `dist/bin/scala` with -D setting */
79+
@Test def verifyScalaDProperty =
80+
val commandline = Seq(scalaPath, "-Dkey=World4", testFiles.find(_.getName == "envtest.scala").get.absPath).mkString(" ")
81+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline)
82+
assertEquals(stdout.mkString("/n"), "Hello World4")
83+
84+
/* verify `dist/bin/scala` with -D setting */
85+
@Test def saveAndRunWithDProperty =
86+
val commandline = Seq(scalaPath, "-save", testFiles.find(_.getName == "envtest.scala").get.absPath).mkString(" ")
87+
val (_, _, _, _) = bashCommand(commandline)
88+
val commandline2 = Seq(scalaPath, "-Dkey=World5", testFiles.find(_.getName == "envtest.jar").get.absPath).mkString(" ")
89+
val (validTest, exitCode, stdout, stderr) = bashCommand(commandline2)
90+
assertEquals(stdout.mkString("/n"), "Hello World5")
91+
5992
/* verify `dist/bin/scala` non-interference with command line args following script name */
6093
@Test def verifyScalaArgs =
6194
val commandline = (Seq("SCALA_OPTS= ", scalaPath, showArgsScript) ++ testScriptArgs).mkString(" ")
@@ -73,7 +106,7 @@ class BashScriptsTests:
73106
assert(stdout == expectedOutput)
74107

75108
/*
76-
* verify that scriptPath.sc sees a valid script.path property,
109+
* verify that scriptPath.sc sees a valid script.path property,
77110
* and that it's value is the path to "scriptPath.sc".
78111
*/
79112
@Test def verifyScriptPathProperty =
@@ -134,6 +167,7 @@ class BashScriptsTests:
134167
def exists: Boolean = s.toPath.toFile.exists
135168
def name: String = s.toFile.getName
136169
def dropExtension: String = s.reverse.dropWhile(_ != '.').drop(1).reverse
170+
def parent(up: Int): String = s.norm.split("/").reverse.drop(up).reverse.mkString("/")
137171
}
138172

139173
extension(p: Path) {
@@ -168,22 +202,20 @@ class BashScriptsTests:
168202
if scalacPath.isFile then scalacPath.replaceAll("/bin/scalac", "")
169203
else envOrElse("SCALA_HOME", "").norm
170204

171-
lazy val javaHome = envOrElse("JAVA_HOME", "").norm
205+
lazy val javaHome = whichJava.parent(2)
172206

173207
lazy val testEnvPairs = List(
174208
("JAVA_HOME", javaHome),
175209
("SCALA_HOME", scalaHome),
176210
("PATH", adjustedPath),
177211
).filter { case (name, valu) => valu.nonEmpty }
178212

179-
lazy val whichBash: String =
180-
var whichBash = ""
181-
if osname.startsWith("windows") then
182-
whichBash = which("bash.exe")
183-
else
184-
whichBash = which("bash")
213+
lazy val whichBash: String = whichExe("bash")
214+
lazy val whichJava: String = whichExe("java")
185215

186-
whichBash
216+
def whichExe(basename: String): String =
217+
val exeName = if (osname.toLowerCase.startsWith("windows")) s"$basename.exe" else basename
218+
which(exeName)
187219

188220
def bashCommand(cmdstr: String, additionalEnvPairs: List[(String, String)] = Nil): (Boolean, Int, Seq[String], Seq[String]) = {
189221
var (stdout, stderr) = (List.empty[String], List.empty[String])
@@ -192,7 +224,7 @@ class BashScriptsTests:
192224
val envPairs = testEnvPairs ++ additionalEnvPairs
193225
val proc = Process(cmd, None, envPairs *)
194226
val exitVal = proc ! ProcessLogger (
195-
(out: String) => stdout ::= out,
227+
(out: String) => stdout ::= out,
196228
(err: String) => stderr ::= err
197229
)
198230
val validTest = exitVal == 0 && ! stderr.exists(_.contains("Permission denied"))

compiler/test/dotty/tools/scripting/ClasspathTests.scala

+3-3
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ class ClasspathTests:
4141

4242
cmd.foreach { printf("[%s]\n", _) }
4343

44-
// test script reports the classpath it sees
44+
// test script reports the classpath it sees
4545
val scriptOutput = exec(cmd:_*)
4646
val scriptCwd = findTaggedLine("cwd", scriptOutput)
4747
printf("script ran in directory [%s]\n", scriptCwd)
4848
val scriptCp = findTaggedLine("classpath", scriptOutput)
4949

5050
val hashbangClasspathJars = scriptCp.split(psep).map { _.getName }.sorted.distinct
5151
val packlibJars = listJars(s"$scriptCwd/$packLibDir").sorted.distinct
52-
52+
5353
printf("%d jar files in dist/target/pack/lib\n", packlibJars.size)
5454
printf("%d test script jars in classpath\n", hashbangClasspathJars.size)
5555

@@ -78,7 +78,7 @@ class ClasspathTests:
7878

7979
cmd.foreach { printf("[%s]\n", _) }
8080

81-
// test script reports the classpath it sees
81+
// test script reports the classpath it sees
8282
val scriptOutput = exec(cmd:_*)
8383
val scriptCp = findTaggedLine("unglobbed classpath", scriptOutput)
8484
val classpathJars = scriptCp.split(psep).map { _.getName }.sorted.distinct

dist/bin/scala

+25-1
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,34 @@ fi
2828

2929
source "$PROG_HOME/bin/common"
3030

31+
while [[ $# -gt 0 ]]; do
32+
case "$1" in
33+
-D*)
34+
# pass to scala as well: otherwise we lose it sometimes when we
35+
# need it, e.g. communicating with a server compiler.
36+
addJava "$1"
37+
addScala "$1"
38+
# respect user-supplied -Dscala.usejavacp
39+
shift
40+
;;
41+
-J*)
42+
# as with -D, pass to scala even though it will almost
43+
# never be used.
44+
addJava "${1:2}"
45+
addScala "$1"
46+
shift
47+
;;
48+
*)
49+
addScala "$1"
50+
shift
51+
;;
52+
esac
53+
done
54+
3155
# exec here would prevent onExit from being called, leaving terminal in unusable state
3256
compilerJavaClasspathArgs
3357
[ -z "${ConEmuPID-}" -o -n "${cygwin-}" ] && export MSYSTEM= PWD= # workaround for #12405
34-
eval "\"$JAVACMD\"" "-Dscala.home=$PROG_HOME" "-classpath \"$jvm_cp_args\"" "dotty.tools.MainGenericRunner" "-classpath \"$jvm_cp_args\"" "$@"
58+
eval "\"$JAVACMD\"" "${java_args[@]}" "-Dscala.home=$PROG_HOME" "-classpath \"$jvm_cp_args\"" "dotty.tools.MainGenericRunner" "-classpath \"$jvm_cp_args\"" "${scala_args[@]}"
3559
scala_exit_status=$?
3660

3761

0 commit comments

Comments
 (0)