昨日久々にnimについての記事を書いて、その最後にビルドが通らないことが多いのでC/C++の知識が必須と書いた。
そこで、実際どんなパターンが多いのかをちょっと挙げてみたいと思う。
dll/lib等にリンクできないパターン
圧倒的に多いのがこれで、正直困るのはこれだけと言っても過言ではない。nim-lang/uiを例にとって説明していこうと思う。
Windowsでの例
nim-lang/uiの説明にしたがって、nimble install ui しておく。ここまでは無事できていると仮定したいのだけれど、もしMSYS2等でうまくいかないときは、たいてい NIMBLE_DIR が適切に設定できていないことが多い。なお、nimのバージョンは2.2.6を使用する。
で、exampleを動かすためにソースをcloneしてくる。
$ git clone https://github.com/nim-lang/ui nim-ui
$ cd nim-uiよし動かそうとして、nim c -r examples\table.nim すると、エラーに見舞われる。(注: 説明環境ではnim-ui2フォルダとして実行。)
# (中略)
c:/users/funatsu/.choosenim/toolchains/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\funatsu\nimcache\table_d\@mtable.nim.c.o:@mtable.nim.c:(.text+0x13c0): undefined reference to `uiTableValueInt'
c:/users/funatsu/.choosenim/toolchains/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\funatsu\nimcache\table_d\@mtable.nim.c.o:@mtable.nim.c:(.text+0x1458): undefined reference to `uiTableModelRowChanged'
c:/users/funatsu/.choosenim/toolchains/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:\Users\funatsu\nimcache\table_d\@mtable.nim.c.o:@mtable.nim.c:(.text+0x1b39): undefined reference to `uiNewTableModel'
collect2.exe: error: ld returned 1 exit status
Error: execution of an external program failed: 'gcc.exe -o C:\Users\funatsu\lab\nim-ui2\examples\table.exe C:\Users\funatsu\lab\nim-ui2\res\resources.o C:\Users\funatsu\nimcache\table_d\@psystem@sexceptions.nim.c.o C:\Users\funatsu\nimcache\table_d\@pstd@sprivate@sdigitsutils.nim.c.o C:\Users\funatsu\nimcache\table_d\@psystem@sdollars.nim.c.o C:\Users\funatsu\nimcache\table_d\@pstd@sexitprocs.nim.c.o C:\Users\funatsu\nimcache\table_d\@pstd@ssyncio.nim.c.o C:\Users\funatsu\nimcache\table_d\@psystem.nim.c.o C:\Users\funatsu\nimcache\table_d\@pdynlib.nim.c.o C:\Users\funatsu\nimcache\table_d\@pwinlean.nim.c.o C:\Users\funatsu\nimcache\table_d\@ptimes.nim.c.o C:\Users\funatsu\nimcache\table_d\@pui.nim.c.o C:\Users\funatsu\nimcache\table_d\@pstd@sprivate@swin_setenv.nim.c.o C:\Users\funatsu\nimcache\table_d\@pstd@scmdline.nim.c.o C:\Users\funatsu\nimcache\table_d\@prandom.nim.c.o C:\Users\funatsu\nimcache\table_d\@mtable.nim.c.o -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lcomctl32 -ld2d1 -ldwrite -lUxTheme -lUsp10 -lgdi32 -luser32 -lkernel32 -Wl,-Bstatic -lpthread'ここで既にC/C++の知識がないと解決ができない。何がエラーしているのかをみると、主原因は
undefined reference to `uiNewTableModel'
にあるようだ。ld.exe 、つまりリンカでのエラーであることから、ヘッダファイルは既にあって、dllやlibがなかったのでリンクできなかった、という状況であることがわかる。
nim-lang/ui は、libui-ng のdllが必要なので、自分でコンパイルしてくるのが一番ではあるのだけれど、今回の場合は neroist/uing の Releases/0.7.2にdllやlib、soなどが配布されているので、ありがたく使うことにする。
とりあえず試しにプロジェクトフォルダに置いてみるも、エラー内容は変わらない。そこで、よく最後の一行を見てみると、そもそもlibuiが読み込まれていないことに気づく。
Error: execution of an external program failed: 'gcc.exe -o C:\Users\funatsu\lab\nim-ui2\examples\table.exe (中略) -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lcomctl32 -ld2d1 -ldwrite -lUxTheme -lUsp10 -lgdi32 -luser32 -lkernel32 -Wl,-Bstatic -lpthread'nim --fullhelp を見ると、nimの完全なオプションがわかるので、grep path とか grep lib とかで調べながら(windows環境の場合は rg = ripgrep とかをインストールするとgrepの代わりになる。)
$ nim c --clib="ui" -r examples\table.nimを実行してみると、
c:/users/funatsu/.choosenim/toolchains/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lui
collect2.exe: error: ld returned 1 exit status
Error: execution of an external program failed: 'gcc.exe -o C:\Users\funatsu\lab\nim-ui2\examples\table.exe (中略) -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lcomctl32 -ld2d1 -ldwrite -lUxTheme -lUsp10 -lgdi32 -luser32 -lkernel32 -lui -Wl,-Bstatic -lpthread'エラー内容が少し変わった。-lui がついているのでちゃんと読み込まれようとしているが、見つからないようだ。
そこで今度は読み込みフォルダを指定してあげることにする。同じくnimのhelpより調べたのちに、
$ nim c --clib="ui" --clibdir=. -r examples\table.nimとすると、
c:/users/funatsu/.choosenim/toolchains/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/11.1.0/../../../../x86_64-w64-mingw32/bin/ld.exe: cannot find -lui
collect2.exe: error: ld returned 1 exit status
Error: execution of an external program failed: 'gcc.exe -o C:\Users\funatsu\lab\nim-ui2\examples\table.exe (中略) -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lcomctl32 -ld2d1 -ldwrite -lUxTheme -lUsp10 -lgdi32 -luser32 -lkernel32 -lui -LC:\Users\funatsu\lab\nim-ui2\examples -Wl,-Bstatic -lpthread'なんか惜しい。-LC:\Users\funatsu\lab\nim-ui2\examples が追加されていることから、. = つまりプロジェクトフォルダを指定したつもりが、どうやらmainのソースがあるフォルダが参照先になっている様子。そこで dll/lib をプロジェクトフォルダではなくexamplesに移して、再度実行すると、
$ nim c --clib="ui" --clibdir=. -r examples\table.nim
う、動いた!
…とまぁ、こんな調子で結局C/C++の知識はほぼ100%必須となるので、あまりユーザが増えないnimであった…。
macの場合: rpath問題とDYLD_LIBRARY_PATH問題
これで終わりかと思いきや、macではさらに事情が複雑になる。これもまたC/C++の知識がいるのだけれど、同じことをmacでもやってみよう。
$ git clone https://github.com/nim-lang/ui nim-ui
$ cd nim-uiさっきのノウハウがあるので、libui.dylibはひとまずここからもってきて、先読みしてexamplesに置いておこう。
で、さっきと同じように実行してみると…
$ nim c --clib="ui" --clibdir=. -r examples/table.nimdyld[14321]: Library not loaded: @rpath/libui.dylib
Referenced from: <80FD2141-193E-35A4-9B23-F75F925BC8B3> /Users/fu/lab/nim-ui2/examples/table
Reason: no LC_RPATH's found
Error: execution of an external program failed: '/Users/fu/lab/nim-ui2/examples/table'RPATHとはなんぞや・・・となる。
RPATHはなにかというのは今回は置いといて、rpathを指定してあげると・・・
$ nim c --clib="ui" --clibdir=. --passL:"-rpath $PWD/examples" -r examples/table.nim
無事に動いた。あー疲れた 笑
ちなみにrpath以外にそもそもdylibが見つからない、となる場合には、DYLD_LIBRARY_PATH=$PWD/examples 等をnimコマンドの前に指定してあげると直ったりする。このあたりは .app として配布する場合にはまた違ってくるので、今回はとりあえず動かすことに主眼をおいた。
まとめ
nimのユーザが増えないのは、結局終始こんな調子でC/C++の知識がないとビルドを通すことができないことに起因していると思う。
トランスパイラの宿命かなとは思うのだけれど、OdinとかV言語ではここまで苦しくない印象なので、おそらくC言語をアセンブリとしか見ていないというスタンスのために nimcache に出力されるCコードが異様に読みづらいのと、エラーメッセージをどう解決すればいいかのHintが少なすぎることに起因しているのかなと思う。
なので個人的にはnimは結構辛い言語の一つになってしまっているんじゃないかなとは思いつつ、ORCなどの画期的な機能があるのは確かなので、今後もうまく付き合っていければなと思う。