Статьи

Начало работы с scala-native

Это просто быстрое воспоминание о шагах, которые я предпринял, чтобы запустить свой собственный helloworld, используя scala-native. На самом деле я еще не начал подробно рассматривать родной язык scala, но идея, стоящая за ним, действительно хороша. Некоторые общие сведения о scala-native можно найти здесь:

Поскольку scala-native зависит от доступности LLVM и Clang ++, эта настройка может отличаться в вашей среде, чем в моей. Я все еще на OS-X Yosemite:

1
2
3
4
$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.10.3
BuildVersion:   14D136

Но для пользователей Mac шаги будут примерно такими же. Теперь давайте приступим к настройке среды, чтобы вы могли запустить пример проекта, предоставляемого scala-native, и мы также создадим базовый проект helloworld. Еще раз, эти шаги работали в моей среде, и ваши могут отличаться. Есть несколько проблем с github, за которыми вы можете следить или узнать больше о том, как настроить вашу среду.

Шаги, которые работали для меня, были следующие:

Проверка кода

Нам, конечно, сначала нужно получить код, из командной строки сделаем следующее:

1
2
3
4
5
6
7
$ git clone --recursive https://github.com/scala-native/scala-native
Cloning into 'scala-native'...
remote: Counting objects: 8295, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 8295 (delta 3), reused 0 (delta 0), pack-reused 8278
Receiving objects: 100% (8295/8295), 1.31 MiB | 94.00 KiB/s, done.
Resolving deltas: 100% (2955/2955), done.

Это должно, теоретически, получить вам все необходимые источники. Я, однако, столкнулся с первой проблемой, что субмодельная скала не вытащила правильно. Каким-то образом git хочет использовать аутентификацию с открытым ключом вместо https. Самый простой способ быстро решить эту проблему, просто сделать это:

01
02
03
04
05
06
07
08
09
10
11
12
$ cd scala-native/submodules
$ git clone https://github.com/scala/scala
Cloning into 'scala'...
remote: Counting objects: 333614, done.
remote: Total 333614 (delta 0), reused 0 (delta 0), pack-reused 333613
Receiving objects: 100% (333614/333614), 83.31 MiB | 5.63 MiB/s, done.
Resolving deltas: 100% (226320/226320), done.
Checking connectivity... done.
Checking out files: 100% (10492/10492), done.
  
$ cd scala
$ git checkout 2.11.x

Публикуйте библиотеки локально

На данный момент у вас есть все необходимые источники, но при попытке его создать вы можете столкнуться со следующими проблемами:

1
2
3
4
5
6
7
8
# from the scala-native directory
$ sbt
> publish-local
... lots of output
[trace] Stack trace suppressed: run last scalalib/compile:compileIncremental for the full output.
[trace] Stack trace suppressed: run last javalib/compile:doc for the full output.
[error] (scalalib/compile:compileIncremental) java.lang.NoClassDefFoundError: scala/scalanative/nscplugin/NirGlobalAddons$nirPrimitives$
[error] (javalib/compile:doc) java.nio.charset.MalformedInputException: Input length = 1

Почему-то, кажется, что-то не так с некоторыми скалярными вещами, что приводит к провалу нашего проекта. Откройте файл build.sbt и измените проект javalib . Чтобы решить эту проблему, мы можем просто отключить скалярные вещи, например, добавив следующие две строки:

1
2
sources in (Compile,doc) := Seq.empty,
publishArtifact in packageDoc := false

Сюда:

1
2
3
4
5
6
7
83 lazy val javalib =
84   project.in(file("javalib")).
85     settings(libSettings,
86       sources in (Compile,doc) := Seq.empty,
87       publishArtifact in packageDoc := false
88     ).
89     dependsOn(nativelib)

Теперь снова выполните локальную публикацию, и это должно как минимум успешно завершиться:

1
2
3
4
5
> reload
> publish-local
... again, lots of output
[info]  published ivy to /Users/jos/.ivy2/local/org.scala-native/scalalib_2.11/0.1-SNAPSHOT/ivys/ivy.xml
[success] Total time: 17 s, completed May 14, 2016 4:06:31 PM

На данный момент мы можем попытаться запустить демонстрационное приложение, но вы, вероятно, столкнетесь со следующими двумя ошибками: (по крайней мере, я сделал)

