Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run Scala.JS linker in an external process, enable back Scala.JS linking on Windows #676

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ out/
.bloop/
.metals/
.vscode/
.scala
.scala-build/
.bsp
.idea/

*.semanticdb
*.semanticdb
15 changes: 11 additions & 4 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,13 @@ trait BuildLikeModule
}

class Core(val crossScalaVersion: String) extends BuildLikeModule {
def moduleDeps = Seq(`bloop-rifle`())
def moduleDeps = Seq(
`bloop-rifle`(),
`build-macros`()
)
def scalacOptions = T {
super.scalacOptions() ++ Seq("-Xasync")
}

def ivyDeps = super.ivyDeps() ++ Agg(
Deps.collectionCompat,
Expand All @@ -205,7 +211,7 @@ class Core(val crossScalaVersion: String) extends BuildLikeModule {
Deps.nativeTools, // Used only for discovery methods. For linking, look for scala-native-cli
Deps.osLib,
Deps.pprint,
Deps.scalaJsLinkerInterface,
Deps.scalaJsLogging,
Deps.swoval
)

Expand Down Expand Up @@ -244,9 +250,11 @@ class Core(val crossScalaVersion: String) extends BuildLikeModule {
| def version = "${publishVersion()}"
| def detailedVersion: Option[String] = $detailedVersionValue
|
| def scalaJsVersion = "${Deps.scalaJsLinker.dep.version}"
| def scalaJsVersion = "${Scala.scalaJs}"
| def scalaNativeVersion = "${Deps.nativeTools.dep.version}"
|
| def scalaJsCliVersion = "${InternalDeps.Versions.scalaJsCli}"
|
| def stubsOrganization = "${stubs.pomSettings().organization}"
| def stubsModuleName = "${stubs.artifactName()}"
| def stubsVersion = "${stubs.publishVersion()}"
Expand Down Expand Up @@ -493,7 +501,6 @@ trait Cli extends SbtModule with CliLaunchers with ScalaCliPublishModule with Fo
Deps.jimfs, // scalaJsEnvNodeJs pulls jimfs:1.1, whose class path seems borked (bin compat issue with the guava version it depends on)
Deps.jniUtils,
Deps.jsoniterCore,
Deps.scalaJsLinker,
Deps.scalaPackager,
Deps.metaconfigTypesafe
)
Expand Down
3 changes: 2 additions & 1 deletion examples/.gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.scala/
.scala-build/
.bsp/
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package scala.build.errors

final class ScalaJsLinkingError extends BuildException("Error linking Scala.JS")

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package scala.build.tests

import com.eed3si9n.expecty.Expecty.expect
import dependency._
import org.scalajs.linker.interface.{ESVersion, ModuleKind, ModuleSplitStyle}

import scala.build.Ops._
import scala.build.Sources
Expand All @@ -12,6 +11,7 @@ import scala.build.Position
import scala.build.options.{BuildOptions, Scope}
import scala.build.preprocessing.directives.MultiValue
import scala.build.preprocessing.directives.NotABoolean
import scala.build.internal.ScalaJsLinkerConfig

class SourcesTests extends munit.FunSuite {

Expand Down Expand Up @@ -508,15 +508,15 @@ class SourcesTests extends munit.FunSuite {
jsOptions.dom == Some(true)
)
expect(
jsConfig.moduleKind == ModuleKind.CommonJSModule,
jsConfig.moduleKind == ScalaJsLinkerConfig.ModuleKind.CommonJSModule,
jsConfig.checkIR == true,
jsConfig.sourceMap == true,
jsConfig.jsHeader == "#!/usr/bin/env node\n",
jsConfig.jsHeader == Some("#!/usr/bin/env node\n"),
jsConfig.esFeatures.allowBigIntsForLongs == true,
jsConfig.esFeatures.avoidClasses == false,
jsConfig.esFeatures.avoidLetsAndConsts == false,
jsConfig.esFeatures.esVersion == ESVersion.ES2017,
jsConfig.moduleSplitStyle == ModuleSplitStyle.SmallestModules
jsConfig.esFeatures.esVersion == "ES2017",
jsConfig.moduleSplitStyle == ScalaJsLinkerConfig.ModuleSplitStyle.SmallestModules
)
}
}
Expand Down

This file was deleted.

6 changes: 3 additions & 3 deletions modules/cli/src/main/scala/scala/cli/commands/Fmt.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ package scala.cli.commands

import caseapp._

import scala.build.internal.{CustomCodeWrapper, Runner}
import scala.build.internal.{CustomCodeWrapper, FetchExternalBinary, Runner}
import scala.build.{CrossSources, Inputs, Logger, Sources}
import scala.cli.CurrentParams
import scala.cli.internal.FetchExternalBinary
import scala.util.control.NonFatal

object Fmt extends ScalaCommand[FmtOptions] {
Expand Down Expand Up @@ -89,7 +88,7 @@ object Fmt extends ScalaCommand[FmtOptions] {
}
CurrentParams.workspaceOpt = Some(workspace)
val (versionMaybe, confExists) = readVersionFromFile(workspace, logger)
val cache = options.shared.coursierCache
val cache = options.shared.buildOptions(false, None).archiveCache

if (sourceFiles.isEmpty)
logger.debug("No source files, not formatting anything")
Expand Down Expand Up @@ -132,6 +131,7 @@ object Fmt extends ScalaCommand[FmtOptions] {
case None =>
val (url, changing) = options.binaryUrl(versionMaybe)
FetchExternalBinary.fetch(url, changing, cache, logger, "scalafmt")
.orExit(logger)
}

logger.debug(s"Using scalafmt launcher $fmtLauncher")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package scala.cli.commands

import caseapp._

import scala.build.internal.Constants
import scala.build.internal.{Constants, FetchExternalBinary}
import scala.build.options.BuildOptions
import scala.cli.internal.FetchExternalBinary
import scala.util.Properties

// format: off
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import caseapp._
import java.io.File
import java.nio.file.Path

import scala.build.internal.Runner
import scala.build.internal.{FetchExternalBinary, Runner}
import scala.build.{Build, BuildThreads, Logger}
import scala.cli.CurrentParams
import scala.cli.internal.FetchExternalBinary
import scala.cli.packaging.Library

object Metabrowse extends ScalaCommand[MetabrowseOptions] {
Expand Down Expand Up @@ -77,7 +76,7 @@ object Metabrowse extends ScalaCommand[MetabrowseOptions] {
FetchExternalBinary.fetch(
url,
changing,
options.shared.coursierCache,
successfulBuild.options.archiveCache,
logger,
"metabrowse"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package scala.cli.commands

import caseapp._

import scala.build.internal.FetchExternalBinary
import scala.build.options.BuildOptions
import scala.cli.internal.FetchExternalBinary
import scala.util.Properties

// format: off
Expand Down
80 changes: 50 additions & 30 deletions modules/cli/src/main/scala/scala/cli/commands/Package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package scala.cli.commands
import caseapp._
import coursier.launcher._
import dependency.dependencyString
import org.scalajs.linker.interface.StandardConfig
import packager.config._
import packager.deb.DebianPackage
import packager.docker.DockerPackage
Expand All @@ -21,7 +20,7 @@ import java.util.zip.{ZipEntry, ZipOutputStream}
import scala.build.EitherCps.{either, value}
import scala.build._
import scala.build.errors.{BuildException, ScalaNativeBuildError}
import scala.build.internal.{NativeBuilderHelper, Runner, ScalaJsConfig}
import scala.build.internal.{NativeBuilderHelper, Runner, ScalaJsLinkerConfig}
import scala.build.options.{PackageType, Platform}
import scala.cli.CurrentParams
import scala.cli.commands.OptionsHelper._
Expand Down Expand Up @@ -525,7 +524,16 @@ object Package extends ScalaCommand[PackageOptions] {
logger: Logger
): Either[BuildException, Unit] = {
val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger)
linkJs(build, destPath, Some(mainClass), addTestInitializer = false, linkerConfig, logger)
linkJs(
build,
destPath,
Some(mainClass),
addTestInitializer = false,
linkerConfig,
build.options.scalaJsOptions.fullOpt.getOrElse(false),
build.options.scalaJsOptions.noOpt.getOrElse(false),
logger
)
}

private def buildNative(
Expand Down Expand Up @@ -657,38 +665,50 @@ object Package extends ScalaCommand[PackageOptions] {
dest: os.Path,
mainClassOpt: Option[String],
addTestInitializer: Boolean,
config: StandardConfig,
config: ScalaJsLinkerConfig,
fullOpt: Boolean,
noOpt: Boolean,
logger: Logger
): Either[BuildException, Unit] =
Library.withLibraryJar(build, dest.last.toString.stripSuffix(".jar")) { mainJar =>
val classPath = mainJar +: build.artifacts.classPath.map(_.toNIO)
val classPath = os.Path(mainJar, os.pwd) +: build.artifacts.classPath
val linkingDir = os.temp.dir(prefix = "scala-cli-js-linking")
(new ScalaJsLinker).link(
classPath.toArray,
mainClassOpt.orNull,
addTestInitializer,
new ScalaJsConfig(config),
linkingDir.toNIO,
logger.scalaJsLogger
)
val relMainJs = os.rel / "main.js"
val relSourceMapJs = os.rel / "main.js.map"
val mainJs = linkingDir / relMainJs
val sourceMapJs = linkingDir / relSourceMapJs
if (os.exists(mainJs)) {
os.copy(mainJs, dest, replaceExisting = true)
if (build.options.scalaJsOptions.emitSourceMaps && os.exists(sourceMapJs)) {
val sourceMapDest =
build.options.scalaJsOptions.sourceMapsDest.getOrElse(os.Path(s"$dest.map"))
os.copy(sourceMapJs, sourceMapDest, replaceExisting = true)
logger.message(s"Emitted js source maps to: $sourceMapDest")
either {
value {
ScalaJsLinker.link(
build.options.notForBloopOptions.scalaJsLinkerOptions,
build.options.javaHome().value.javaCommand, // FIXME Allow users to use another JVM here?
classPath,
mainClassOpt.orNull,
addTestInitializer,
config,
linkingDir,
fullOpt,
noOpt,
logger,
build.options.finalCache,
build.options.archiveCache,
build.options.scalaJsOptions.finalVersion
)
}
val relMainJs = os.rel / "main.js"
val relSourceMapJs = os.rel / "main.js.map"
val mainJs = linkingDir / relMainJs
val sourceMapJs = linkingDir / relSourceMapJs
if (os.exists(mainJs)) {
os.copy(mainJs, dest, replaceExisting = true)
if (build.options.scalaJsOptions.emitSourceMaps && os.exists(sourceMapJs)) {
val sourceMapDest =
build.options.scalaJsOptions.sourceMapsDest.getOrElse(os.Path(s"$dest.map"))
os.copy(sourceMapJs, sourceMapDest, replaceExisting = true)
logger.message(s"Emitted js source maps to: $sourceMapDest")
}
os.remove.all(linkingDir)
}
else {
val found = os.walk(linkingDir).map(_.relativeTo(linkingDir))
value(Left(new ScalaJsLinkingError(relMainJs, found)))
}
os.remove.all(linkingDir)
Right(())
}
else {
val found = os.walk(linkingDir).map(_.relativeTo(linkingDir))
Left(new ScalaJsLinkingError(relMainJs, found))
}
}

Expand Down
28 changes: 23 additions & 5 deletions modules/cli/src/main/scala/scala/cli/commands/Run.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package scala.cli.commands

import caseapp._
import org.scalajs.linker.interface.StandardConfig

import scala.build.EitherCps.{either, value}
import scala.build.errors.BuildException
import scala.build.internal.{Constants, Runner}
import scala.build.internal.{Constants, Runner, ScalaJsLinkerConfig}
import scala.build.options.Platform
import scala.build.{Build, BuildThreads, Inputs, Logger}
import scala.cli.CurrentParams
Expand Down Expand Up @@ -162,7 +161,15 @@ object Run extends ScalaCommand[RunOptions] {
case Platform.JS =>
val linkerConfig = build.options.scalaJsOptions.linkerConfig(logger)
val res =
withLinkedJs(build, Some(mainClass), addTestInitializer = false, linkerConfig, logger) {
withLinkedJs(
build,
Some(mainClass),
addTestInitializer = false,
linkerConfig,
build.options.scalaJsOptions.fullOpt.getOrElse(false),
build.options.scalaJsOptions.noOpt.getOrElse(false),
logger
) {
js =>
Runner.runJs(
js.toIO,
Expand Down Expand Up @@ -215,11 +222,22 @@ object Run extends ScalaCommand[RunOptions] {
build: Build.Successful,
mainClassOpt: Option[String],
addTestInitializer: Boolean,
config: StandardConfig,
config: ScalaJsLinkerConfig,
fullOpt: Boolean,
noOpt: Boolean,
logger: Logger
)(f: os.Path => T): Either[BuildException, T] = {
val dest = os.temp(prefix = "main", suffix = ".js")
try Package.linkJs(build, dest, mainClassOpt, addTestInitializer, config, logger).map { _ =>
try Package.linkJs(
build,
dest,
mainClassOpt,
addTestInitializer,
config,
fullOpt,
noOpt,
logger
).map { _ =>
f(dest)
}
finally if (os.exists(dest)) os.remove(dest)
Expand Down
Loading