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

Frgaal integration in sbt #3421

Merged
merged 11 commits into from
May 4, 2022
32 changes: 25 additions & 7 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ import org.enso.build.BenchTasks._
import org.enso.build.WithDebugCommand
import sbt.Keys.{libraryDependencies, scalacOptions}
import sbt.addCompilerPlugin
import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
import src.main.scala.licenses.{
DistributionDescription,
SBTDistributionComponent
}
import sbtcrossproject.CrossPlugin.autoImport.{CrossType, crossProject}
import src.main.scala.licenses.{DistributionDescription, SBTDistributionComponent}

import java.io.File
import java.nio.file.Paths

// ============================================================================
// === Global Configuration ===================================================
Expand Down Expand Up @@ -952,7 +950,7 @@ lazy val searcher = project
lazy val `interpreter-dsl` = (project in file("lib/scala/interpreter-dsl"))
.settings(
version := "0.1",
libraryDependencies += "com.google.auto.service" % "auto-service" % "1.0.1" exclude ("com.google.code.findbugs", "jsr305")
libraryDependencies += "org.netbeans.api" % "org-openide-util-lookup" % "RELEASE130"
)

// ============================================================================
Expand Down Expand Up @@ -1128,6 +1126,22 @@ lazy val runtime = (project in file("engine/runtime"))
cleanInstruments := FixInstrumentsGeneration.cleanInstruments.value,
inConfig(Compile)(truffleRunOptionsSettings),
inConfig(Benchmark)(Defaults.testSettings),
compilers := {
val cp = (Compile / dependencyClasspath).value
val frgaalCheck = (module: ModuleID) => module.organization == "org.frgaal" && module.name == "compiler"
val frgaalOnClasspath =
cp.find(f => f.metadata.get(AttributeKey[ModuleID]("moduleID")).map(frgaalCheck).getOrElse(false))
.map(_.data.toPath)

if (frgaalOnClasspath.isEmpty) {
throw new RuntimeException("Failed to resolve Frgaal compiler. Aborting!")
}
val local = javax.tools.ToolProvider.getSystemJavaCompiler
val javaHome = Option(System.getProperty("java.home")).map(Paths.get(_))
val frgaalJavac = new FrgaalJavaCompiler(javaHome, frgaalOnClasspath.get, source = "16")
val javaTools = sbt.internal.inc.javac.JavaTools(frgaalJavac, compilers.value.javaTools.javadoc())
xsbti.compile.Compilers.of(compilers.value.scalac, javaTools)
},
Test / parallelExecution := false,
Test / logBuffered := false,
scalacOptions += "-Ymacro-annotations",
Expand All @@ -1147,7 +1161,11 @@ lazy val runtime = (project in file("engine/runtime"))
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.graalvm.truffle" % "truffle-api" % graalVersion % Benchmark,
"org.typelevel" %% "cats-core" % catsVersion,
"eu.timepit" %% "refined" % refinedVersion
"eu.timepit" %% "refined" % refinedVersion,
// This dependency is needed only so that developers don't download Frgaal manually.
// Sadly it cannot be placed under plugins either because meta dependencies are not easily
// accessible from the non-meta build definition.
"org.frgaal" % "compiler" % "18.0.0" % "provided"
),
// Note [Unmanaged Classpath]
Compile / unmanagedClasspath += (`core-definition` / Compile / packageBin).value,
Expand Down
5 changes: 5 additions & 0 deletions engine/runtime/src/main/scala/org/enso/compiler/core/R.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.enso.compiler.core;