1
2
3
4
5
6
7
8
# This one:
/Users/jos/dev/git/scala-native-clean/scala-native/demo-native/target/scala-2.11/demonative-out.ll:152:40: error: expected '{' in function body
declare double @"llvm.sqrt.f64"(double)
                                       ^
  
# And this one
rt.cpp:3:10: fatal error: 'gc.h' file not found
#include <gc.h>

Ах … плохо. Что-то еще пошло не так. Первая ошибка вызвана неправильной версией LLVM (требуется 3.7, у меня версия 3.6), а вторая — тем, что библиотеки Boehm GC недоступны.

Настройте LLVM и Clang ++ правильно

Я не знаю, какая версия на более новых версиях OS-X, но у меня все еще было 3.6:

1
2
3
4
$ clang++ -v
Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

Чтобы это исправить, не вмешиваясь, возможно, в другие инструменты, в зависимости от 3.6, я использовал brew для установки 3.7 версии LLVM и Clang ++. Возможно, вам придется сначала сделать ** brew tap homebrew / version **, если вы не можете найти llvm37

01
02
03
04
05
06
07
08
09
10
11
12
$ brew install llvm37 --with-clang
==> Installing llvm37 from homebrew/versions
==> Downloading https://homebrew.bintray.com/bottles-versions/llvm37-3.7.1.yosemite.bottle.1.tar.gz
Already downloaded: /Library/Caches/Homebrew/llvm37-3.7.1.yosemite.bottle.1.tar.gz
==> Pouring llvm37-3.7.1.yosemite.bottle.1.tar.gz
==> Caveats
Extra tools are installed in /usr/local/opt/llvm37/share/clang-3.7
  
To link to libc++, something like the following is required:
  CXX="clang++-3.7 -stdlib=libc++"
  CXXFLAGS="$CXXFLAGS -nostdinc++ -I/usr/local/opt/llvm37/lib/llvm-3.7/include/c++/v1"
  LDFLAGS="$LDFLAGS -L/usr/local/opt/llvm37/lib/llvm-3.7/lib"

Вы можете увидеть каталог, в котором установлены Clang и LLVM. Прежде чем мы снова запустим SBT, нам нужно создать символическую ссылку, чтобы плагин мог найти правильный исполняемый файл clang .

1
2
$ cd /usr/local/opt/llvm37/bin
$ ln -s clang++-3.7 clang++

И, наконец, нам просто нужно обновить переменную PATH, чтобы она указала на каталог установки перед запуском SBT :

1
2
3
4
5
$ export PATH=/usr/local/opt/llvm37/bin:$PATH
$ clang++ -v
clang version 3.7.1 (tags/RELEASE_371/final)
Target: x86_64-apple-darwin14.3.0
Thread model: posix

На данный момент у нас должна быть одна из наших проблем, поэтому давайте просто проверим, что произойдет, если мы попробуем запустить демо:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<br/>
# go back to the directory where you cloned scala-native
$ cd ~/dev/git/scala-native-clean/scala-native
$ sbt
> demoNative/run
[info] Updating {file:/Users/jos/dev/git/scala-native-clean/scala-native/}demoNative...
[info] Resolving org.scala-lang#scalap;2.11.8 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/jos/dev/git/scala-native-clean/scala-native/demo-native/target/scala-2.11/classes...
warning: overriding the module target triple with x86_64-apple-macosx10.10.0 [-Woverride-module]
1 warning generated.
/Users/jos/.scalanative/rtlib-0.1-SNAPSHOT/rt.cpp:3:10: fatal error: 'gc.h' file not found
#include <gc.h>
        ^
1 error generated.

Как видите, у нас на одну ошибку меньше, но все равно что-то не так

Установить библиотеку Boehm GC

Чего не хватает и на что указывает ошибка, так это библиотеки Boehm GC. Есть несколько способов установить это. Мы можем использовать предварительно упакованный экземпляр brew или просто загрузить исходные тексты напрямую и установить Boehm таким образом. В этом примере мы сделаем последнее. Это означает, что следуйте инструкциям здесь: http://hboehm.info/gc/

01
02
03
04
05
06
07
08
09
10
11
$ mkdir boehm
$ cd boehm
$ git clone https://github.com/ivmai/libatomic_ops.git
$ git clone https://github.com/ivmai/bdwgc.git
$ cd bdgwc
$ ln -s ../libatomic_ops
$ autoreconf -vif
$ automake --add-missing
$ ./configure
$ make
$ sudo make install

