クリーンで、効率的で、標準に準拠した標準Cライブラリの実装を目標としている。1から設計されており、アプリケーションを単一のポータブルなバイナリファイルとして配布できるように静的リンクに最適化している。準拠であるとしている。非標準な関数も実装されている。rustupを使ってLinux環境にRustをインストールすると、デフォルトのターゲットとして*-linux-gnuが選択されます。*-linux-gnuと*-linux-muslには以下のような違いがあります。静的リンクUbuntuやCentOSを含むほとんどのLinuxディストリビューションではシステムの標準Cライブラリとしてglibcが使われています。SQLiteやOpenSSLのようなパッケージマネージャでインストールできるライブラリは、基本的にglibcと動的リンクしています。Rustで*-linux-gnuターゲットを使うと、Rustのバイナリもglibcと動的リンクします。このようなバイナリを配布する際は、バイナリを実行するLinux環境にglibcがなければなりません。バイナリがOpenSSLなどの外部ライブラリにも依存してるなら(動的リンクしているなら)、aptなどのパッケージマネージャを使ってそれらのライブラリもインストールしなければなりません。バイナリを一般のユーザーに使ってもらうなら、DEBやRPMなどのパッケージに入れて、適切な依存ライブラリを設定するのが無難でしょう。確実な方法ではありますが、ちょっと面倒ですよね。Rustで*-linux-muslターゲットを使うと、バイナリはmuslと静的リンクします。OpenSSLなどの外部ライブラリに依存しているなら、それらとも静的リンクします。Rustの単一のバイナリファイルにこれら全てのライブラリが埋め込まれている状態になります。このようなバイナリならCPUアーキテクチャさえ一致すればどんなLinux環境でも実行できます。DEBやRPMなどのパッケージを使わず、単一のバイナリを渡すだけですみますので、気軽にバイナリを配布できます。*-linux-muslがデフォルトのターゲットではない理由バイナリの配布に便利な*-linux-muslターゲットですが、なぜLinux環境ではそれをデフォルトにせず、*-linux-gnuターゲットが使われるのでしょうか?それはmuslを使うとビルドが面倒になるからです。*-linux-muslではRustバイナリが外部ライブラリに依存しているときは、それなりの準備が必要です。外部ライブラリはglibcと動的リンクする代わりに、muslと静的リンクしている必要があるからです。そのようなものはaptなどではインストールできないのが普通ですので、musl向けのgccを使ってソースコードからビルドすることになります。いえ、Rustでよく使われる外部ライブラリなら、自分で準備する必要はありません。使われるライブラリとRustコンパイラ/gccをセットにしたDockerイメージがいくつかありますので、それらを使えば簡単です。前置きが長くなりました。Worldをビルドしてみましょう。このバイナリは標準Cライブラリだけに依存しますので、muslターゲットでも簡単にビルドできます。ビルドする環境にはLinux向けのリンカが必要ですので、macOSやWindowsでビルドするならDockerを使うのが楽です。3.10でも実行できることを確認します。18.04環境(Dockerコンテナ)を起動して、Rustなどの必要なソフトウェアをインストールします。$HOME/.cargo/envバイナリを実行するための環境も起動しておきます。Linuxはセキュリティを重視したシンプルかつ軽量なLinuxディストリビューションです。組み込み系でよく使われているBusyBoxをベースにしているのでインストールサイズが小さいのが特徴です。Dockerのイメージサイズを比べてみましょう。3.10は5.55MBです2。Dockerではイメージが小さいほうがユーザから喜ばれる傾向がありますので、Dockerの公式イメージもUbuntuベースからAlpineベースに移行していく動きがあります。Worldプログラムを作成します。普通の方法でビルドします。--releaseLinux環境ではデフォルトのターゲットがx86_64-unknown-linux-gnuに設定されています。lddコマンドでどのライブラリと動的リンクしているか調べましょう。(0x00007fb28647a000)生成されたバイナリはlibc.soやlibpthread.soといった共有ライブラリと動的リンクしています。一般的なLinuxディストリビューションではglibcが使われており、libpthreadなどと共に最初からインストールされています。8にコピーしても実行できます。Linuxではmuslが使われており、glibcはインストールされていません。そのため、このバイナリをAlpine環境にコピーしても実行できません。Linuxでも実行できるよう、x86_64-unknown-linux-muslターゲットを使いましょう。Ubuntu環境に戻り、rustupでx86_64-unknown-linux-muslターゲットを追加します。2019-11-04)デフォルトのターゲットはlinux-gnuのままです。buildに--targetオプションを追加してmuslターゲット向けにビルドします。--target=x86_64-unknown-linux-muslこのターゲットでは外部ライブラリと静的リンクします。lddコマンドで調べると動的リンクではないことが確認できます。Linuxでも実行できました。world!このように標準Cライブラリだけに依存するプログラムなら、静的リンク版のLinuxバイナリを簡単に作成できます。3と静的リンクしたバイナリを作成して、Dockerイメージに収めます。Linuxカーネルのバージョンは2.6.18かそれ以降でなければなりません。↩︎DockerイメージにはLinuxカーネルが含まれていないので、カーネル抜きのサイズになります。(tatsuya6502)Erlang/OTPやRustで分散DBを開発してます。最近、Rustの本を書きました。(tatsuya6502)。