
初めてソースから何かをコンパイルしようとしたとき、金曜の夜に3時間もエラーメッセージをググっていました。3時間です。たった5分で終わるはずのプログラムのために。
私はPythonとJavaScriptの世界から来たので、pip installやnpm installはただ動くものだと思っていました。依存関係の解決、ロックファイル、分かりやすいエラーメッセージ - すべて自動で処理されていました。それが、PyPIにないCライブラリが必要になった途端、リンカの出力を象形文字のように読み解く羽目になったのです。
そんなに苦痛である必要はありません。実際にうまくいく方法を教えましょう。
ほとんどのCプロジェクトは、同じ3段階の儀式に従います。
./configure
make -j$(nproc)
sudo make install
configureスクリプトはシステムを調べて、どのライブラリがあるかを特定し、マシンに特化したMakefileを作成します。次に、makeが実際のコンパイルを行います。最後に、make installが完成したバイナリをシェルが見つけられる場所にコピーします。
すべてのプロジェクトがautotoolsを使っているわけではありません。手書きのMakefileを使っているものや、CMakeを使っているものもあります。しかし、configure/makeパターンを使っているものが非常に多いため、常に遭遇することになるでしょう。迷ったときは、READMEやINSTALLファイルを確認してください。通常、実行すべき内容が正確に書かれています。
プロジェクトがどのビルドシステムを使っているか分からない?ルートディレクトリでconfigure、CMakeLists.txt、Makefile、またはmeson.buildを探してみてください。それが最初の手がかりです。
ここで物事がうまくいかなくなることがよくあります。./configureを実行すると、次のようなメッセージが表示されます。
checking for libqpdf... no
configure: error: Package requirements (libqpdf >= 8.0) were not met
このエラーのせいで、数え切れないほどのコンパイルセッションが中断されました。プログラムがライブラリを必要としているのに、それがインストールされていないのです。
UbuntuまたはDebianでは、パッケージの-devバージョンが必要です。通常のパッケージはランタイムライブラリを提供しますが、実際に何かをコンパイルするにはヘッダーが必要です。
sudo apt install -y libqpdf-dev
Homebrewを使用しているmacOSでは、もっと簡単です。Homebrewはパッケージを開発用とランタイム用に分けません。
brew install qpdf
もう一つmacOSのヒントです。Homebrewでライブラリをインストールしたのに、configureがまだ見つけられない場合、パスが正しく設定されていない可能性があります。これについては次のセクションで説明します。
私は仕事でMacBookを使っています。Homebrewは素晴らしいですが、すべてを非標準的な場所にインストールします。Apple Siliconでは、ライブラリは/opt/homebrew/にインストールされます。Intel Macでは、/usr/local/にインストールされます。
コンパイラは自動的にそこを探すようにはなっていません。そのため、Homebrewで何かをインストールしたとしても、configureスクリプトはまだ見つからないと文句を言うかもしれません。
ld: library not foundが表示されたら、コンパイラにどこを探すべきかを伝える必要があります。
CPPFLAGS="-I/opt/homebrew/include" \
LDFLAGS="-L/opt/homebrew/lib" \
./configure
CPPFLAGSはインクルードディレクトリを追加します。LDFLAGSはライブラリディレクトリを追加します。これらがないと、configureは標準システムパス外にあるヘッダーやライブラリを見つけられません。
プロジェクトがconfigureを使用しない場合、makeに直接これを行う必要があることもあります。
CPPFLAGS="-I/opt/homebrew/include" LDLIBS="-L/opt/homebrew/lib -liconv" make
プロジェクトが異なれば、構文も少し異なります。しかし、原則は同じです。Homebrewがファイルを実際に置いた場所をコンパイラに教えるのです。
これを発見するのに、恥ずかしいほど長い時間がかかりました。
デフォルトでは、makeは1つのジョブ、つまり1つのCPUコアでコンパイルします。その間、マシンの残りの部分はアイドル状態です。最新の8コアノートパソコンでは、潜在能力の12.5%しか使っていないことになります。
代わりにどうすればいいのでしょうか?
make -j$(nproc) # Linux
make -j$(sysctl -n hw.ncpu) # macOS
-jフラグは、複数のコンパイルジョブを並行して実行します。$(nproc)は、LinuxにCPUコアの数を尋ねるだけです。macOSでは、sysctl -n hw.ncpuが同じことをします。
小さなプロジェクトでは、あまり違いは感じられないでしょう。しかし、数千のソースファイルを持つような大規模なプロジェクトでは、すべてが変わります。5分かかっていたものが45秒で終わるかもしれません。本当に大規模なプロジェクトでは、コーヒーブレイクとランチの差になることもあります。
実際に何コア持っていますか?ほとんどの最新のノートパソコンは4〜8コアです。nprocまたはsysctl -n hw.ncpuを実行して、何が得られるか見てみましょう。そして、その数値を-jと一緒に使ってください。
時には、すべてを正しく行ったのに、まだ失敗することがあります。私が遭遇した最も一般的な落とし穴をいくつか紹介します。
リンク時にシンボルが見つからない - 通常、ライブラリのバージョン不一致を意味します。プログラムが、あなたが持っているものよりも新しいバージョン、または異なるAPIを持つ古いバージョンを期待している可能性があります。プロジェクトのドキュメントで、必要な正確なバージョンを確認してください。
configureでパーミッションが拒否される - configureスクリプトがまだ実行可能でない場合があります。chmod +x configureを実行して、もう一度試してください。
sudoを使いたくない? - それはもっともです。システム全体のインストールにはroot権限が必要ですが、代わりにホームディレクトリにインストールすることもできます。
./configure --prefix=$HOME/.local
make -j$(nproc)
make install
これで、プログラムは/usr/local/bin/ではなく~/.local/bin/にインストールされます。まだ設定されていない場合は、~/.local/binをPATHに追加する必要があります。
金曜の夜の3時間にわたるデバッグセッションを振り返ると、問題はすべて解決可能でした。ただ、自分が何を知らないのかを知らなかっただけです。
多くの時間を節約してくれたであろういくつかのこと:
Ubuntuでは、-devパッケージのサフィックスが重要です。これがないと、ライブラリはあってもヘッダーがありません。configureは、見えないライブラリに対してビルドすることはできません。
Homebrewはファイルを非標準的な場所に置きます。macOSでは、CPPFLAGSとLDFLAGSの設定はオプションではありません。ビルドシステムにインストールした場所を伝える方法です。
-jフラグは最適化ではありません。必須です。1コアではコンパイルが遅いです。すべてのコアを使えば速くコンパイルできます。
そして最後に、configureが失敗した場合、エラーメッセージは通常、何が不足しているかを正確に教えてくれます。Googleで検索する前に、それを読んでください。「Package requirements (libqpdf >= 8.0) were not met」は謎めいたものではありません。チェックリストの項目です。そのパッケージをインストールして、次に進みましょう。
Ubuntu/Debianで、インストールしたライブラリをconfigureが見つけられない場合、どのパッケージサフィックスを探すべきですか?
make -j$(nproc) の -j フラグは何のためにありますか?
HomebrewはApple Silicon Macにライブラリをどこにインストールしますか?
ソースからのコンパイルは、見た目ほど恐ろしいものではありません。ビルドシステムは古く、エラーメッセージもあまり親切ではありませんが、数回経験すれば、そのプロセスは実際にはかなり予測可能です。もう一度試してみてください。初めてソースからコンパイルが成功したときの達成感は素晴らしいものです。
何か特定のものをコンパイルする手順を説明してほしいですか?最近の私のコンパイルのほとんどは、これらの手順のいずれかをスキップしたためにうまくいきませんでした。あなたが取り組んでいることのデバッグを喜んでお手伝いします。
AI CLIログの整形、Cron式の作成、JWTの解析、chmod権限の計算をオフラインで実行。

なぜ「q」でほとんどのものが終了し、Ctrl-Cがユニバーサルなkill switchになったのか、そしてコマンドラインを使い慣れたものにするPOSIXの幽霊について解説します。
続きを読む
大規模なeBPFとXDPについて、毎秒1000万パケットのDDoS軽減やドライバーレベルフィルタリングを、実用的なアーキテクチャとコード例で網羅的に解説します。
続きを読む
KubernetesにおけるLinuxcgroupsv2のPSI(PressureStallInformation)、メモリ制限、OOMシールドについて、本番環境レベルのアーキテクチャとコード例を交えて解説する包括的なガイド。
続きを読む