julia in FreeBSD

前回だったか前々回だったか、FreeBSD 10.2にjuliaを入れようとして、あえなく撃沈した。 くやしいので、リベンジしてみる。

前回の失敗の原因は、コンパイル時間を短縮しようとして、llvmを備え付けのやつで流用 してしまった事にある。

膨大なコンパイル時間がかかる事を覚悟の上、llvmを気の済むように作ってもらった。 大体1.5時間ぐらいかかりましたかねぇ。

後はすんなり行くかと思ったら、blasもFreeBSDのpkgから持ってきたやつではお気にめさない よう。お前の好きにしろって指示したら、openblasを勝手に取って来てコンパイルを 始めたんだけど、途中でエラー。

ちゃんと記録を取っていなかったんで、うろ覚えだけどblas_server.cで、includeファイルの指定をしてる所で、 FreeBSDの宣言が抜けてて、すっとばされ、盛大にこけてた。そこを修正して、やはり待つ事、 1.5時間ぐらい。

これで行けるかと思ったら、悪夢が再現。

REPLCompletions.jl
REPL.jl
client.jl
util.jl
error during bootstrap:
LoadError(at "sysimg.jl" line 238: LoadError(at "util.jl" line 234: ErrorException("error compiling blas_vendor: could not load library "libopenblas"
/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc48/libgfortran.so.3 not found")))
rec_backtrace at /usr/home/sakae/src/julia-0.4.3/usr/bin/../lib/libjulia.so (unknown line)
jl_throw at /usr/home/sakae/src/julia-0.4.3/usr/bin/../lib/libjulia.so (unknownline)
   :

いい所まで来たんですがね。

gmake FC='gfortran48 -Wl,-rpath=/usr/local/lib/gcc48 '

このおまじないが効く範囲って限定的? これに気が付いたのは、fortran系のモジュールの configure中で、簡単な実行ファイルを作成出来るか試験してる部分があったんだけど、 それがこけてて、モジュール作成が出来なかった時に発見した裏技。

しょうがないので、 (Unix系OSの掟) LD_LIBRARY_PATHは最後の武器だから、濫用してはいけない とか ライブラリとは何なのか? なんてので、魔法の世界を再確認。

最後の砦の

$ export LD_LIBRARY_PATH=/usr/local/lib/gcc48

を発動。これで、やっとコンパイル完了。julia-0.4.3の作業Dir容量は、1.2Gになりましたよ。 そのうち依存関係者が入るdepsの容量が986M。出来上がったjulia群は170M(LLVMを含む) Make.incで節約したのは

USE_SYSTEM_LIBM=1
USE_SYSTEM_FFTW=1
USE_SYSTEM_GMP=1
USE_SYSTEM_MPFR=1

だけだった。

$ ./julia
WARNING: Error during initialization of module LinAlg:
ErrorException("could not load library "libopenblas"
/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc48/libgfortran.so.3 not found")
WARNING: Error during initialization of module CHOLMOD:
ErrorException("could not load library "libcholmod"
Shared object "libcholmod" not found, required by "julia"")
               _
   _       _ _(_)_     |  A fresh approach to technical computing
  (_)     | (_) (_)    |  Documentation: http://docs.julialang.org
   _ _   _| |_  __ _   |  Type "?help" for help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 0.4.3
 _/ |\__'_|_|_|\__'_|  |
|__/                   |  i386-portbld-freebsd10.1

julia>

LD_LIBRARY_PATHの設定をしなくても、警告が出て来るだけで、一応起動はする。 と思ったら、

julia> versioninfo()
Julia Version 0.4.3
Platform Info:
  System: FreeBSD (i386-portbld-freebsd10.1)
  CPU: Intel(R) Celeron(R) CPU          900  @ 2.20GHz
  WORD_SIZE: 32
ERROR: could not load library "libopenblas"
/lib/libgcc_s.so.1: version GCC_4.6.0 required by /usr/local/lib/gcc48/libgfortran.so.3 not found
 in openblas_get_config at ./util.jl:239
 in versioninfo at interactiveutil.jl:188
 in versioninfo at interactiveutil.jl:158

案の定、まともに動かない。しょうがないので、

alias julia='LD_LIBRARY_PATH=/usr/local/lib/gcc48 /home/sakae/src/julia-0.4.3/julia'

こんなエイリアスを設定、

julia> versioninfo()
Julia Version 0.4.3
Platform Info:
  System: FreeBSD (i386-portbld-freebsd10.1)
  CPU: Intel(R) Celeron(R) CPU          900  @ 2.20GHz
  WORD_SIZE: 32
  BLAS: libopenblas (DYNAMIC_ARCH NO_AFFINITY Penryn)
  LAPACK: libopenblas
  LIBM: libm
  LLVM: libLLVM-3.3

ちゃんとFreeBSD印も押してあるし、まずは目出度い。あれ? juliaを普通の言語系として 使わないの? ええ、replから使うものだと割り切りました。だって、スクリプトを実行 させるのにやれJITとかやらかしてくれると、イライラが募りますから。

FreeBSDでLinuxのエミュレーション

もう一つリベンジが残っていた。過去にOpenBSDやらNetBSDのLinuxエミュレーションを使って、 gdbserverが動くかやった。結果、あえなく撃沈。あれは特殊なアプリだっから?

今回は普通のアプリ、Linux側のJuliaをFreeBSD側に持ってきて動くか、確認してみたい。 ええ、Julia開発陣の気まぐれで、FreeBSDの対応が打ち切られても、あたふたしないように 、逃げ道を確認しておきたいと思って。。。

man linuxすればあらかたの事が分かる。最初juliaだけを持ってきて試そうかと思ったけど、 素直にLinuxのBedを用意する事にした。どんなのがあるか、取りあえず確認。

$ pkg search linux_base
linux_base-c6-6.6_6            Base set of packages needed in Linux mode for i386/amd64 (Linux CentOS 6)
linux_base-f10-10_9            Base set of packages needed in Linux mode for i386/amd64 (Linux Fedora 10)

Cent6の方が新しいだろうって理由で選んだら、約170MぐらいDisk容量が必要との事。 忘れずにkldload linuxしておく。

$ kldstat
Id Refs Address    Size     Name
 1   12 0xc0400000 13ed81c  kernel
 2    1 0xc4b9e000 4000     fdescfs.ko
 3    1 0xc4d28000 4000     uhid.ko
 4    1 0xc5fa1000 4a000    linux.ko

後は、Fedoraからlibを持ってきて、/compat/linux/usr/libの下に入れる。念のためLinuxの 儀式を行う。

$ /compat/linux/sbin/ldconfig -r /compat/linux

そして実行。

$ /compat/linux/usr/bin/julia
/compat/linux/usr/bin/julia: relocation error: /usr/lib/libc.so.6: symbol _dl_starting_up, version GLIBC_PRIVATE not defined in file ld-linux.so.2 with link time reference

おかしいなってんで、 10.2. インストール を見直し。

$ ldd /compat/linux/usr/bin/julia
/compat/linux/usr/bin/julia:
        libjulia.so => /usr/lib/libjulia.so (0x2806f000)
        libdl.so.2 => /lib/libdl.so.2 (0x2820f000)
        librt.so.1 => /lib/librt.so.1 (0x28214000)
        libpthread.so.0 => /lib/libpthread.so.0 (0x2821d000)
        libunwind-x86.so.8 => /usr/lib/libunwind-x86.so.8 (0x28238000)
        libunwind.so.8 => /usr/lib/libunwind.so.8 (0x28251000)
        libz.so.1 => /lib/libz.so.1 (0x28267000)
        libffi.so.6 => /usr/lib/libffi.so.6 (0x2827b000)
        libLLVM-3.3.so => /usr/lib/libLLVM-3.3.so (0x28283000)
        libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x29889000)
        libm.so.6 => /lib/libm.so.6 (0x29a03000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x29a2d000)
        libc.so.6 => /usr/lib/libc.so.6 (0x29a4c000)
        libutf8proc.so.1 => /usr/lib/libutf8proc.so.1 (0x29c19000)
        /lib/ld-linux.so.2 (0x2804c000)

ちなみにFreeBSDの方は、

$ ldd src/julia-0.4.3/usr/bin/julia
src/julia-0.4.3/usr/bin/julia:
        libjulia.so => /usr/home/sakae/src/julia-0.4.3/usr/bin/../lib/libjulia.so (0x28400000)
        libelf.so.1 => /usr/lib/libelf.so.1 (0x28078000)
        libkvm.so.6 => /lib/libkvm.so.6 (0x2808e000)
        librt.so.1 => /usr/lib/librt.so.1 (0x28097000)
        libstdc++.so.6 => /usr/local/lib/gcc48/libstdc++.so.6 (0x2809d000)
        libm.so.5 => /lib/libm.so.5 (0x28189000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x281b0000)
        libc.so.7 => /lib/libc.so.7 (0x281bc000)
        libz.so.6 => /lib/libz.so.6 (0x28331000)
        libthr.so.3 => /lib/libthr.so.3 (0x28345000)

構成が違うね。FreeBSDでちゃんとJITが効いてくれるか、思わず確かめちゃったぞ。

それはいいとして、ここに至るまで、

$ /compat/linux/usr/bin/julia
FATAL: kernel too old

とか言われたので、

$ sudo sysctl -w compat.linux.osrelease=2.6.32
compat.linux.osrelease: 2.6.18 -> 2.6.32

無理してLinuxのバージョンを上げた。で、上の結果になった。諦めきれないオイラーは、 ld-linux.so.2をヒントに、

$ ls -l /compat/linux/lib/ld-*
-rwxr-xr-x  1 root   wheel  141144 Jan 31 10:16 /compat/linux/lib/ld-2.12.so*
-rwxr-xr-x  1 sakae  wheel  159928 Mar  4 16:11 /compat/linux/lib/ld-2.22.so*
lrwxr-xr-x  1 root   wheel      10 Mar  4 16:26 /compat/linux/lib/ld-linux.so.2@ -> ld-2.12.so
lrwxr-xr-x  1 root   wheel      13 Feb 22  2013 /compat/linux/lib/ld-lsb.so.3@ -> ld-linux.so.2

で、ld-linux.so.2のリンク先を、Fedoraのそれ、ld-2.22.soに付け替えたんだ。そしたら、

$ /compat/linux/usr/bin/julia
Segmentation fault (core dumped)
$ ldd /compat/linux/usr/bin/julia
/compat/linux/usr/bin/julia:
/compat/linux/usr/bin/julia: signal 11

状況は悪化しましたよ。Fedora23なんて、時代の最先端な実験Linux(そうさ、オイラーは赤帽 さんのモルモットを喜んで務めております)、そして実用のRedHat版のLinxuが出て、それの クローンがCentOS。だから、無理はきかないのね。討ち死にじゃーー。 まあ、LinuxのBedにしたやつは、Linux CentOS 6.5 meta port. らしいですから。

file julia

と、まあ無駄骨でしたねぇ。結局エミュレーション関連は綺麗さっぱりと削除しました。 この環境で、fedoraから持ってきたjuliaは、FreeBSDにはどう映るか確認。

$ ./julia
ELF binary type "0" not known.
./julia: Exec format error
$ file julia
julia: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=ea81d90f90b6a7dd581f6cce55f07d613433bb2d, stripped

実行しようとすると、そんな異物は知らんと免疫機能が働いています(当然)。でも、fileコマンドで 相手の素性を調査してみると、ちゃんとどのLinuxバージョン上でコンパイルされたかを 含めて、DNAが残っているようです。あれ? ELFファイルにOSのバージョン番号なんて付与 されてたっけ? 調べてみれって事で、まずは file コマンドを参照。 続いて、ソース嫁。

たまたまNetBSDが立ち上がっているので、 /usr/src/external/bsd/file/dist/srcを参照。多分見るべきファイルはreadelf.c。

 472private size_t
 473donote(struct magic_set *ms, void *vbuf, size_t offset, size_t size,
 474    int clazz, int swap, size_t align, int *flags)
  :
 541                if (file_printf(ms, ", for GNU/") == -1)
 542                        return size;
 543                switch (elf_getu32(swap, desc[0])) {
 544                case GNU_OS_LINUX:
 545                        if (file_printf(ms, "Linux") == -1)
 546                                return size;
 547                        break;
  :
 568                if (file_printf(ms, " %d.%d.%d", elf_getu32(swap, desc[1]),
 569                    elf_getu32(swap, desc[2]), elf_getu32(swap, desc[3])) == -1 )
 570                        return size;

どうも関数名、donoteなんて言う名前が怪しい。readelf.hを見たら

typedef struct elf_note {
    Elf32_Word  n_namesz;       /* Name size */
    Elf32_Word  n_descsz;       /* Content size */
    Elf32_Word  n_type;         /* Content type */
} Elf32_Nhdr;

/*
 * GNU executables (name = "GNU")
 * word[0]: GNU OS tags
 * word[1]: major version
 * word[2]: minor version
 * word[3]: tiny version
 */

次はは、readelfの出番だ。

Notes at offset 0x00000168 with length 0x00000020:
  Owner                 Data size       Description
  GNU                  0x00000010       NT_GNU_ABI_TAG (ABI version tag)
    OS: Linux, ABI: 2.6.32

Notes at offset 0x00000188 with length 0x00000024:
  Owner                 Data size       Description
  GNU                  0x00000014       NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: ea81d90f90b6a7dd581f6cce55f07d613433bb2d

readelf.cには、FreeBSD用のdonote表示コードも掲載されてたけど、version4から5の頃は、 がたがたしてたみたいで、それを吸収するコードが無様に組み込んであった。fileの作者さん、 どうもスマソ。

乗り掛けた船なんで、もうちょっと調べてみる。そもそもfileコマンドは寄贈ソフトを FreeBSDもNetBSDも採用してる。OpenBSDにはソース上言及していない。 ならば、fileコマンドはOpenBSDの事をほとんど知らないはず。

例としてOpenBSD用のfileコマンドをFreeBSDに持ってきて、どういう報告をするか確認。

$ file file
file: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /usr/libexec/ld.so, for OpenBSD, stripped
$ readelf -a file
   :
No version information found in this file.

Displaying notes found at file offset 0x000001e8 with length 0x00000030:
  Owner                 Data size       Description
  OpenBSD              0x00000004       NT_VERSION (version)
  OpenBSD              0x00000004       NT_VERSION (version)

やはり、OpenBSDなんて、オラ白根って言ってきた。

FreeBSDに持って行ったjuliaは

[ob: ~]$ file julia
julia: ELF 32-bit LSB executable, Intel 80386, version 1, for GNU/Linux 2.6.32, dynamically linked (uses shared libs), stripped

ちゃんと表示してくれた。

OpenBSDのfileコマンドソースは、正統な場所(/usr/src/usr.bin/file)に収められている。 READMEを読むと、freeware扱いのソースを取ってきて、OpenBSD用に改変したよって書いてる。 面白いな。

julia in NetBSD

無謀にもjuliaがNetBSDに入るか挑戦してみた。まずは下準備って事で、 gtar,cmake,gcc48(for gfortran)を入れてあげる。設定はFreeBSDのそれを継承する。

nb7$ gmake FC=gfortran
  CC       src/unix/libuv_la-netbsd.lo
src/unix/netbsd.c: In function 'uv_get_free_memory':
src/unix/netbsd.c:104:17: error: storage size of 'info' isn't known
   struct uvmexp info;
                 ^
Makefile:1915: recipe for target 'src/unix/libuv_la-netbsd.lo' failed
gmake[3]: *** [src/unix/libuv_la-netbsd.lo] Error 1
Makefile:830: recipe for target 'all' failed
gmake[2]: *** [all] Error 2
Makefile:757: recipe for target 'libuv-efb40768b7c7bd9f173a7868f74b92b1c5a61a0e/.libs/libuv.la' failed
gmake[1]: *** [libuv-efb40768b7c7bd9f173a7868f74b92b1c5a61a0e/.libs/libuv.la] Error 2
Makefile:51: recipe for target 'julia-deps' failed
gmake: *** [julia-deps] Error 2

ぐぐったら、こんなのを入れるといいよってのが遭った。

#include <uvm/uvm_extern.h> 

ここまではいいんだけど、llvmのインストールの所でコケル。ぐぐる先生に聞いてみても、 エラー報告は有るものの解決策は全く無い。そんじゃ、NetBSDのpkgになってるllvmはどうやってるか 調べてみるか。こういう時はpatch集を見るに限るな。

2つのMakefileにパッチが当っていた。内容はNetBSDは蚊帳の外だからFreeBSDと同様に扱って くれよなーって物。同等のpatchを手で当ててみたけど、やはりエラー。

だったら、pkgのllvmを使ってあげればいいじゃんって事にしたよ。えっちらおっちらと巨大な clangパッケージをインストール。そしてコンパイルを再回。

今度は、openblsaの所でコケタ。エラー内容は、リンクが解決出来ないってやつ。これもぐぐる 先生に聞いてみた。やはりエラーの報告は有るものの、使い方を限定しろってもの。 そうしたら、多分juliaとしては成り立たなくなるんで、潔く撤退する事にした。

後に残るはclangよ。これはきっと、llvmに手を出してみろって事なんだろうな。

etc

わずか600円台のコンピューター「Raspberry Pi Zero」が登場

Rustで書いた自作OSをRaspberry Pi Zeroで動かす

Raspberry Pi 3」が登場

何、64Bitで4コアだって! 何と言う凄まじさ。オイラーの所の旧石器は、もう暫く 寝かせておくと、何でも鑑定団に出品出来るぞ。32Bit、シングルコア、昔の人は こういう石器で頑張っていたんですねぇ。大切に保存しておきましょう。 そのうちに、国立科学博物館から高値で引き取りたいと言ってきますから。