-
-
Notifications
You must be signed in to change notification settings - Fork 360
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This is a PR to close issue #3647
- Loading branch information
Showing
20 changed files
with
495 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
= Scala Native Examples | ||
:page-aliases: Scala_Native_Examples.adoc | ||
|
||
++++ | ||
<script> | ||
gtag('config', 'AW-16649289906'); | ||
</script> | ||
++++ | ||
|
||
|
||
This page contains examples of using Mill as a build tool for scala-native applications. | ||
It covers setting up a basic scala-native application that calls C function within it, | ||
as well as example of two modules with a scala-native application. | ||
|
||
== Simple | ||
|
||
include::partial$example/scalalib/native/1-simple.adoc[] | ||
|
||
== Interop | ||
|
||
include::partial$example/scalalib/native/2-interop.adoc[] | ||
|
||
== Multi-Module | ||
|
||
include::partial$example/scalalib/native/3-multi-module.adoc[] | ||
|
||
== Common Config | ||
|
||
include::partial$example/scalalib/native/4-common-config.adoc[] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package build | ||
import mill._, scalalib._, scalanativelib._ | ||
|
||
object `package` extends RootModule with ScalaNativeModule { | ||
def scalaVersion = "3.3.4" | ||
def scalaNativeVersion = "0.5.5" | ||
|
||
// You can have arbitrary numbers of third-party dependencies | ||
def ivyDeps = Agg( | ||
ivy"com.lihaoyi::mainargs::0.7.6" | ||
) | ||
|
||
object test extends ScalaNativeTests with TestModule.Utest{ | ||
def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.8.4") | ||
def testFramework = "utest.runner.Framework" | ||
} | ||
} | ||
|
||
// This example demonstrates a simple Scala program that generates HTML content | ||
// from user-provided text and prints it to the standard output, utilizing Scala | ||
// Native for native integration and `mainargs` for command-line argument parsing. | ||
|
||
/** Usage | ||
|
||
> ./mill run --text hello | ||
<h1>hello</h1> | ||
|
||
> ./mill show nativeLink # Build and link native binary | ||
".../out/nativeLink.dest/out" | ||
|
||
> ./out/nativeLink.dest/out --text hello # Run the executable | ||
<h1>hello</h1> | ||
|
||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package foo | ||
|
||
import scala.scalanative.libc._ | ||
import scala.scalanative.unsafe._ | ||
import mainargs.{main, ParserForMethods} | ||
|
||
object Foo { | ||
|
||
def generateHtml(text: String): CString = { | ||
val html = "<h1>" + text + "</h1>\n" | ||
|
||
implicit val z: Zone = Zone.open() | ||
val cResult = toCString(html) | ||
cResult | ||
|
||
} | ||
|
||
@main | ||
def main(text: String) = { | ||
stdio.printf(generateHtml(text)) | ||
} | ||
|
||
def main(args: Array[String]): Unit = ParserForMethods(this).runOrExit(args) | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package foo | ||
|
||
import scala.scalanative.unsafe._ | ||
import utest._ | ||
|
||
object FooTests extends TestSuite { | ||
def tests = Tests { | ||
test("simple one") { | ||
val result = Foo.generateHtml("hello") | ||
assert(fromCString(result) == "<h1>hello</h1>\n") | ||
fromCString(result) | ||
} | ||
test("simple two") { | ||
val result = Foo.generateHtml("hello world") | ||
assert(fromCString(result) == "<h1>hello world</h1>\n") | ||
fromCString(result) | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package build | ||
import mill._, scalalib._, scalanativelib._ | ||
|
||
object `package` extends RootModule with ScalaNativeModule { | ||
def scalaVersion = "3.3.4" | ||
def scalaNativeVersion = "0.5.5" | ||
|
||
object test extends ScalaNativeTests { | ||
def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.8.4") | ||
def testFramework = "utest.runner.Framework" | ||
} | ||
|
||
} | ||
|
||
|
||
// This is an example of how to use Mill to compile C code together with your Scala Native | ||
// code. | ||
// | ||
// The above build expect the following project layout: | ||
// | ||
// ---- | ||
// build.mill | ||
// src/ | ||
// foo/ | ||
// HelloWorld.scala | ||
// | ||
// resources/ | ||
// scala-native/ | ||
// HelloWorld.c | ||
// | ||
// test/ | ||
// src/ | ||
// foo/ | ||
// HelloWorldTests.scala | ||
// ---- | ||
// | ||
// *Note:* C/C++ source files need to be in `resources/scala-native` directory so | ||
// It can be linked and compiled successfully. More info from Scala Native doc | ||
// https://scala-native.org/en/stable/user/native.html#using-libraries-with-native-code[here] | ||
// and also Scala user forum https://users.scala-lang.org/t/how-to-test-scala-native-code-interop-with-c/10314/3?u=c0d33ngr[here] | ||
// | ||
// This example is pretty minimal, but it demonstrates the core principles, and | ||
// can be extended if necessary to more elaborate use cases. | ||
|
||
/** Usage | ||
|
||
> ./mill run | ||
Running HelloWorld function | ||
Done... | ||
Reversed: !dlroW ,olleH | ||
|
||
> ./mill test | ||
Tests: 1, Passed: 1, Failed: 0 | ||
|
||
*/ | ||
|
20 changes: 20 additions & 0 deletions
20
example/scalalib/native/2-interop/resources/scala-native/HelloWorld.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <stdlib.h> | ||
|
||
char* reverseString(const char *str) { | ||
int length = strlen(str); | ||
char *reversed = (char*) malloc((length + 1) * sizeof(char)); // +1 for null terminator | ||
|
||
if (reversed == NULL) { | ||
return NULL; // handle malloc failure | ||
} | ||
|
||
for (int i = 0; i < length; i++) { | ||
reversed[i] = str[length - i - 1]; | ||
} | ||
reversed[length] = '\0'; // Null-terminate the string | ||
|
||
return reversed; | ||
} | ||
|
22 changes: 22 additions & 0 deletions
22
example/scalalib/native/2-interop/src/foo/HelloWorld.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package foo | ||
|
||
import scala.scalanative.libc._ | ||
import scala.scalanative.unsafe._ | ||
import scala.scalanative.unsigned._ | ||
|
||
object Main { | ||
def main(args: Array[String]): Unit = { | ||
println("Running HelloWorld function") | ||
val reversedStr = HelloWorld.reverseString(c"Hello, World!") | ||
println("Reversed: " + fromCString(reversedStr)) | ||
stdlib.free(reversedStr) // Free the allocated memory | ||
println("Done...") | ||
} | ||
} | ||
|
||
// Define the external module, the C library containing our function "reverseString" | ||
@extern | ||
object HelloWorld { | ||
def reverseString(str: CString): CString = extern | ||
} | ||
|
20 changes: 20 additions & 0 deletions
20
example/scalalib/native/2-interop/test/src/HelloWorldTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package foo | ||
|
||
import utest._ | ||
import scala.scalanative.unsafe._ | ||
import scala.scalanative.libc.stdlib | ||
|
||
object HelloWorldTest extends TestSuite { | ||
val tests = Tests { | ||
test("reverseString should reverse a C string correctly") { | ||
val expected = "!dlroW olleH" | ||
val result = HelloWorld.reverseString(c"Hello World!") | ||
|
||
// Check if the reversed string matches the expected result | ||
assert(fromCString(result) == expected) | ||
|
||
stdlib.free(result) // Free memory after the test | ||
} | ||
} | ||
} | ||
|
8 changes: 8 additions & 0 deletions
8
example/scalalib/native/3-multi-module/bar/resources/scala-native/HelloWorldBar.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
#include <string.h> | ||
#include "bar.h" | ||
|
||
// Function to count the length of a string | ||
int stringLength(const char* str) { | ||
return strlen(str); | ||
} | ||
|
7 changes: 7 additions & 0 deletions
7
example/scalalib/native/3-multi-module/bar/resources/scala-native/bar.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
#ifndef BAR_H | ||
#define BAR_H | ||
|
||
// Declaration of the function to count string length | ||
int stringLength(const char* str); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package bar | ||
|
||
import scala.scalanative.libc._ | ||
import scala.scalanative.unsafe._ | ||
|
||
object Bar { | ||
def main(args: Array[String]): Unit = { | ||
println("Running HelloWorld function") | ||
implicit val z: Zone = Zone.open() | ||
val result = toCString(args(0)) | ||
val barValue = HelloWorldBar.stringLength(result) | ||
stdio.printf(c"Bar value: Argument length is %i\n", barValue) | ||
println("Done...") | ||
} | ||
} | ||
|
||
// Define the external module, the C library containing our function "stringLength" | ||
@extern | ||
// Arbitrary object name | ||
object HelloWorldBar { | ||
// Name and signature of C function | ||
def stringLength(str: CString): CInt = extern | ||
} | ||
|
||
|
15 changes: 15 additions & 0 deletions
15
example/scalalib/native/3-multi-module/bar/test/src/BarTests.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package bar | ||
|
||
import utest._ | ||
import scala.scalanative.unsafe._ | ||
|
||
object BarTests extends TestSuite { | ||
def tests = Tests { | ||
test("simple one") { | ||
val result = HelloWorldBar.stringLength(c"hello") | ||
assert(result == 5) | ||
result | ||
} | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package build | ||
import mill._, scalalib._, scalanativelib._ | ||
|
||
trait MyModule extends ScalaNativeModule { | ||
def scalaVersion = "3.3.4" | ||
def scalaNativeVersion = "0.5.5" | ||
|
||
object test extends ScalaNativeTests { | ||
def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.8.4") | ||
def testFramework = "utest.runner.Framework" | ||
} | ||
} | ||
|
||
object foo extends MyModule { | ||
def moduleDeps = Seq(bar) | ||
|
||
def ivyDeps = Agg(ivy"com.lihaoyi::mainargs::0.7.6") | ||
} | ||
|
||
object bar extends MyModule | ||
|
||
// This example contains a simple Mill build with two modules, `foo` and `bar`. | ||
// We don't mark either module as top-level using `extends RootModule`, so | ||
// running tasks needs to use the module name as the prefix e.g. `foo.run` or | ||
// `bar.run`. You can define multiple modules the same way you define a single | ||
// module, using `def moduleDeps` to define the relationship between them. | ||
// | ||
// Note that we split out the `test` submodule configuration common to both | ||
// modules into a separate `trait MyModule`. This lets us avoid the need to | ||
// copy-paste common settings, while still letting us define any per-module | ||
// configuration such as `ivyDeps` specific to a particular module. | ||
// | ||
// The above builds expect the following project layout: | ||
// | ||
// ---- | ||
// build.mill | ||
// bar/ | ||
// resources/ | ||
// scala-native/ | ||
// bar.h | ||
// HelloWorldBar.c | ||
// src/ | ||
// Bar.scala | ||
// test/ | ||
// src/ | ||
// BarTests.scala | ||
// foo/ | ||
// resources/ | ||
// scala-native/ | ||
// bar.h | ||
// HelloWorldFoo.c | ||
// src/ | ||
// Foo.scala | ||
// | ||
// ---- | ||
// | ||
// *Note:* C/C++ source files need to be in `resources/scala-native` directory so | ||
// It can be linked and compiled successfully. More info from Scala Native doc | ||
// https://scala-native.org/en/stable/user/native.html#using-libraries-with-native-code[here] | ||
// and also Scala user forum https://users.scala-lang.org/t/how-to-test-scala-native-code-interop-with-c/10314/3?u=c0d33ngr[here] | ||
|
||
/** Usage | ||
|
||
> ./mill bar.run hello | ||
Running HelloWorld function | ||
Done... | ||
Bar value: Argument length is 5 | ||
|
||
> ./mill bar.test | ||
Tests: 1, Passed: 1, Failed: 0 | ||
|
||
> ./mill foo.run --bar-text hello --foo-text world | ||
Foo.value: The vowel density of 'world' is 20 | ||
Bar.value: The string length of 'hello' is 5 | ||
|
||
*/ |
Oops, something went wrong.