diff --git a/api/api/src/main/scala/aqua/api/Imports.scala b/api/api/src/main/scala/aqua/api/Imports.scala index 880dad2fd..c9bca47b1 100644 --- a/api/api/src/main/scala/aqua/api/Imports.scala +++ b/api/api/src/main/scala/aqua/api/Imports.scala @@ -11,7 +11,7 @@ import fs2.io.file.Path final case class Imports( settings: Map[Path, Imports.PathSettings] ) { - + def toIO: IOImports = IOImports( settings.view diff --git a/build.sbt b/build.sbt index edce76fa3..2bb3738a0 100644 --- a/build.sbt +++ b/build.sbt @@ -21,7 +21,7 @@ name := "aqua-hll" val commons = Seq( version := { val aquaSnapshot = sys.env.getOrElse("SNAPSHOT", "") - if (aquaSnapshot.isEmpty()) aquaVersion else aquaVersion + "-" + aquaSnapshot, + if (aquaSnapshot.isEmpty()) aquaVersion else aquaVersion + "-" + aquaSnapshot }, scalaVersion := scalaV, libraryDependencies ++= Seq( @@ -212,6 +212,30 @@ lazy val compiler = crossProject(JVMPlatform, JSPlatform) .settings(commons) .dependsOn(semantics, linker, backend, transform % "test->test", res % "test->test") +lazy val `compiler-native-lib` = project + .in(file("compiler-native-lib")) + .enablePlugins(NativeImagePlugin) + .settings(commons: _*) + .settings( + name := "libaqua", + Compile / mainClass := Some("aqua.compiler.Library"), + nativeImageVersion:="22.3.1", + nativeImageOptions ++= Seq( + "--verbose", + "--no-fallback", + "--shared", // Produce shared library + "--initialize-at-run-time=aqua.logging.LogFormatter$", + // Uncomment next lines to use llvm backend + // and obtain bitcode files + // "-H:CompilerBackend=llvm", + // "-H:TempDirectory=temp", // Directory with bc files + ), + libraryDependencies ++= Seq( + "org.graalvm.sdk" % "graal-sdk" % "24.0.1" + ) + ) + .dependsOn(`aqua-api`.jvm) + lazy val backend = crossProject(JVMPlatform, JSPlatform) .withoutSuffixFor(JVMPlatform) .crossType(CrossType.Pure) diff --git a/compiler-native-lib/src/main/scala/aqua/compiler/Library.scala b/compiler-native-lib/src/main/scala/aqua/compiler/Library.scala new file mode 100644 index 000000000..a57076179 --- /dev/null +++ b/compiler-native-lib/src/main/scala/aqua/compiler/Library.scala @@ -0,0 +1,60 @@ +package aqua.compiler + +import org.graalvm.nativeimage.IsolateThread +import org.graalvm.nativeimage.c.function.CEntryPoint +import org.graalvm.nativeimage.c.`type`.{CCharPointer, CCharPointerPointer, CTypeConversion} + +import scala.annotation.static +import cats.effect.unsafe.implicits.global +import aqua.api.{APICompilation, AquaAPIConfig, Imports} +import aqua.backend.api.APIBackend +import aqua.logging.LogFormatter + +// This is neede for @static to work in object +class Library {} + +object Library { + + @CEntryPoint(name = "compile") + @static + def compile( + thread: IsolateThread, + codePointer: CCharPointer, + resultPointer: CCharPointerPointer, + errorsPointer: CCharPointerPointer + ): Int = { + val code = CTypeConversion.toJavaString(codePointer) + + LogFormatter.initEmptyLogger() + + val result = APICompilation + .compileString( + code, + imports = Imports(Map.empty), + aquaConfig = AquaAPIConfig(), + backend = APIBackend + ) + .unsafeRunSync() + + result.value.value.fold( + errors => + errors.toChain.toList.zipWithIndex.foreach { case (error, i) => + errorsPointer.write(i, CTypeConversion.toCString(error).get()) + } + + 1 + , + compiled => + compiled.toList.flatMap(_.compiled).flatMap(_.air).map(_.air).zipWithIndex.foreach { + case (air, i) => resultPointer.write(i, CTypeConversion.toCString(code).get()) + } + + 0 + ) + } + + // Without main native-image refuses to work + @static + def main(args: Array[String]): Unit = () + +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 7044eb9b2..d7360d4d7 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,4 +2,5 @@ addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.5") addSbtPlugin("org.scala-js" % "sbt-scalajs" % "1.15.0") addSbtPlugin("org.portable-scala" % "sbt-scalajs-crossproject" % "1.3.2") addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") +addSbtPlugin("org.scalameta" % "sbt-native-image" % "0.3.4") addSbtPlugin("com.github.sbt" % "sbt-native-packager" % "1.10.0") diff --git a/utils/logging/src/main/scala/aqua/logging/LogFormatter.scala b/utils/logging/src/main/scala/aqua/logging/LogFormatter.scala index 62cacf1be..3845ab81f 100644 --- a/utils/logging/src/main/scala/aqua/logging/LogFormatter.scala +++ b/utils/logging/src/main/scala/aqua/logging/LogFormatter.scala @@ -18,4 +18,10 @@ object LogFormatter { .withHandler(formatter = formatter, minimumLevel = level) .replace() } + + def initEmptyLogger(): Logger = + scribe.Logger.root + .clearHandlers() + .clearModifiers() + .replace() }