Skip to content

Commit

Permalink
Better tools API
Browse files Browse the repository at this point in the history
Modularizes tools API and makes it less tightly coupled.
Compiler is now split into Linker, Optimizer and CodeGen.
All three can be used and tested independently.

Fixes #329
  • Loading branch information
densh committed Nov 24, 2016
1 parent d7078df commit 8220daa
Show file tree
Hide file tree
Showing 56 changed files with 1,332 additions and 1,005 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,12 @@ import java.nio.file.{StandardOpenOption => OpenOpt, _}
import java.nio.channels._

package object serialization {
private val default = ByteBuffer.allocateDirect(128 * 1024 * 1024)

def serializeText(defns: Seq[Defn], buffer: ByteBuffer): Unit =
buffer.put(Shows.showDefns(defns).toString.getBytes)

def serializeBinary(defns: Seq[Defn], buffer: ByteBuffer): Unit =
(new BinarySerializer(buffer)).serialize(defns)

def serializeFile(serialize: (Seq[Defn], ByteBuffer) => Unit,
defns: Seq[Defn],
path: String,
buffer: ByteBuffer = default): Unit = {
buffer.clear
serialize(defns, buffer)
buffer.flip
val channel = FileChannel.open(Paths.get(path),
OpenOpt.CREATE,
OpenOpt.WRITE,
OpenOpt.TRUNCATE_EXISTING)
try channel.write(buffer)
finally channel.close
}

def serializeTextFile(defns: Seq[Defn],
path: String,
buffer: ByteBuffer = default): Unit =
serializeFile(serializeText, defns, path, buffer)

def serializeBinaryFile(defns: Seq[Defn],
path: String,
buffer: ByteBuffer = default): Unit =
serializeFile(serializeBinary, defns, path, buffer)

def deserializeBinaryFile(path: String): BinaryDeserializer =
new BinaryDeserializer({
val bytes = Files.readAllBytes(Paths.get(path))
val buffer = ByteBuffer.wrap(bytes)
buffer
})
def deserializeBinary(buffer: ByteBuffer): BinaryDeserializer =
new BinaryDeserializer(buffer)
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ trait NirDefinitions { self: NirGlobalAddons =>

// Native runtime

lazy val RuntimePackage = getPackage("scala.scalanative.runtime")
lazy val RuntimePackage = getPackage(TermName("scala.scalanative.runtime"))

lazy val RuntimeMonitorClass = getRequiredClass(
"scala.scalanative.runtime.Monitor")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package scala.scalanative
package nscplugin

import java.nio.file.{Path, Paths}
import scala.tools.nsc._
import scala.tools.nsc.io.AbstractFile
import scalanative.nir.serialization.{serializeText, serializeBinary}
import scalanative.io.withScratchBuffer
import scalanative.io.VirtualDirectory.root

trait NirFiles { self: NirCodeGen =>
import global._

private def getPathFor(cunit: CompilationUnit,
sym: Symbol,
suffix: String): String = {
suffix: String): Path = {
val baseDir: AbstractFile =
settings.outputDirs.outputDirFor(cunit.source.file)

Expand All @@ -20,15 +24,22 @@ trait NirFiles { self: NirCodeGen =>
var filename = pathParts.last
val file = dir fileNamed (filename + suffix)

file.file.getAbsolutePath
Paths.get(file.file.getAbsolutePath)
}

def genIRFile(cunit: CompilationUnit,
sym: Symbol,
defns: Seq[nir.Defn]): Unit = {
nir.serialization
.serializeBinaryFile(defns, getPathFor(cunit, sym, s".nir"))
nir.serialization
.serializeTextFile(defns, getPathFor(cunit, sym, s".hnir"))
withScratchBuffer { buffer =>
serializeBinary(defns, buffer)
buffer.flip
root.write(getPathFor(cunit, sym, s".nir"), buffer)
}

withScratchBuffer { buffer =>
serializeText(defns, buffer)
buffer.flip
root.write(getPathFor(cunit, sym, s".hnir"), buffer)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@ package scala.scalanative
package sbtplugin

import sbt._, Keys._, complete.DefaultParsers._
import scalanative.compiler.{Compiler => NativeCompiler, Opts => NativeOpts}
import ScalaNativePlugin.autoImport._
import scala.util.Try
import scalanative.nir
import scalanative.tools
import scalanative.io.VirtualDirectory
import scalanative.sbtplugin.ScalaNativePlugin.autoImport._

object ScalaNativePluginInternal {
private def cpToStrings(cp: Seq[File]): Seq[String] =
cp.map(_.getAbsolutePath)

private def cpToString(cp: Seq[File]): String =
cpToStrings(cp).mkString(java.io.File.pathSeparator)

private lazy val nativelib: File =
Path.userHome / ".scalanative" / ("nativelib-" + nir.Versions.current)

Expand Down Expand Up @@ -46,9 +42,13 @@ object ScalaNativePluginInternal {
}

/** Compiles application nir to llvm ir. */
private def compileNir(opts: NativeOpts): Seq[nir.Attr.Link] = {
val compiler = new NativeCompiler(opts)
compiler.apply()
private def compileNir(config: tools.Config): Seq[nir.Attr.Link] = {
val driver = tools.Driver(config)
val (links, raw) = tools.link(config, driver)
val optimized = tools.optimize(config, driver, raw)
tools.codegen(config, optimized)

links
}

/** Compiles *.c[pp] in `cwd`. */
Expand All @@ -65,13 +65,16 @@ object ScalaNativePluginInternal {
}

/** Compiles rt to llvm ir using clang. */
private def unpackRtlib(clang: File,
clangpp: File,
classpath: Seq[String]): Boolean = {
val nativelibjar = classpath.collectFirst {
case p if p.contains("scala-native") && p.contains("nativelib") =>
file(p)
}.get
private def unpackNativelib(clang: File,
clangpp: File,
classpath: Seq[File]): Boolean = {
val nativelibjar = classpath
.map(abs)
.collectFirst {
case p if p.contains("scala-native") && p.contains("nativelib") =>
file(p)
}
.get
val jarhash = Hash(nativelibjar).toSeq
val jarhashfile = nativelib / "jarhash"
def bootstrapped =
Expand Down Expand Up @@ -149,24 +152,25 @@ object ScalaNativePluginInternal {
val mainClass = (selectMainClass in Compile).value.getOrElse(
throw new MessageOnlyException("No main class detected.")
)
val entry = mainClass.toString + "$"
val classpath = cpToStrings((fullClasspath in Compile).value.map(_.data))
val entry = nir.Global.Top(mainClass.toString + "$")
val classpath = (fullClasspath in Compile).value.map(_.data)
val target = (crossTarget in Compile).value
val appll = target / (moduleName.value + "-out.ll")
val appll = target / "out.ll"
val binary = (artifactPath in nativeLink).value
val verbose = nativeVerbose.value
val clang = nativeClang.value
val clangpp = nativeClangPP.value
val clangOpts = nativeClangOptions.value
val dotpath = nativeEmitDependencyGraphPath.value
val linkage = nativeLibraryLinkage.value
val sharedLibrary = nativeSharedLibrary.value
val opts = new NativeOpts(classpath,
abs(appll),
dotpath.map(abs),
entry,
verbose,
sharedLibrary)

val config = tools.Config.empty
.withEntry(entry)
.withPaths(classpath.map(p => tools.Path(VirtualDirectory.real(p))))
.withTargetDirectory(VirtualDirectory.real(target))
.withInjectMain(!nativeSharedLibrary.value)
.withCheck(false)
.withVerbose(nativeVerbose.value)

checkThatClangIsRecentEnough(clang)

Expand All @@ -175,7 +179,7 @@ object ScalaNativePluginInternal {
val inputFiles = nirFiles + configFile

writeConfigHash(configFile,
opts,
config,
clang,
clangpp,
classpath,
Expand All @@ -190,9 +194,9 @@ object ScalaNativePluginInternal {
FilesInfo.hash) {
_ =>
IO.createDirectory(target)
val unpackSuccess = unpackRtlib(clang, clangpp, classpath)
val unpackSuccess = unpackNativelib(clang, clangpp, classpath)
if (unpackSuccess) {
val links = compileNir(opts).map(_.name)
val links = compileNir(config).map(_.name)
compileLl(clangpp,
target,
appll,
Expand Down

0 comments on commit 8220daa

Please sign in to comment.