aboutsummaryrefslogblamecommitdiff
path: root/project/native.scala
blob: 68c970edb6e3e89eb2b82c03927c70e12c1c0fe6 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13




                                       







                           

                   


                                                                                                               
 






                                                                                                             

                                                                                              





                                                                                                      







                                                                                                           







                                                                                                                                          
 




                                                                                               

   



                                                                                                                                                                 
                                       


                                                         

                                 


                                                                                           


       































                                                                                                                             
     
                  

   

















                                                                                          
 


                                             
 
import sbt._
import Keys._
import java.io.File
import scala.collection.mutable.HashSet

case class NativeBuild(
  name: String,
  cCompiler: String,
  cFlags: Seq[String],
  linker: String,
  linkerFlags: Seq[String],
  binary: String)

object NativeKeys {
  
  //build settings
  val nativeBuilds = taskKey[Seq[NativeBuild]]("All native build configurations, including cross-compilation.")
  val nativeVersion = settingKey[String]("Version of native binary")

  //compile settings
  val nativeIncludeDirectories = settingKey[Seq[File]]("Directories to include during build (gcc -I option)")
  
  //link settings
  val nativeLibraries = settingKey[Seq[String]]("Default names of libraries to use during linking.")
  val nativeLibraryDirectories = settingKey[Seq[File]]("Directories to search for libraries (gcc -L option)")
  
  //directories
  val nativeSource = settingKey[File]("Lowest level directory containing all native sources.")
  val nativeCSources = taskKey[Seq[File]]("All c source files.")
  val nativeTargetDirectory = settingKey[File]("Directory containing all compiled and linked files.")

  //tasks
  val nativeCompile = taskKey[Map[NativeBuild, Seq[File]]]("Compile all native build configurations.")
  val nativeLink = taskKey[Map[NativeBuild, File]]("Link all native build configurations.")
  
}

object NativeDefaults {
  import NativeKeys._

  private def generate(generators: SettingKey[Seq[Task[Seq[File]]]]) = generators { _.join.map(_.flatten) }

  private def compile(logger: Logger, compiler: String, flags: Seq[String], includeDirectories: Seq[File], src: File, out: File): File = {
    IO.createDirectory(out.getParentFile)
    val parts: Seq[String] =
      Seq(compiler) ++
      flags ++
      includeDirectories.map("-I" + _.getAbsolutePath) ++
      Seq("-o", out.getAbsolutePath) ++
      Seq("-c", src.getAbsolutePath)

    val cmd = parts.mkString(" ")
    logger.info(cmd)
    val ev = Process(cmd) ! logger
    if (ev != 0) throw new RuntimeException(s"Compilation of ${src.getAbsoluteFile()} failed.")
    out
  }

  private def link(logger: Logger, linker: String, flags: Seq[String], libraryDirectories: Seq[File], libraries: Seq[String], in: Seq[File], out: File): File = {
    val parts: Seq[String] =
      Seq(linker) ++
      flags ++
      Seq("-o", out.getAbsolutePath) ++
      in.map(_.getAbsolutePath) ++
      libraryDirectories.map("-L" + _.getAbsolutePath) ++
      libraries.map("-l" + _)

    val cmd = parts.mkString(" ")
    logger.info(cmd)
    val ev = Process(cmd) ! logger
    if (ev != 0) throw new RuntimeException(s"Linking of ${out.getAbsoluteFile()} failed.")
    out
  }


  def  nativeCompileImpl() = Def.task {
    val logger = streams.value.log
    val builds = nativeBuilds.value
    val outDir = nativeTargetDirectory.value
    val includeDirs = nativeIncludeDirectories.value
    val csrcs = nativeCSources.value

    val compilations = for (build <- builds) yield {
      logger.info("Compiling configuration " + build.name)
      val objects = for (src <- csrcs) yield {
        compile(logger, build.cCompiler, build.cFlags, includeDirs, src, outDir / build.name / "objects" / (src.base + ".o"))
      }
      build -> objects
    }
     compilations.toMap
  }

  lazy val nativeLinkImpl = Def.task {
    val logger = streams.value.log
    val builds = nativeBuilds.value
    val outDir = nativeTargetDirectory.value
    val libDirs = nativeLibraryDirectories.value
    val libs = nativeLibraries.value
    val compilations = nativeCompile.value
    val version = nativeVersion.value

    val linkages = for (build <- builds) yield {
      logger.info("Linking configuration " + build.name)
      val objects = compilations(build)
      val binary = link(logger, build.linker, build.linkerFlags, libDirs, libs, objects, outDir / build.name / build.binary)
      build -> binary
    }
    linkages.toMap
  }
  
  def localPlatform = try {
    Process("gcc -dumpmachine").lines.headOption
  } catch {
    case ex: Exception => None
  }

  
  val settings: Seq[Setting[_]] = Seq(
    //nativeBuilds :=

    nativeSource := (sourceDirectory in Compile).value / "native",
    includeFilter in nativeCSources := "*.c",
    nativeCSources := (nativeSource.value ** (includeFilter in nativeCSources).value).get,
    nativeTargetDirectory := target.value / "native",

    nativeIncludeDirectories := Seq(nativeSource.value, nativeSource.value / "include"),
    nativeLibraries := Seq(),
    nativeLibraryDirectories := Seq(),

    nativeCompile := nativeCompileImpl.value,
    nativeLink := nativeLinkImpl.value
  )
}