All Downloads are FREE. Search and download functionalities are using the official Maven repository.

scala.scalanative.build.Build.scala Maven / Gradle / Ivy

There is a newer version: 0.5.5
Show newest version
package scala.scalanative
package build

import java.nio.file.{Path, Paths}
import scala.scalanative.util.Scope

/** Utility methods for building code using Scala Native. */
object Build {

  /** Run the complete Scala Native pipeline, LLVM optimizer and system linker,
   *  producing a native binary in the end.
   *
   *  For example, to produce a binary one needs a classpath, a working
   *  directory and a main class entry point:
   *
   *  {{{
   *  val classpath: Seq[Path] = ...
   *  val workdir: Path        = ...
   *  val main: String         = ...
   *
   *  val clang    = Discover.clang()
   *  val clangpp  = Discover.clangpp()
   *  val linkopts = Discover.linkingOptions()
   *  val compopts = Discover.compileOptions()
   *
   *  val outpath  = workdir.resolve("out")
   *
   *  val config =
   *    Config.empty
   *      .withCompilerConfig{
   *        NativeConfig.empty
   *        .withGC(GC.default)
   *        .withMode(Mode.default)
   *        .withClang(clang)
   *        .withClangPP(clangpp)
   *        .withLinkingOptions(linkopts)
   *        .withCompileOptions(compopts)
   *        .withLinkStubs(true)
   *      }
   *      .withMainClass(main)
   *      .withClassPath(classpath)
   *      .withWorkdir(workdir)
   *
   *  Build.build(config, outpath)
   *  }}}
   *
   *  @param config
   *    The configuration of the toolchain.
   *  @param outpath
   *    The path to the resulting native binary.
   *  @return
   *    `outpath`, the path to the resulting native binary.
   */
  def build(config: Config, outpath: Path)(implicit scope: Scope): Path =
    config.logger.time("Total") {
      // validate classpath
      val fconfig = {
        val fclasspath = NativeLib.filterClasspath(config.classPath)
        config.withClassPath(fclasspath)
      }

      // find and link
      val linked = {
        val entries = ScalaNative.entries(fconfig)
        val linked = ScalaNative.link(fconfig, entries)
        ScalaNative.logLinked(fconfig, linked)
        linked
      }

      // optimize and generate ll
      val generated = {
        val optimized = ScalaNative.optimize(fconfig, linked)
        ScalaNative.codegen(fconfig, optimized)
      }

      val objectPaths = config.logger.time("Compiling to native code") {
        // compile generated LLVM IR
        val llObjectPaths = LLVM.compile(fconfig, generated)

        /* Used to pass alternative paths of compiled native (lib) sources,
         * eg: reused native sources used in partests.
         */
        val libObjectPaths = scala.util.Properties
          .propOrNone("scalanative.build.paths.libobj") match {
          case None =>
            findAndCompileNativeSources(fconfig, linked)
          case Some(libObjectPaths) =>
            libObjectPaths
              .split(java.io.File.pathSeparatorChar)
              .toSeq
              .map(Paths.get(_))
        }

        libObjectPaths ++ llObjectPaths
      }

      LLVM.link(fconfig, linked, objectPaths, outpath)
    }

  def findAndCompileNativeSources(
      config: Config,
      linkerResult: linker.Result
  ): Seq[Path] = {
    import NativeLib._
    findNativeLibs(config.classPath, config.workdir)
      .map(unpackNativeCode)
      .flatMap { destPath =>
        val paths = findNativePaths(config.workdir, destPath)
        val (projPaths, projConfig) =
          Filter.filterNativelib(config, linkerResult, destPath, paths)
        LLVM.compile(projConfig, projPaths)
      }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy