いそがしい人のための結論
Crystalでは、簡単に静的ライブラリをリンクできる。
-link-flags
フラグを指定すればよい。
crystal build a.cr --link-flags "-L/path/to/the/dir -lpiyo`
以上。
はじめに
C言語のライブラリには「共有(shared)ライブラリ」と「静的(static)ライブラリ」があります。Rubyでバインディングを作成するときは、Ruby-FFIやFiddleを使って共有ライブラリを呼び出すと楽なことが多いので、もっぱら共有ライブラリに触れていました。C拡張ライブラリとしてGemを作る場合は、静的ライブラリにリンクすることも可能ですが、一般にはパッケージマネージャーで配布される共有ライブラリを使うのが王道だと思うので、静的リンクは少し縁遠い世界でした。
Crystalでは静的ライブラリにリンクすることができる
クリスタルでコマンドライン・ツールを作って配布するときは、Dockerイメージを使ってmuslでコンパイルすることが多いですね。C言語のライブラリをCrystalから呼び出すときも静的にビルドしたいですね。Crystalの公式のマニュアルを読んでもやり方がわかりにくかったので、Qiita記事に残します。
参考資料
次の記事がよくまとまっていました。
静的ライブラリを準備する
簡単な例として、Intの文字列を足し合わせるだけのライブラリを作ります。addition.h
と addition.c
を用意します。
#ifndef ADDITION_H
#define ADDITION_H
int add(int a, int b);
#endif
#include "addition.h"
int add(int a, int b) {
return a + b;
}
静的ライブラリ libaddition.a
を生成します。ar
コマンドで複数のオブジェクトファイルをまとめて、静的ライブラリとすることができます。ここでは addition.o
一つだけです。
gcc -c addition.c -o addition.o
ar rcs libaddition.a addition.o
作成された libaddition.a
をC言語から使う場合は、次のようなコードを書いて、
#include <stdio.h>
#include "addition.h"
int main() {
int result = add(5, 3);
printf("Result: %d\n", result);
return 0;
}
こんな感じのコマンドでコンパイルします。
gcc main.c -L. -laddition -o main
ここで、-L
コマンドはライブラリのパスを直接指定していますが、ldconfig -v
というコマンドを使うことで、すでにパスが通っている場所や利用できるライブラリの一覧などが表示できるようです。
Crystalから静的ライブラリを使う
実は、Crystalのコードは共有ライブラリのときと同じです。
@[Link("addition")]
lib LibAddition
fun add(a : Int32, b : Int32) : Int32
end
puts LibAddition.add(5, 3)
大切なのは、ビルドコマンドに --link-flags
を追加することです。
crystal build a.cr --link-flags "-L/home/kojix2/Crystal/tmp -laddition"
正しくコンパイルされていることを確認します。
./a
8
実際に生成されたプログラムがリンクされているライブラリを確認してみましょう。
ldd ./a
linux-vdso.so.1 (0x00007fff799c2000)
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0 (0x00007f8f86b50000)
libgc.so.1 => /usr/local/lib/libgc.so.1 (0x00007f8f86ae2000)
libevent-2.1.so.7 => /lib/x86_64-linux-gnu/libevent-2.1.so.7 (0x00007f8f86a90000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8f86a6c000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8f86800000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8f86d3c000)
libaddition
はありません。つまり、libaddition.so がない環境でもこのプログラムは動作します。めでたしめでたし。
この記事は以上です。
本来は「Crystal言語がどのようにして動作するのか調べてみた(中編)」を投稿する予定だったのですが、昨年は記事をかけるだけの進捗がなく、あきらめて薄いネタを投稿しました。なお、Crystal言語の理解を諦めたわけではありませんので、少しずつ勉強していずれはCrystalがどのように動作しているのか理解したいと思っています。