Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Remove code related to LibraryI #135

Merged
merged 2 commits into from
Apr 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions core/docs/_docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Slinc is published to Maven Central for Scala 3. It is built to take advantage o
In your `build.sbt`:

```scala
libraryDependencies += "fr.hammons" %% "slinc-runtime" % "0.2.0"
libraryDependencies += "fr.hammons" %% "slinc-runtime" % "0.3.0"
//if forking and on Java 17
javaOptions ++= Seq("--add-modules=jdk.incubator.foreign", "--enable-native-access=ALL-UNNAMED")
```
Expand All @@ -32,13 +32,15 @@ Once you have your build system set up, you can create a new file and write the

```scala
import fr.hammons.slinc.runtime.given
import fr.hammons.slinc.types.*
import fr.hammons.slinc.*

case class div_t(quot: CInt, rem: CInt) derives Struct

trait MyLib derives Lib:
trait MyLib derives FSet:
def div(numer: CInt, denom: CInt): div_t

val myLib = Lib.instance[MyLib]
val myLib = FSet.instance[MyLib]

@main def calc =
val (quot, rem) = Tuple.fromProduct(myLib.div(5,2))
Expand Down
134 changes: 119 additions & 15 deletions core/docs/_docs/reference/library-modules.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
---
title: "Library Modules"
title: "Function Sets"
---

Library modules are groupings of functions in Slinc. Each can be configured in a number of ways.
Function sets are groupings of functions in Slinc. Each can be configured in a number of ways.

A library module is a Scala `trait` that derives the `Lib` type class. Method declarations within it are used as a template for the bindings to C that the Slinc runtime will generate.
A function set is a Scala `trait` that derives the `FSet` type class. Method declarations within it are used as a template for the bindings to C that the Slinc runtime will generate.

## Module Declarations
## FSet declarations

Module declarations are declarations of C library bindings without any entanglement in runtime details. This means that a module declaration only requires the use of the Slinc core library, and does not effect the runtime requirements of users of the module.
FSet declarations are declarations of C library bindings without any entanglement in runtime details. This means that an fset declaration only requires the use of the Slinc core library, and does not effect the runtime requirements of users of the module.

### Module naming
### FSet naming

The type name of the module does not matter to Slinc.

### Method naming

The name of method declarations within a library module should reflect the name of the C function you wish to bind to. If a method name is not found in the C namespace, this will cause a runtime error when you try to summon the module implementation.
The name of method declarations within an fset module should reflect the name of the C function you wish to bind to. If a method name is not found in the C namespace, this will cause a runtime error when you try to summon the module implementation.

Example:

```scala
trait L derives Lib:
trait L derives FSet:
def abs(i: CInt): CInt
```

Expand All @@ -39,23 +39,127 @@ trait L derives Lib:

This function is helpful when you have a function symbol that should be present on a platform, but has an alternative name for some reason. In the case with Windows, the `time` function in the C standard library is a macro that points to `_time64` on 64-bit platforms, and `_time32` on 32-bit platforms. Since macros do not exist as symbols in the C standard library namespace, this `NameOverride` makes the Slinc platform choose the right function name on Windows X64.

## Summoning Module Implementations
## Dependencies

FSets can be declared that depend on C libraries in a number of different ways:

* libraries stored in resources
* libraries at a relative location compared to the program
* libraries on the system path
* libraries at an absolute location
* C files located in resources

### Libraries in resources

A library can be stored in the jar for the program, and an FSet can depend on it with the `@NeedsResource` annotation.

```scala
import fr.hammons.slinc.annotations.*
import fr.hammons.slinc.types.*
import fr.hammons.slinc.*

@NeedsResource("my_lib.so")
trait L derives FSet:
def my_fun(i: CInt): Unit
```

This indicates that the FSet named `L` needs to load `/native/my_lib.so` from the jar resources. This dependency declaration is rather platform specific, since it depends on a specific .so file.

#### Platform dependent resource dependencies

Module declarations have been shown above, but they are not useable without being summoned. Doing so requires the Slinc runtime on your classpath, and makes the JAR and class files generated dependent on a specific JVM.
If you just provide the name of the library, not a specific .so file, Slinc will look in the jar resources for a library with that kind of name but with a library suffix and architecture tag based on the platform the program is run on. For example:

To summon a module implementation, you use the `Lib.instance[?]` method as shown in the following example:
```scala
import fr.hammons.slinc.annotations.*
import fr.hammons.slinc.types.*
import fr.hammons.slinc.*

