├── .gitignore ├── README.md ├── build.sc ├── example ├── src │ └── Example.scala └── test │ ├── resources │ └── src.json │ └── src │ └── ExampleTests.scala └── mill /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | *.iml 3 | .idea 4 | .settings 5 | .classpath 6 | .project 7 | .cache 8 | .sbtserver 9 | project/.sbtserver 10 | tags 11 | nohup.out 12 | out/ 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # scala-native-example-app 2 | 3 | An example project showing how to use Scala-Native in SBT, together with third 4 | party libraries (in this case [Scalatags](https://github.com/lihaoyi/scalatags)) 5 | and a test suite (using [uTest](https://github.com/lihaoyi/utest)). 6 | 7 | ## Using this project 8 | 9 | You should be able to import this project into IntelliJ-IDEA or any other Scala 10 | IDE or editor without issue. 11 | 12 | To build an executable without running: 13 | 14 | ``` 15 | $ ./mill show example.nativeLink 16 | ... 17 | "out/example/nativeLink/dest/out" 18 | ``` 19 | 20 | To then run that executable: 21 | 22 | ``` 23 | $ out/example/nativeLink/dest/out --help 24 | JSON Reformatter 25 | Pretty-print JSON or minify it 26 | --src Source file to load JSON from; defaults to stdin if not given 27 | --dest Destination file to write JSON to; defaults to stdout if not given 28 | --indent Indentation to pretty-print the JSON with; default 4, pass -1 to minify instead 29 | 30 | $ echo [1, 2, 3] | out/example/nativeLink/dest/out --dest out.json 31 | [ 32 | 1, 33 | 2, 34 | 3 35 | ] 36 | 37 | $ echo [1, 2, 3] | out/example/nativeLink/dest/out --indent -1 38 | [1,2,3] 39 | 40 | $ echo [1, 2, 3] | out/example/nativeLink/dest/out --dest out.json 41 | 42 | $ cat out.json 43 | [ 44 | 1, 45 | 2, 46 | 3 47 | ] 48 | ``` 49 | 50 | The executable should run instantly, without the ~1s startup overhead you may be 51 | used to with Scala programs running on the JVM. 52 | 53 | ``` 54 | $ time out/example/nativeLink/dest/out --help 55 | ... 56 | real 0m0.009s 57 | user 0m0.003s 58 | sys 0m0.003s 59 | ``` 60 | 61 | To run tests: 62 | 63 | ``` 64 | $ ./mill example.test 65 | ... 66 | -------------------------------- Running Tests -------------------------------- 67 | + example.ExampleTests.minified 0ms 68 | + example.ExampleTests.indent0 0ms 69 | + example.ExampleTests.indent2 0ms 70 | ``` 71 | 72 | You can of course use the full functionality of uTest to 73 | [select which tests to run](https://github.com/lihaoyi/utest#running-tests). 74 | 75 | ## Other libraries 76 | 77 | That's all that is necessary to try using this project. Feel free to try 78 | building larger applications using Scala-Native using this template, or trying 79 | out some of the other third-party libraries that are available for Scala-Native: 80 | 81 | ```scala 82 | ivy"com.lihaoyi::utest::0.7.7" 83 | ivy"com.lihaoyi::ujson::1.2.3" 84 | ivy"com.lihaoyi::upickle::1.2.3" 85 | ivy"com.lihaoyi::os-lib::0.7.2" 86 | ivy"com.lihaoyi::sourcecode::0.2.3" 87 | ivy"com.lihaoyi::fastparse::2.3.1" 88 | ivy"com.lihaoyi::fansi::0.2.10" 89 | ivy"com.lihaoyi::scalatags::0.9.3" 90 | ivy"com.lihaoyi::pprint::0.6.1" 91 | ivy"com.lihaoyi::mainargs::0.2.1" 92 | ``` 93 | -------------------------------------------------------------------------------- /build.sc: -------------------------------------------------------------------------------- 1 | import mill._, scalalib._, scalanativelib._, scalanativelib.api._ 2 | 3 | object example extends ScalaNativeModule{ 4 | def scalaNativeVersion = "0.4.0" 5 | def scalaVersion = "2.13.4" 6 | def releaseMode = ReleaseMode.ReleaseFast 7 | def nativeLTO = LTO.Thin 8 | def ivyDeps = Agg( 9 | ivy"com.lihaoyi::ujson::1.2.3", 10 | ivy"com.lihaoyi::mainargs::0.2.1", 11 | ivy"com.lihaoyi::os-lib::0.7.2" 12 | ) 13 | object test extends Tests{ 14 | def ivyDeps = Agg(ivy"com.lihaoyi::utest::0.7.7") 15 | def testFrameworks = Seq("utest.runner.Framework") 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/src/Example.scala: -------------------------------------------------------------------------------- 1 | package example 2 | import mainargs.{TokensReader, ParserForMethods, main, arg} 3 | object Example { 4 | implicit object PathRead extends TokensReader[os.Path]( 5 | "path", 6 | strs => Right(os.Path(strs.head, os.pwd)) 7 | ) 8 | @main(name = "JSON Reformatter", doc = "Pretty-print JSON or minify it") 9 | def main(@arg(doc = "Source file to load JSON from; defaults to stdin if not given") 10 | src: Option[os.Path], 11 | @arg(doc = "Destination file to write JSON to; defaults to stdout if not given") 12 | dest: Option[os.Path], 13 | @arg(doc = 14 | "Indentation to pretty-print the JSON with; default 4, pass -1 to minify instead") 15 | indent: Int = 4) = { 16 | 17 | val inputStream = src match{ 18 | case None => System.in 19 | case Some(s) => os.read.inputStream(s) 20 | } 21 | 22 | val outputStream = dest match{ 23 | case None => System.out 24 | case Some(o) => os.write.outputStream(o) 25 | } 26 | 27 | val writer = new java.io.OutputStreamWriter(outputStream) 28 | try ujson.reformatTo(inputStream, writer, indent) 29 | finally writer.flush() 30 | } 31 | 32 | def main(args: Array[String]): Unit = ParserForMethods(Example).runOrExit(args) 33 | } 34 | -------------------------------------------------------------------------------- /example/test/resources/src.json: -------------------------------------------------------------------------------- 1 | { 2 | "person1": { 3 | "name": "Alice", 4 | "welcome": "Hello Alice!" 5 | }, 6 | "person2": { 7 | "name": "Bob", 8 | "welcome": "Hello Bob!" 9 | } 10 | } -------------------------------------------------------------------------------- /example/test/src/ExampleTests.scala: -------------------------------------------------------------------------------- 1 | package example 2 | import utest._ 3 | object ExampleTests extends TestSuite{ 4 | val tests = Tests{ 5 | 6 | val src = os.pwd / "example" / "test" / "resources" / "src.json" 7 | test("minified") { 8 | 9 | val destMinified = os.temp() 10 | Example.main(src = Some(src), dest = Some(destMinified), indent = -1) 11 | assert( 12 | os.read(destMinified) == 13 | """{"person1":{"name":"Alice","welcome":"Hello Alice!"},"person2":{"name":"Bob","welcome":"Hello Bob!"}}""" 14 | ) 15 | } 16 | test("indent0") { 17 | val destIndent0 = os.temp() 18 | Example.main(src = Some(src), dest = Some(destIndent0), indent = 0) 19 | assert( 20 | os.read(destIndent0) == 21 | """|{ 22 | |"person1": { 23 | |"name": "Alice", 24 | |"welcome": "Hello Alice!" 25 | |}, 26 | |"person2": { 27 | |"name": "Bob", 28 | |"welcome": "Hello Bob!" 29 | |} 30 | |}""".stripMargin 31 | ) 32 | } 33 | test("indent2"){ 34 | val destIndent2 = os.temp() 35 | Example.main(src = Some(src), dest = Some(destIndent2), indent = 2) 36 | 37 | assert( 38 | os.read(destIndent2) == 39 | """{ 40 | | "person1": { 41 | | "name": "Alice", 42 | | "welcome": "Hello Alice!" 43 | | }, 44 | | "person2": { 45 | | "name": "Bob", 46 | | "welcome": "Hello Bob!" 47 | | } 48 | |}""".stripMargin 49 | ) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /mill: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # This is a wrapper script, that automatically download mill from GitHub release pages 4 | # You can give the required mill version with MILL_VERSION env variable 5 | # If no version is given, it falls back to the value of DEFAULT_MILL_VERSION 6 | DEFAULT_MILL_VERSION=0.9.5-7-f9a698 7 | 8 | set -e 9 | 10 | if [ -z "$MILL_VERSION" ] ; then 11 | if [ -f ".mill-version" ] ; then 12 | MILL_VERSION="$(head -n 1 .mill-version 2> /dev/null)" 13 | elif [ -f "mill" ] && [ "$BASH_SOURCE" != "mill" ] ; then 14 | MILL_VERSION=$(grep -F "DEFAULT_MILL_VERSION=" "mill" | head -n 1 | cut -d= -f2) 15 | else 16 | MILL_VERSION=$DEFAULT_MILL_VERSION 17 | fi 18 | fi 19 | 20 | MILL_DOWNLOAD_PATH="$HOME/.mill/download" 21 | MILL_EXEC_PATH="${MILL_DOWNLOAD_PATH}/$MILL_VERSION" 22 | 23 | if [ ! -x "$MILL_EXEC_PATH" ] ; then 24 | mkdir -p $MILL_DOWNLOAD_PATH 25 | DOWNLOAD_FILE=$MILL_EXEC_PATH-tmp-download 26 | MILL_DOWNLOAD_URL="https://github.com/lihaoyi/mill/releases/download/${MILL_VERSION%%-*}/$MILL_VERSION-assembly" 27 | curl --fail -L -o "$DOWNLOAD_FILE" "$MILL_DOWNLOAD_URL" 28 | chmod +x "$DOWNLOAD_FILE" 29 | mv "$DOWNLOAD_FILE" "$MILL_EXEC_PATH" 30 | unset DOWNLOAD_FILE 31 | unset MILL_DOWNLOAD_URL 32 | fi 33 | 34 | unset MILL_DOWNLOAD_PATH 35 | unset MILL_VERSION 36 | 37 | exec $MILL_EXEC_PATH "$@" 38 | --------------------------------------------------------------------------------