Кроме того, вы также можете установить пакет bdw-gc в brew.

1
$ brew install bdw-gc

И после этого добавьте следующий build.sbt в демонстрационный проект с дополнительными настройками clang:

1
2
$ cat build.sbt
nativeClangOptions := Seq("-I/usr/local/Cellar/bdw-gc/7.4.2/include", "-L/usr/local/Cellar/bdw-gc/7.4.2/lib")

Однако я предпочитаю установку из источника *. На данный момент мы должны запустить демо.

1
2
3
4
> demoNative/run
warning: overriding the module target triple with x86_64-apple-macosx10.10.0 [-Woverride-module]
1 warning generated.
Rendering (8 spp) 100.00%[success] Total time: 13 s, completed May 14, 2016 6:30:42 PM

Woohoo … успех !!! Чтобы увидеть, что мы на самом деле выполняем код, сделаем небольшое изменение в источнике в каталоге demoNative. В файле smallpt.scala измените количество семплов на 8 следующим образом:

1
2
3
4
153   final val W = 800
154   final val H = 600
155   final val SAMPLES = 8
156   def main(args: Array[String]): Unit = {

Теперь запустите программу снова (что должно занять намного больше времени):

1
2
3
4
5
> demoNative/run
[info] Compiling 1 Scala source to /Users/jos/dev/git/scala-native-clean/scala-native/demo-native/target/scala-2.11/classes...
warning: overriding the module target triple with x86_64-apple-macosx10.10.0 [-Woverride-module]
1 warning generated.
Rendering (32 spp) 100.00%[success] Total time: 52 s, completed May 14, 2016 6:34:11 PM

Кажется, это работает. Кстати, результатом этой программы является трехмерная отрисованная сцена (пример программы — raytracer). Если вы установите большое количество сэмплов, вы получите довольно хороший рендер:

Мы также можем проверить, является ли вывод настоящей нативной программой:

1
2
3
4
5
otool -L demonative-out
demonative-out:
    /usr/local/lib/libgc.1.dylib (compatibility version 2.0.0, current version 2.3.0)
    /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)

Теперь давайте создадим пустой проект helloworld, где мы создадим собственную минимальную программу native-scala.

Helloworld scala-native

В проекте scala-native создайте новый каталог с именем helloworld-native. В этом каталоге создайте следующий файл (** helloworld.scala **):

01
02
03
04
05
06
07
08
09
10
package helloworld
  
import scalanative.native._, stdlib._
  
object Main {
  
  def main(args: Array[String]): Unit = {
    fprintf(__stdoutp, c"Hello World: Scala Native!!!")
  }
}

Прежде чем мы сможем запустить его, нам также необходимо обновить основной файл build.sbt и определить этот проект. Для этого добавьте следующее:

1
2
3
4
5
6
7
8
lazy val helloworldNative =
  project.in(file("helloworld-native")).
    settings(libSettings).
    settings(
      nativeVerbose := true,
      nativeClangOptions := Seq("-O2")
    ).
    dependsOn(scalalib)

Не забудьте использовать Seq («- I / usr / local / Cellar / bdw-gc / 7.4.2 / include», «-L / usr / local / Cellar / bdw-gc / 7.4.2 / lib») для Ваше определение сборки helloworld, если вы не устанавливаете Boehm GC с нуля.

Теперь перезагрузите sbt, и вы сможете запустить наше собственное scala-native приложение:

1
2
3
4
5
> helloworldNative/run
[info] Compiling 1 Scala source to /Users/jos/dev/git/scala-native-clean/scala-native/helloworld-native/target/scala-2.11/classes...
warning: overriding the module target triple with x86_64-apple-macosx10.10.0 [-Woverride-module]
1 warning generated.
Hello World: Scala Native!!!

Или мы можем просто запустить его из командной строки напрямую:

1
2
3
4
$ pwd
/Users/jos/dev/git/scala-native-clean/scala-native/helloworld-native/target/scala-2.11
$ ./helloworldnative-out
Hello World: Scala Native!!!

Я надеюсь, что вы также можете начать с этого краткого вступления. Если позволит время, я планирую немного глубже погрузиться в родной язык scala и изучить некоторые его особенности.

Ссылка: Начало работы с scala-native от нашего партнера JCG Йоса Дирксена в блоге Smart Java .