@NeedsResource("my_lib")
trait L derives FSet:
def my_fun(i: CInt): Unit
```

The slinc runtime will look for `/native/my_lib_x64.so` on x86_64 linux, and `/native/my_lib_x64.dll` on x86_64 Windows.

### Libraries on the system path

If the library is on the system path that the JVM is aware of, you can declare an FSet's dependence on it with the `Needs` annotation.

```scala
import fr.hammons.slinc.annotations.*
import fr.hammons.slinc.types.*
import fr.hammons.slinc.*

@Needs("z")
trait L derives FSet:
def zlibVersion(): Ptr[CChar]
```

This declaration is for a binding to zlib.

### Libraries in the filesystem

If the library dependency is located on the filesystem, you can use an absolute or relative path with the `@NeedsFile` annotation.

```scala
import fr.hammons.slinc.annotations.*
import fr.hammons.slinc.types.*
import fr.hammons.slinc.*

//relative path
@NeedsFile("my_lib.so")
trait A derives FSet:
def my_fn(): Unit

//absolute path
@NeedsFile("/tmp/my_lib.so")
trait B derives FSet:
def my_fn(): Unit
```

#### Platform dependent filesystem dependencies

If you do not provide an absolute file name (file ending with .so or .dll), Slinc will use the base file name provided along with the appropriate library suffix for the OS and a tag based on the architecture.

For example, on Windows x86_64, `@NeedsFile("my_lib")` will look for `.\my_lib_x64.dll`.

The architecture tags for the architectures follows:

|arch |tags |
|-----|-----|
|x86_64| x64, amd64, x86_64|

### C file jar resources

If a C file is placed in a jar, under the `/native` you can use the `@NeedsResource` annotation to have Slinc compile and load the file at runtime. In order for this to work, one must have clang installed on the target system.

```scala
import fr.hammons.slinc.annotations.*
import fr.hammons.slinc.types.*
import fr.hammons.slinc.*

@NeedsResource("my_lib.c")
trait L derives FSet:
def my_fn(): Unit
```

## Summoning FSet Implementations

FSet declarations have been shown above, but they are not useable without being summoned. Doing so requires the Slinc runtime on your classpath, and makes the JAR and class files generated dependent on a specific JVM.

To summon an fset implementation, you use the `FSet.instance[?]` method as shown in the following example:

```scala
import fr.hammons.slinc.types.CInt
import fr.hammons.slinc.Lib
import fr.hammons.slinc.FSet
import fr.hammons.slinc.runtime.given

trait L derives Lib:
trait L derives FSet:
def abs(i: CInt): CInt

val l = Lib.instance[L]
val l = FSet.instance[L]

@main def program = println(l.abs(4))
```

Note the assignment of the instance to a `val`. This is not strictly necessary, and `Lib.instance` will always return the same module instance, but re-summoning is more expensive than storing the summoned module implementation.
Note the assignment of the instance to a `val`. This is not strictly necessary, and `FSet.instance` will always return the same module instance, but re-summoning is more expensive than storing the summoned module implementation.
26 changes: 0 additions & 26 deletions core/src/fr/hammons/slinc/Convertible.scala

This file was deleted.

32 changes: 0 additions & 32 deletions core/src/fr/hammons/slinc/DowncallI.scala

This file was deleted.

1 change: 1 addition & 0 deletions core/src/fr/hammons/slinc/FSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import fr.hammons.slinc.annotations.NeedsResource
import fr.hammons.slinc.annotations.Needs
import fr.hammons.slinc.annotations.NeedsFile

import fr.hammons.slinc.fset.FSetBacking
trait FSet[L]:
val dependencies: List[Dependency]
val description: List[CFunctionDescriptor]
Expand Down
1 change: 0 additions & 1 deletion core/src/fr/hammons/slinc/FunctionBindingGenerator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import scala.annotation.nowarn
import fr.hammons.slinc.FunctionContext.{InputTransition, ReturnTransition}
import fr.hammons.slinc.FunctionBindingGenerator.VariadicTransition

import fr.hammons.slinc.FunctionContext
trait FunctionBindingGenerator:
def generate(
methodHandler: MethodHandler,
Expand Down
Loading