// Just to demonstrate we can now compile records
public record R (String name) {
hubertp marked this conversation as resolved.
Show resolved Hide resolved
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.enso.interpreter.dsl;

import com.google.auto.service.AutoService;
import org.enso.interpreter.dsl.model.MethodDefinition;

import javax.annotation.processing.*;
Expand All @@ -15,11 +14,12 @@
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Collectors;
import org.openide.util.lookup.ServiceProvider;

/** The processor used to generate code from the {@link BuiltinMethod} annotation. */
@SupportedAnnotationTypes("org.enso.interpreter.dsl.BuiltinMethod")
@SupportedSourceVersion(SourceVersion.RELEASE_11)
@AutoService(Processor.class)
@ServiceProvider(service = Processor.class)
hubertp marked this conversation as resolved.
Show resolved Hide resolved
public class MethodProcessor extends AbstractProcessor {

/**
Expand Down
91 changes: 91 additions & 0 deletions project/FrgaalJavaCompiler.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

import sbt.internal.inc.CompilerArguments
import sbt.internal.inc.javac.JavacLogger
import sbt.io.IO
import sbt.util.Logger
import xsbti.{PathBasedFile, Reporter, VirtualFile, Logger => XLogger}
import xsbti.compile.{IncToolOptions, Output, JavaCompiler => XJavaCompiler}

import java.io.File
import java.nio.file.Path
import scala.sys.process.Process

object FrgaalJavaCompiler {

/** Helper method to launch programs. */
def launch(
javaHome: Option[Path],
compilerJar: Path,
sources0: Seq[VirtualFile],
options: Seq[String],
output: Output,
log: Logger,
reporter: Reporter,
source: String,
target: String
): Boolean = {
val (jArgs, nonJArgs) = options.partition(_.startsWith("-J"))
val outputOption = CompilerArguments.outputOption(output)
val sources = sources0 map {
case x: PathBasedFile => x.toPath.toAbsolutePath.toString
}
val frgaalOptions = Seq("-source", source, "-target", target)
val allArguments = outputOption ++ frgaalOptions ++ nonJArgs ++ sources

withArgumentFile(allArguments) { argsFile =>
val forkArgs = (jArgs ++ Seq("--limit-modules", "java.base,jdk.zipfs", "-jar", compilerJar.toString)) :+ s"@${normalizeSlash(argsFile.getAbsolutePath)}"
hubertp marked this conversation as resolved.
Show resolved Hide resolved
val exe = getJavaExecutable(javaHome, "java")
val cwd = new File(new File(".").getAbsolutePath).getCanonicalFile
val javacLogger = new JavacLogger(log, reporter, cwd)
var exitCode = -1
try {
exitCode = Process(exe +: forkArgs, cwd) ! javacLogger
} finally {
javacLogger.flush("frgaal", exitCode)
}
// We return true or false, depending on success.
exitCode == 0
}
}

/**
* Helper method to create an argument file that we pass to Javac. Gets over the windows
* command line length limitation.
* @param args The string arguments to pass to Javac.
* @param f A function which is passed the arg file.
* @tparam T The return type.
* @return The result of using the argument file.
*/
def withArgumentFile[T](args: Seq[String])(f: File => T): T = {
import IO.{ Newline, withTemporaryDirectory, write }
withTemporaryDirectory { tmp =>
val argFile = new File(tmp, "argfile")
write(argFile, args.map(escapeSpaces).mkString(Newline))
f(argFile)
}
}
// javac's argument file seems to allow naive space escaping with quotes. escaping a quote with a backslash does not work
private def escapeSpaces(s: String): String = '\"' + normalizeSlash(s) + '\"'
private def normalizeSlash(s: String) = s.replace(File.separatorChar, '/')

/** create the executable name for java */
def getJavaExecutable(javaHome: Option[Path], name: String): String =
javaHome match {
case None => name
case Some(jh) =>
jh.resolve("bin").resolve(name).toAbsolutePath.toString
}
}

/** An implementation of compiling java which forks a Javac instance. */
final class FrgaalJavaCompiler(javaHome: Option[Path], compilerPath: Path, source: String="11", target: String="11") extends XJavaCompiler {
hubertp marked this conversation as resolved.
Show resolved Hide resolved
def run(
sources: Array[VirtualFile],
options: Array[String],
output: Output,
incToolOptions: IncToolOptions,
reporter: Reporter,
log: XLogger
): Boolean =
FrgaalJavaCompiler.launch(javaHome, compilerPath, sources, options, output, log, reporter, source, target)
}
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-license-report" % "1.2.0")
addSbtPlugin("com.lightbend.sbt" % "sbt-java-formatter" % "0.7.0")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.6")

libraryDependencies += "io.circe" %% "circe-yaml" % "0.14.1"
libraryDependencies += "io.circe" %% "circe-yaml" % "0.14.1"