Julia debug, LLVM

前回は、ひょんな事からllvmを入れるはめになった。Juliaでも使われている。勿論、FreeBSDにも 使われている。gccの代わりにね。

llvmはいろいろな言語をコンパイル出来るような作りになってる。C語をコンパイル出来るように フロントを整えたものをclang(シランと発音するそうだ。恐い化合物だぞ)と特別に呼んでいる。

julia語をJITコンパイルするために、juliaでは重要な役割を果たしている。juliaにおいてllvmは どう使われるか? libLLVMのどこかが呼ばれるはず。

えと、ライブラリーをトレースするコマンドが有ったな。 ltraceを調べたよ FreeBSDにもシステムユーティリティにltraceは有るんだけど、64Bitマシンしかサポート していない。旧石器人は肩身が狭いですよ。そんな訳で、fedoraです。特殊な事してる のかな。まあいい。

簡単なスクリプトを実行して、トレース。

[sakae@fedora ~]$ ltrace julia -e 'println(factor(987654321))'
__libc_start_main([ "julia", "-e", "println(factor(987654321))" ] <unfinished ...>
uv_setup_args(3, 0xbfe0ccf4, 0x804a649, 0x804906a) = 0x86e6538
libsupport_init(3, 0xbfe0ccf4, 0x804a649, 0x804906a) = 0x86e6ff0
getopt_long(3, 0xbfe0ccf4, "+vhqFfH:e:E:P:L:J:C:ip:Ob:", 0x804d0e0, nil) = 101
__strdup(0xbfe0e1f6, 0xbfe0ccf4, 0x804a744, 0x804d0e0) = 0x86e7078
getopt_long(3, 0xbfe0ccf4, "+vhqFfH:e:E:P:L:J:C:ip:Ob:", 0x804d0e0, nil) = -1
julia_init(1, 0xbfe0cc64, 0x804a649, 0x804906a <no return ...>
--- SIGCHLD (Child exited) ---
<... julia_init resumed> )                       = 0
jl_symbol(0x804a705, 0xbfe0cb28, 0xb767e000, 0xbfe0cb48) = 0x935299d4
jl_get_global(0x935c8160, 0x935299d4, 0xb767e000, 0xbfe0cb48) = 0x94fad5a0
jl_array_grow_end(0x94fad5a0, 0, 0xb767e000, 0xbfe0cb48) = 0x94fad5a0
jl_symbol(0x804a711, 0, 0xb767e000, 0xbfe0cb48)  = 0x9353921c
jl_get_global(0x935c8160, 0x9353921c, 0xb767e000, 0xbfe0cb48) = 0x950c2a30
Dict(17=>2,379721=>1,3=>2)
jl_atexit_hook(0, 0xbfe0cc64, 0x804a649, 0x804906a) = 0
+++ exited (status 0) +++

えっ、なんか中抜けしてないか。小供がどうこう言ってるし。小供も追跡するように、-f オプションを加えてみる。

[sakae@fedora ~]$ ltrace -o LOG -n 2 -f julia -e 'println(factor(987654321))'
Couldn't find .dynsym or .dynstr in "/proc/1973/exe"
[sakae@fedora ~]$ lv LOG
1972 __libc_start_main([ "julia", "-e", "println(factor(987654321))" ] <unfinished ...>
1972   uv_setup_args(3, 0xbf9fcbc4, 0x804a649, 0x804906a) = 0x9aa6538
1972   libsupport_init(3, 0xbf9fcbc4, 0x804a649, 0x804906a) = 0x9aa6ff0
1972   getopt_long(3, 0xbf9fcbc4, "+vhqFfH:e:E:P:L:J:C:ip:Ob:", 0x804d0e0, nil)101
1972   __strdup(0xbf9fe1f6, 0xbf9fcbc4, 0x804a744, 0x804d0e0) = 0x9aa7078
1972   getopt_long(3, 0xbf9fcbc4, "+vhqFfH:e:E:P:L:J:C:ip:Ob:", 0x804d0e0, nil)= -1
1972   julia_init(1, 0xbf9fcb34, 0x804a649, 0x804906a <no return ...>
1973 --- Called exec() ---
1973 __libc_start_main([ "sh", "-c", "/sbin/ldconfig -p" ] <unfinished ...>
1973   __sigsetjmp(0x8019cf60, 0, 0, 4096)       = 0
  :
1973   execve(0x81345210, 0x813452a0, 0x81343aa8, 0x81345250 <no return ...>
1973 --- Called exec() ---

どうも肝心な所が見えないですなあ。

lsof -c julia ってして、待機してるjuliaのライブラリィー使用状況を調べると、 ちゃんとlibLLVMも開いている。

しょうがないので、julia-debug用に下記をインストール

 julia-debuginfo             i686      0.4.3-1.fc23            nalimilan-julia        4.6 M
 libffi-debuginfo            i686      3.1-8.fc23              fedora-debuginfo       115 k
 libunwind-debuginfo         i686      1.1-10.fc23             fedora-debuginfo       222 k
 llvm-debuginfo              i686      3.7.0-4.fc23            updates-debuginfo      570 M
 utf8proc-debuginfo          i686      1.3-1.fc23              nalimilan-julia         86 k
 zlib-debuginfo              i686      1.2.8-9.fc23            fedora-debuginfo       254 k

実際に展開されると、表示された容量の4倍ぐらいに膨れ上がり、DISKが心もとなく なったので使用を断念。FreeBSD側に期待をかける事にした。

FreeBSDでdebug

と言う名のjuliaソースツアーをやってみたい。で、大本になるjuliaがdebug用に コンパイルされていない。まずはそこからだな。

Makefileを見ると make debugで行けそう。待つ事10分ぐらいかな。julia-debugが 出来上がった。 makeする時のログを取ってたので眺めてみると

  GEN      include/uv-dtrace.h
  CC       src/libuv_la-fs-poll.lo
  CC       src/libuv_la-inet.lo
  CC       src/libuv_la-uv-common.lo
  CC       src/libuv_la-version.lo
  CC       src/unix/libuv_la-async.lo
  ;
  CCLD     libuv.la
  GEN      src/unix/uv-dtrace.o
    llvm
    pcore
    flisp
    xxx.jl

ってな具合にコンパイルされた。blsaとかllvmの長くかかるコンパイル時間の影に 隠れていたけど、ようやくコンパイル過程が分かった気がする。

後はgdbを何とかしたい。portsから自分でコンパイルしようとしたら、kgdbも一緒に 作る仕様になってた。このおかげで出来合いのgdbは自分の環境とマッチしなかったの だろう。多分、旧石器問題(32Bitの石)問題だと思われ。

で、下記は恒例のreplが待ちに入った時の状況。

(gdb) bt
#0  0x282e144f in _kevent () from /lib/libc.so.7
#1  0x2835ff05 in ?? () from /lib/libthr.so.3
#2  0x28579e83 in uv__io_poll (loop=loop@entry=0x29290000 <default_loop_struct>, timeout=-1\) at src/unix/kqueue.c:130
#3  0x2856cf21 in uv_run (loop=0x29290000 <default_loop_struct>, mode=UV_RUN_ONCE) at src/u\nix/core.c:294
#4  0x28536be4 in jl_run_once (loop=0x29290000 <default_loop_struct>) at jl_uv.c:116
#5  0x2b63ca83 in julia_process_events_17329 () at stream.jl:713
#6  0x2b63c6ef in julia_wait_17327 () at task.jl:360
#7  0x2b63c4a7 in julia_wait_17325 () at task.jl:286
#8  0x2b647598 in julia_wait_readnb_17554 () at stream.jl:358
#9  0x2b6472f4 in julia_eof_17553 () at stream.jl:1209
#10 0x2b6470ed in julia_match_input_17552 () at LineEdit.jl:756
#11 0x2847e2ad in jl_apply (f=0x2d910530, args=0xbfbfde94, nargs=5) at julia.h:1325
#12 0x28482425 in jl_trampoline (F=0x2d910530, args=0xbfbfde64, nargs=5) at builtins.c:1037
#13 0x28471f0b in jl_apply (f=0x2d910530, args=0xbfbfde64, nargs=5) at julia.h:1325
#14 0x28477796 in jl_apply_generic (F=0x2d9103d0, args=0xbfbfde64, nargs=5) at gf.c:1684
#15 0x2b646e4a in julia_match_input_17547 () at LineEdit.jl:756
#16 0x2847e2ad in jl_apply (f=0x2d910510, args=0xbfbfe03c, nargs=2) at julia.h:1325
#17 0x28482425 in jl_trampoline (F=0x2d910510, args=0xbfbfe03c, nargs=2) at builtins.c:1037
#18 0x28471f0b in jl_apply (f=0x2d910510, args=0xbfbfe03c, nargs=2) at julia.h:1325
#19 0x28477796 in jl_apply_generic (F=0x2d9103d0, args=0xbfbfe03c, nargs=2) at gf.c:1684
#20 0x2b649178 in julia_prompt!_17601 () at LineEdit.jl:1631
#21 0x2b64c4ed in julia_run_interface_17668 () at LineEdit.jl:1605
#22 0x2b64c6b7 in jlcall_run_interface_17668 () from /usr/home/sakae/src/julia-0.4.3/usr/lib/julia/sys-debug.so
#23 0x2847e2ad in jl_apply (f=0x2dbd7850, args=0xbfbfe2cc, nargs=2) at julia.h:1325
#24 0x28482425 in jl_trampoline (F=0x2dbd7850, args=0xbfbfe2cc, nargs=2) at builtins.c:1037
#25 0x28471f0b in jl_apply (f=0x2dbd7850, args=0xbfbfe2cc, nargs=2) at julia.h:1325
#26 0x28477796 in jl_apply_generic (F=0x2dbd77c0, args=0xbfbfe2cc, nargs=2) at gf.c:1684
#27 0x2b656ce3 in julia_run_frontend_17953 () at REPL.jl:863
#28 0x2b6562c5 in julia_run_repl_17939 () at REPL.jl:167
#29 0x2847e2ad in jl_apply (f=0x2dc48d20, args=0xbfbfe52c, nargs=2) at julia.h:1325
#30 0x28482425 in jl_trampoline (F=0x2dc48d20, args=0xbfbfe52c, nargs=2) at builtins.c:1037
#31 0x28471f0b in jl_apply (f=0x2dc48d20, args=0xbfbfe52c, nargs=2) at julia.h:1325
#32 0x28477796 in jl_apply_generic (F=0x2dc48c40, args=0xbfbfe52c, nargs=2) at gf.c:1684
#33 0x2b6694b7 in julia__start_18352 () at client.jl:420
#34 0x2b6697b5 in jlcall.start_18352 () from /usr/home/sakae/src/julia-0.4.3/usr/lib/julia/sys-debug.so
#35 0x2847e2ad in jl_apply (f=0x2ebdbb60, args=0x0, nargs=0) at julia.h:1325
#36 0x28482425 in jl_trampoline (F=0x2ebdbb60, args=0x0, nargs=0) at builtins.c:1037
#37 0x28471f0b in jl_apply (f=0x2ebdbb60, args=0x0, nargs=0) at julia.h:1325
#38 0x28477796 in jl_apply_generic (F=0x2ebdbb00, args=0x0, nargs=0) at gf.c:1684
#39 0x0804956f in jl_apply (f=0x2ebdbb00, args=0x0, nargs=0) at ../src/julia.h:1325
#40 0x0804a5ea in true_main (argc=0, argv=0xbfbfe878) at repl.c:491
#41 0x0804a93a in main (argc=0, argv=0xbfbfe878) at repl.c:595

深い、深い、不快、不快って事で、目先を変えてみる。julialangの資料を流し読み。 面白い機能を発見。LLVMに依頼して出来たIR(中間表現)を取り出せるんですって。

$ export JULIA_LLVM_ARGS=-print-after-all
$ julia -E 'factor(123456)' 2> IR-LOG
Dict(643=>1,3=>1,2=>6)

STDERRに出てくるので、それだけをログ。ログのサイズは39M。67万行を超えるもの だったよ。これをコンパイルとかやってると、遅くなるのは肯けるな。 どんなになってるか?

$ head -15 IR-LOG
*** IR Dump After Simplify the CFG ***
define %jl_value_t* @jlcall_pointer_20837(%jl_value_t*, %jl_value_t**, i32) {
top:
  %3 = getelementptr %jl_value_t** %1, i32 0
  %4 = load %jl_value_t** %3
  %5 = getelementptr %jl_value_t** %1, i32 1
  %6 = load %jl_value_t** %5
  %7 = bitcast %jl_value_t* %6 to i32*
  %8 = load i32* %7, align 16
  %9 = call i8* @julia_pointer_20837(%jl_value_t* %4, i32 %8)
  %10 = ptrtoint i8* %9 to i32
  %11 = call %jl_value_t* @jl_gc_allocobj(i32 4)
  %12 = bitcast %jl_value_t* %11 to %jl_value_t**
  %13 = getelementptr %jl_value_t** %12, i32 -1
  store %jl_value_t* inttoptr (i32 763775056 to %jl_value_t*), %jl_value_t** %13
$ tail -15 IR-LOG
    Predecessors according to CFG: BB#0
        %EAX<def> = MOV32rr %ESI<kill>; dbg:dict.jl:339:1
        %ESP<def,tied1> = ADD32ri8 %ESP<tied0>, 24, %EFLAGS<imp-def,dead>; dbg:dict.jl:339:1
        %ESI<def> = POP32r %ESP<imp-def>, %ESP<imp-use>; dbg:dict.jl:339:1
        %EDI<def> = POP32r %ESP<imp-def>, %ESP<imp-use>; dbg:dict.jl:339:1
        %EBP<def> = POP32r %ESP<imp-def>, %ESP<imp-use>; dbg:dict.jl:339:1
        RET %EAX; dbg:dict.jl:339:1

BB#2: derived from LLVM BB %CallStackCheckFailBlk
    Live Ins: %EBP
    Predecessors according to CFG: BB#0
        CALLpcrel32 <ga:@__stack_chk_fail>, <regmask>, %ESP<imp-use>, %ESP<imp-def>

# End machine code for function julia_delete!_20895.

表面と裏面だけ見せて本物と信用させる、誘拐事件の身代金みたいな物と思っちゃいけないよ。 中身がびっしり詰まった正真正銘のIRですから。 その証拠(になるかな? factorなんて何処にも有りそうだから、マーカーには不適)

define %jl_value_t* @jlcall_factor_20856(%jl_value_t*, %jl_value_t**, i32) {
top:
  %3 = getelementptr %jl_value_t** %1, i32 0
  %4 = load %jl_value_t** %3
  %5 = bitcast %jl_value_t* %4 to i32*
  %6 = load i32* %5, align 16
  %7 = call %jl_value_t* @julia_factor_20856(i32 %6)
  ret %jl_value_t* %7
}
*** IR Dump After Promote Memory to Register ***
 :
*** IR Dump After Combine redundant instructions ***
 :
*** IR Dump After Scalar Replacement of Aggregates (DT) ***
 :
*** IR Dump After Combine redundant instructions ***
 :
*** IR Dump After Jump Threading ***
 :
 :
*** IR Dump After Aggressive Dead Code Elimination ***
define %jl_value_t* @jlcall_factor_20856(%jl_value_t*, %jl_value_t**, i32) {
top:
  %3 = load %jl_value_t** %1, align 4
  %4 = bitcast %jl_value_t* %3 to i32*
  %5 = load i32* %4, align 16
  %6 = call %jl_value_t* @julia_factor_20856(i32 %5)
  ret %jl_value_t* %6
}

元のコードをマネーロンダリングと言うかクレンジングと言うかサニタイズして、似て非なるものに変換してから使うとな。 並々ならぬ努力をしてますよ。執念ですなあ。

とまあ、偉そうに分かったようなへらず口を叩いておりますが、オイラーは正真正銘の LLVM童貞であります。どこかの怪しげな所に寄って、童貞とおさらばしましょ。

大学院生のためのLLVM

LLVM フレームワークで実用的なコンパイラーを作成する: 第 1 回

#JuliaLang ていすいじゅん?の話(LLVM IRとNative code 触りだけ)

LLVM + clang で LLVM IR やアセンブリを出力する

LLVM 言語マニュアル(Language Reference Manual)

LLVM Tutorial: Table of Contents

LLVMによるプログラミング言語の実装 上記の翻訳版?

flisp

またちょっと違った方向から眺めてみます。LLVMで必要なIR語を出力するための 第一歩として、juliaではflispが使われているとの事。抽象構文木(AST)とかを 出すんですなあ。

juliaをdebug buildしたんで、flispも -debug付きで作成されています。それを まず走らせてから、lulia側で用意したフロントエンドスクリプトを読み込みます。 後は、julia語を入力して、ASTを観察。

$ flisp/flisp-debug
;  _
; |_ _ _ |_ _ |  . _ _
; | (-||||_(_)|__|_)|_)
;-------------------|----------------------------------------------------------

> (load "jlfrontend.scm")
#fn("7000r1e0e1|3141;" [expand-toplevel-expr julia-parse] fe)

> (jl-parse-string "1 + 3")
(call + 1 3)

> (jl-parse-string "f(x) = 2x")
(= (call f x) (block (line 1 none) (call * 2 x)))

> (jl-parse-string "x = 1234")
(= x 1234)

次は実例っぽく、以前に作ったオイラーのjulia語から。

> (jl-parse-string "macro em(f)
    return :( emacs($f) )
end
")
(macro (call em f) (block (line 2 /home/sakae/.juliarc.jl)
                          (return '(call emacs ($ f)))))

> (jl-parse-string
"function emacs(m::Method)
    tv, decls, file, line = arg_decl_parts(m)
    emacs(string(file), line)
end
")
(function (call emacs (:: m Method)) (block (line 2 /home/sakae/.juliarc.jl)
                                            (= (tuple tv decls file line)
                                               (call arg_decl_parts m))
                                            (line 3 /home/sakae/.juliarc.jl)
                                            (call emacs (call string file) line)))
> (jl-parse-string
"import Base: find_in_path, find_source_file, function_module, functionloc")
(toplevel (import Base find_in_path) (import Base find_source_file)
          (import Base function_module) (import Base functionloc))
> (jl-parse-string
"emacs(file::AbstractString) = emacs(file, 1)
emacs(f)          = emacs(functionloc(f)...)
emacs(f, t::ANY)  = emacs(functionloc(f,t)...)
emacs(file, line::Integer) = emacs(file, line)
")
(toplevel (= (call emacs (:: file AbstractString))
             (block (line 1 /home/sakae/.juliarc.jl)
                    (call emacs file 1)))
          (= (call emacs f) (block (line 2 /home/sakae/.juliarc.jl)
                                   (call emacs (... (call functionloc f)))))
          (= (call emacs f
                   (:: t ANY))
             (block (line 3 /home/sakae/.juliarc.jl)
                    (call emacs (... (call functionloc f t)))))
          (= (call emacs file
                   (:: line Integer))
             (block (line 4 /home/sakae/.juliarc.jl)
                    (call emacs file line))))

flispと来たら中身を見ておきたい。ソースの構成がsrc/flisp/ってなってて、flisp本体は、 flisp-dir内に、flispのアプリである *.scm 類は、srcの直下に置いてあるんで、scmを flisp内に移動。そこでetagsを実行。

$ etags *.[ch] *.lsp *.scm

こんな事をやって、3種混合ワクチンならぬ、3種混合TAGSを生成。これで、flispの ネイティブ実装、lispで書かれたlisp拡張、julia様ご要求のLLVM用フロントエンドである scm類が一発で引けるぞ。

ああ、flisp類はjuliaから独立してる訳ではなく、julia生成の途中で、libflisp.aに なってjuliaに組み込まれている。

そしてflisp側とJulia側とのデータ交換は、ast.c内にある、julia_to_scmとscm_to_juliaが 担当してるようだ。 同ソース内に、

// this is used to parse a line of repl input
DLLEXPORT jl_value_t *jl_parse_input_line(const char *str, size_t len)
{
    value_t s = cvalue_static_cstrn(str, len);
    value_t e = fl_applyn(1, symbol_value(symbol("jl-parse-string")), s);
    if (e == FL_EOF)
        return jl_nothing;
    return scm_to_julia(e,0);
}

上でオイラーが、flispから呼んで実験してたのが、ここでjulia側のreplから使われて いるんだな。

juliaとflispの癒着にはflisp側に用意したapplyが使われているとな。flisp側で実行 したい手続きは、文字列をシンボルにして渡す。手続きの引数もflisp側に馴染むように して渡す。返ってきた結果はflisp色に染まっているから、julia側で使えるように変換 してる。

それにしてもapplyとは名手だな。さすがMITはLisperの巣窟だな。こういう所に センスが出てるよ。

ついでなんで、どんな手続きをjulia側から呼んでるか、調べておく。

$ grep 'jl-' *.[ch] *.cpp
ast.c:    value_t e = fl_applyn(1, symbol_value(symbol("jl-parse-string")), s);
ast.c:    value_t p = fl_applyn(3, symbol_value(symbol("jl-parse-one-string")),
ast.c:    if (fl_applyn(1, symbol_value(symbol("jl-parse-file")), s) == FL_F)
ast.c:    fl_applyn(0, symbol_value(symbol("jl-parser-close-stream")));
ast.c:    value_t prev = fl_applyn(1, symbol_value(symbol("jl-parser-depwarn")),
ast.c:    value_t prev = fl_applyn(1, symbol_value(symbol("jl-parser-deperror")),
ast.c:    value_t c = fl_applyn(0, symbol_value(symbol("jl-parser-next")));
ast.c:        jl_lineno = numval(fl_applyn(0, symbol_value(symbol("jl-parser-current-lineno"))));
ast.c:    fl_applyn(2, symbol_value(symbol("jl-parse-string-stream")), t, f);
ast.c:    value_t e = fl_applyn(1, symbol_value(symbol("jl-expand-to-thunk")), arg);
ast.c:    value_t e = fl_applyn(1, symbol_value(symbol("jl-macroexpand")), arg);

lisp側の関数名は、キャメルケースでもなくスネークケースでもなく、ハイフォンで 単語を繋ぎ合せる記法なんで、こういう時は楽だ。ついでに、入力も楽で非常に宜しい!!

マクロ展開なんてのも有るね。と言う事はjulia側からも使えるんだろうね。いろいろ 予想が出来て楽しいな。

flispのreplが起動した所を記念撮影。何せjulia観光のオプションツアーですから。

(gdb) bt
#0  0x2826ee1f in _read () from /lib/libc.so.7
#1  0x280fba1d in ?? () from /lib/libthr.so.3
#2  0x0806fecc in _os_read (fd=0, buf=0x2880e000, n=131072, nread=0xbfbfe088) at ios.c:95
#3  0x08070760 in _ios_read (s=0x2880c020, dest=0xbfbfe12b "\b\244\261JEQ\216\r200\030\021(\205", n=1, all=0) at ios.c:295
#4  0x08070821 in ios_read (s=0x2880c020, dest=0xbfbfe12b "\b\244\261JEQ\216\r(\00\030\021(\205", n=1) at ios.c:313
#5  0x08072d2f in ios_getc (s=0x2880c020) at ios.c:1003
#6  0x0805ab93 in nextchar () at read.c:138
#7  0x0805aeaa in peek () at read.c:215
#8  0x0805c1b4 in do_read_sexpr (label=1) at read.c:587
#9  0x0805c81e in fl_read_sexpr (f=679940237) at read.c:712
#10 0x08068adb in fl_read (args=0x2897d090, nargs=0) at iostream.c:125
#11 0x0805ee7a in apply_cl (nargs=0) at flisp.c:1226
#12 0x0805e100 in do_trycatch () at flisp.c:950
#13 0x08062437 in apply_cl (nargs=0) at flisp.c:1856
#14 0x0805e100 in do_trycatch () at flisp.c:950
#15 0x08062437 in apply_cl (nargs=0) at flisp.c:1856
#16 0x08059e1a in _applyn (n=1) at flisp.c:729
#17 0x0805a089 in fl_applyn (n=1, f=679950938) at flisp.c:774
#18 0x0806b153 in main (argc=1, argv=0xbfbfebdc) at flmain.c:54

つらつらとほっつき歩いていたら、緒言にぶち当たったので、記録を 残して、旅の思い出とする。本当は、沖縄あたりに旅したいんだけど。。。

/*
  femtoLisp

  a compact interpreter for a minimal lisp/scheme dialect

  characteristics:
  * lexical scope, lisp-1
  * unrestricted macros
  * data types: 30-bit integer, symbol, pair, vector, char, string, table
      iostream, procedure, low-level data types
  * case-sensitive
  * simple compacting copying garbage collector
  * Scheme-style varargs (dotted formal argument lists)
  * "human-readable" bytecode with self-hosted compiler

  extra features:
  * circular structure can be printed and read
  * #. read macro for eval-when-read and readably printing builtins
  * read macros for backquote
  * symbol character-escaping printer
  * exceptions
  * gensyms (can be usefully read back in, too)
  * #| multiline comments |#, lots of other lexical syntax
  * generic compare function, cyclic equal
  * cvalues system providing C data types and a C FFI
  * constructor notation for nicely printing arbitrary values

  by Jeff Bezanson (C) 2009
  Distributed under the BSD License
*/

最後にflispがどんな風にコンパイルされるかLOGから抜粋しておく

$ grep -C 12 libflisp LOG
    CC src/support/libsupportinit.dbg.obj
    CC src/support/arraylist.dbg.obj
    CC src/support/strtod.dbg.obj
    LINK src/support/libsupport-debug.a
    CC src/flisp/flisp.dbg.obj
    CC src/flisp/builtins.dbg.obj
    CC src/flisp/string.dbg.obj
    CC src/flisp/equalhash.dbg.obj
    CC src/flisp/table.dbg.obj
    CC src/flisp/iostream.dbg.obj
    CC src/flisp/julia_extensions.dbg.obj
    LINK src/flisp/libflisp-debug.a
    CC src/flisp/flmain.dbg.obj
    LINK src/flisp/flisp-debug
    FLISP src/julia_flisp.boot
    FLISP src/julia_flisp.boot.inc
    CC src/ast.dbg.obj
    CC src/builtins.dbg.obj
    CC src/module.dbg.obj
    CC src/codegen.dbg.obj
    CC src/disasm.dbg.obj
    CC src/debuginfo.dbg.obj
    CC src/interpreter.dbg.obj
    CC src/alloc.dbg.obj

続きをちょっと眺めると

    CC src/gc.dbg.obj
    LINK usr/lib/libjulia-debug.so
    CC ui/repl.dbg.obj
    LINK usr/bin/julia-debug
    PERL base/pcre_h.jl
    PERL base/errno_h.jl
    PERL base/build_h.jl.phony
    PERL base/fenv_constants.jl
    PERL base/file_constants.jl
    PERL base/uv_constants.jl
    JULIA usr/lib/julia/inference0.ji
essentials.jl
reflection.jl

julia_flisp.bootとかは、何じゃらホイって事で調べてみると、

$ grep julia_flisp.boot Makefile
$(BUILDDIR)/julia_flisp.boot.inc: $(BUILDDIR)/julia_flisp.boot $(FLISP_EXECUTABLE)
export julia_flisp_boot=$(BUILDDIR)/julia_flisp.boot
$(julia_flisp_boot): julia-parser.scm julia-syntax.scm \
        match.scm utils.scm jlfrontend.scm mk_julia_flisp_boot.scm $(FLISP_EXECUTABLE)
        @$(call PRINT_FLISP, $(call spawn,$(FLISP_EXECUTABLE)) ./mk_julia_flisp_boot.scm)
$(BUILDDIR)/ast.o $(BUILDDIR)/ast.dbg.obj: $(BUILDDIR)/julia_flisp.boot.inc flisp/*.h
        -rm -f $(BUILDDIR)/julia_flisp.boot $(BUILDDIR)/julia_flisp.boot.inc

んでもって、mk_julia_flisp_boot.scmが気になって調べると

$ cat mk_julia_flisp_boot.scm
(load "jlfrontend.scm")
(make-system-image (os.getenv "julia_flisp_boot"))

んでもって、make-system-imageなんてのを調べると、動いてるflispを生きたまま 保存する、普通のlispが持ってる種の保存機能でしたよ。この機能はテスト時にでも 使うのかな? いくら調べても終る事が無いので、これぐらにしておこう。

etc

CentOS 7のネットワーク管理「NetworkManager」を極める