Skip to content

Commit

Permalink
feat: File dependencies (#131)
Browse files Browse the repository at this point in the history
FSet dependencies to relative paths
FSet dependencies to absolute paths
Fixes #94, #95
  • Loading branch information
markehammons authored Apr 8, 2023
1 parent daf1380 commit fcfdfc4
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 1 deletion.
26 changes: 26 additions & 0 deletions build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,32 @@ trait BaseModule extends ScoverageModule with ScalafmtModule {
ivy"org.scalameta::munit-scalacheck:$munitVersion"
)


def compileLibs = T {

val suffix = System.getProperty("os.name") match {
case "windows" => ".dll"
case _ => ".so"
}

os.proc(
"clang",
"-shared",
"-fvisibility=default",
"-Os",
"-o",
s"libs/test$suffix",
"libs/test-code.c"
).spawn()

os.pwd / "libs" / s"test$suffix"
}

override def compile = T{
compileLibs()
super.compile()
}

}
}
object core
Expand Down
3 changes: 2 additions & 1 deletion core/src/fr/hammons/slinc/FSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import scala.annotation.nowarn
import fr.hammons.slinc.fset.Dependency
import fr.hammons.slinc.annotations.NeedsResource
import fr.hammons.slinc.annotations.Needs
import fr.hammons.slinc.annotations.NeedsFile

trait FSet[L]:
val dependencies: List[Dependency]
Expand Down Expand Up @@ -59,7 +60,7 @@ object FSet:
'{
new FSet[L]:
val dependencies =
(NeedsResource[L] ++ Needs[L]).map(_.toDependency)
(NeedsResource[L] ++ Needs[L] ++ NeedsFile[L]).map(_.toDependency)
val description = $descriptors
val generation = $generators
}
Expand Down
34 changes: 34 additions & 0 deletions core/src/fr/hammons/slinc/annotations/NeedsFile.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package fr.hammons.slinc.annotations

import scala.annotation.StaticAnnotation
import fr.hammons.slinc.fset.Dependency
import java.nio.file.Paths
import scala.quoted.*

final case class NeedsFile(val path: String)
extends StaticAnnotation,
DependencyAnnotation:
def toDependency: Dependency =
val filePath = Paths.get(path).nn
Dependency.FilePath(filePath)

object NeedsFile:
inline def apply[F]: List[NeedsFile] = ${
apply[F]()
}

private def apply[F]()(using Quotes, Type[F]): Expr[List[NeedsFile]] =
import quotes.reflect.*

Expr.ofList(
TypeRepr
.of[F]
.classSymbol
.get
.annotations
.view
.map(_.asExpr)
.collect:
case n @ '{ new NeedsFile(${ _ }) } => n
.toList
)
1 change: 1 addition & 0 deletions core/src/fr/hammons/slinc/fset/Dependency.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ enum Dependency:
case LibraryResource(path: Path)
case CResource(path: Path)
case PathLibrary(name: String)
case FilePath(path: Path)
2 changes: 2 additions & 0 deletions core/src/fr/hammons/slinc/modules/LinkageTools.scala
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ object LinkageTools:
load(compilationPath)
case Dependency.PathLibrary(name) =>
loadLibrary(name)
case Dependency.FilePath(path) =>
load(path)

dependenciesLoaded.compareAndExchange(
currentDeps,
Expand Down
39 changes: 39 additions & 0 deletions core/test/src/fr/hammons/slinc/FSetRuntimeSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ package fr.hammons.slinc
import java.{util as ju}
import fr.hammons.slinc.annotations.NeedsResource
import fr.hammons.slinc.types.CInt
import fr.hammons.slinc.types.{os, OS}
import fr.hammons.slinc.annotations.NeedsFile
import java.nio.file.Files
import java.nio.file.Paths

trait FSetRuntimeSpec(val slinc: Slinc) extends munit.FunSuite:
import slinc.given
Expand Down Expand Up @@ -34,3 +38,38 @@ trait FSetRuntimeSpec(val slinc: Slinc) extends munit.FunSuite:
FSet.instance[L].identity_int(5),
5
)

test("Relative file loading works"):
if os == OS.Windows then
@NeedsFile("libs/test.dll")
trait L derives FSet:
def test_fn(i: CInt): CInt

assertEquals(
FSet.instance[L].test_fn(2),
2
)
else
@NeedsFile("libs/test.so")
trait L derives FSet:
def test_fn(i: CInt): CInt

assertEquals(
FSet.instance[L].test_fn(2),
2
)

test("Absolute file loading works"):
if os == OS.Linux then
if !Files.exists(Paths.get("/tmp/test.so")) then
Files.copy(Paths.get("libs/test.so"), Paths.get("/tmp/test.so"))

@NeedsFile("/tmp/test.so")
trait L derives FSet:
def test_fn(i: CInt): CInt

assertEquals(
FSet.instance[L].test_fn(2),
2
)
else assert(true)
12 changes: 12 additions & 0 deletions core/test/src/fr/hammons/slinc/FSetSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,15 @@ class FSetSpec extends munit.FunSuite:
summon[FSet[L]].dependencies,
List(Dependency.PathLibrary("posix"))
)

test("file dependencies should be recorded for loading"):
@NeedsFile("core/test/resources/native/test.c")
trait L derives FSet:
def abs(i: CInt): CInt

assertEquals(
summon[FSet[L]].dependencies,
List(
Dependency.FilePath(Paths.get("core/test/resources/native/test.c").nn)
)
)
9 changes: 9 additions & 0 deletions libs/test-code.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifdef _WIN32
# define EXPORTED __declspec( dllexport )
#else
# define EXPORTED
#endif

EXPORTED int test_fn(int i) {
return i;
}

0 comments on commit fcfdfc4

Please sign in to comment.