
llbuild-analyzeをWindowsでビルドするには?SQLiteエラーと重複シンボル問題の原因・対処法を徹底解説
Swift製プロジェクトのビルド時間を調査したいとき、llbuild-analyze は非常に有力な手段です。ところが、macOSでは動いてもWindows環境では思わぬ壁にぶつかることがあります。特に厄介なのが、sqlite3.h file not found と duplicate symbol の二段構えのエラーです。表面的には「SQLiteを入れれば済む話」に見えますが、実際には依存関係の持ち方そのものが衝突の原因になっているケースが少なくありません。本記事では、Windowsでllbuild-analyzeをビルドしようとした際に起きやすい問題を整理しながら、なぜエラーが起きるのか、どう直せばよいのかを実務目線でわかりやすく解説します。
- llbuild-analyzeをWindowsでビルドするには?SQLiteエラーと重複シンボル問題の原因・対処法を徹底解説
- llbuild-analyzeをWindowsで動かしたい理由
- 最初に発生しやすいエラー:sqlite3.h が見つからない
- vcpkgでSQLiteを導入しても次の壁にぶつかる理由
- duplicate symbolエラーの本質
- なぜこの問題はWindowsで特に目立つのか
- つまり、対策の方向性は「SQLiteを1本化する」こと
- その場しのぎで解決しようとしてはいけない理由
- 実際に見直すべきポイント
- 1. どのパッケージがSQLiteをどの方式で取り込んでいるか洗い出す
- 2. Swift Package Managerのmanifestを確認する
- 3. リンクコマンドラインを確認する
- 4. どちらのSQLiteを残すか決める
- 実務的にはリファクタリングが最短ルートになりやすい
- Windowsでllbuild-analyzeを安定運用するための考え方
- まとめ:llbuild-analyzeのWindowsビルドはSQLiteの整理がカギ
llbuild-analyzeをWindowsで動かしたい理由
Swiftのビルド時間が長いとき、まず疑いたくなるのがリンク工程です。コンパイルそのものよりも、最終的なリンクや依存解決、ビルドデータベースの解析部分で時間が膨らむケースは珍しくありません。そこで役立つのがllbuild-analyzeです。
このツールを使うと、ビルドデータベースをもとに処理時間の偏りや依存関係の流れを確認しやすくなります。つまり、「なんとなく遅い」状態から、「どこが遅いのか」を定量的に追えるわけです。
ただし、ここで1つ大きな問題があります。macOSでビルドしたllbuild-analyzeをWindowsマシンで生成したビルドデータベースに対して使うと、Windowsパスの扱いで失敗することがあります。パス区切り文字やドライブレターの扱いがmacOS前提ではうまく解釈できず、解析そのものが止まってしまうのです。
このため、Windows上のビルドデータベースを正しく扱いたいなら、素直にWindows環境でllbuild-analyzeをビルドして実行したい、という流れになります。
最初に発生しやすいエラー:sqlite3.h が見つからない
Windowsでswift runを実行したとき、まず遭遇しやすいのが次のタイプのエラーです。
-
sqlite3.h file not found -
could not build C module 'CSQLite3'
これは非常に典型的で、Swiftパッケージの一部がSQLiteのヘッダファイルを必要としているのに、コンパイラがその場所を見つけられていない状態です。
なぜSQLiteが必要になるのか
llbuild-analyze周辺では、内部的にSQLiteベースの処理が関わることがあります。Swiftの周辺ツール群では、CライブラリをSwiftから扱うためにラッパーやシステムモジュールが使われることが多く、その過程でsqlite3.hが必要になります。
WindowsではmacOSやLinuxほど標準的に開発用ヘッダが整っていないため、SQLite本体を導入していても「実行ファイルはあるがヘッダはない」「ライブラリはあるがインクルードパスが通っていない」といった状態になりがちです。
つまりこの段階では、問題はシンプルです。必要なヘッダをコンパイラに見せられていないだけです。
vcpkgでSQLiteを導入しても次の壁にぶつかる理由
多くの開発者はここでvcpkgを使ってSQLiteを導入します。実際、この判断自体は間違っていません。includeとlibのパスを-Xcc -Iや-Xlinker -Lで指定してやれば、最初のsqlite3.h not foundは解消できる可能性が高いです。
ところが、その次に発生するのがさらにややこしいエラーです。
-
duplicate symbol: sqlite3_bind_null -
duplicate symbol: sqlite3_bind_text
これは「SQLiteが見つからない問題」が解決したあとに、「SQLiteが二重に存在してしまう問題」に変化したことを意味します。
duplicate symbolエラーの本質
このエラーの本質は単純です。リンク時に、同じ関数が2つの場所から定義されているため、リンカがどちらを採用すべきか判断できなくなっています。
今回のケースでは、次のような構図が起きています。
1. ある依存はSQLiteをシステムライブラリとして使おうとしている
つまり、外部にインストールされたsqlite3.libや対応するDLLを使う前提です。vcpkgから導入したSQLiteは、まさにこの用途に合っています。
2. 別の依存はSQLiteをソースからビルドしている
こちらは外部の既存SQLiteを使うのではなく、パッケージ内部でsqlite3.cをコンパイルして取り込んでいます。
3. 結果として、同じSQLiteの関数が2回リンクされる
sqlite3_bind_nullやsqlite3_bind_textのような関数が、片方ではsqlite3.c.o、もう片方ではsqlite3.libの両方に存在するため、重複シンボルとして検出されます。
これがWindowsでのビルドを難しくしている最大のポイントです。
なぜこの問題はWindowsで特に目立つのか
macOSやLinuxでも同様の構造的問題は起こり得ます。しかしWindowsでは、ライブラリの取り回しやツールチェーンの違いにより、こうした衝突がより表面化しやすい傾向があります。
理由は大きく3つあります。
Cライブラリの取り込み方法が環境差の影響を受けやすい
WindowsではMSVC系ツールチェーンやlld-linkの振る舞いが関わるため、静的ライブラリ・DLLインポートライブラリ・オブジェクトファイルのどれが最終リンクに乗っているかが見えづらくなります。
パッケージごとの依存方針が混在しやすい
あるライブラリは「システムにあるSQLiteを使う」設計、別のライブラリは「どの環境でも動くようSQLiteを同梱する」設計、というように、思想が一致していないことがあります。これがWindows移植時に顕在化します。
一度ヘッダ問題を解決すると、今度はリンク問題が顔を出す
最初のエラーは「見つからない」なので比較的わかりやすいのですが、それを解決した直後に「今度は多すぎる」という真逆の問題になるため、原因の切り分けが難しくなります。
つまり、対策の方向性は「SQLiteを1本化する」こと
結論から言えば、この種の問題に対する最も本質的な解決策は、依存関係全体でSQLiteの供給元を1つに統一することです。
「複数あるSQLiteをうまく共存させる方法はないか」と考えたくなりますが、実務上はおすすめしません。理由は簡単で、今たとえ通っても、将来バージョン差異やリンカ設定の変更で再発しやすいからです。
llbuild-analyzeを安定してビルドしたいなら、次のどちらかに寄せる必要があります。
パターンA:すべてシステムのSQLiteを使う
vcpkgなどで導入したSQLiteを使う方針に統一し、ソース内蔵型のSQLiteビルドを無効化します。環境構築は少し増えますが、外部依存を明示的に管理できるため、Windowsでは比較的扱いやすい方法です。
パターンB:すべて同梱SQLiteに寄せる
逆に、外部のsqlite3.libをリンク対象から外し、ソースからビルドされるSQLiteだけを使います。依存の完結性は高まりますが、すでにシステムライブラリ前提で書かれている箇所があると調整が必要です。
この二択のどちらかです。中途半端に両方を残すと、今回のような重複シンボルがほぼ確実に再発します。
その場しのぎで解決しようとしてはいけない理由
Windowsのリンクエラーに直面すると、つい「リンカオプションで重複を無視できないか」「片方のライブラリを後ろに回せば通らないか」といった小手先の回避策を試したくなります。
しかし、SQLiteのような基盤ライブラリでそれをやるのは危険です。
なぜなら、仮にリンクが通っても、実行時にどちらの実装が使われるのかが不安定になったり、ABIの差異やビルドオプションの違いによって予期しない不具合が起きたりする可能性があるからです。データベース系ライブラリは特に、コンパイルフラグやバージョン差分の影響を受けやすい領域です。
「ビルドできたからOK」ではなく、「依存関係が整理された状態でビルドできたか」が重要です。
実際に見直すべきポイント
では、具体的に何を確認すればよいのでしょうか。Windowsでこの問題に遭遇したときは、次の視点で見直すと整理しやすくなります。
1. どのパッケージがSQLiteをどの方式で取り込んでいるか洗い出す
まず必要なのは、依存ツリーの中でSQLiteが何回登場しているかを把握することです。特に確認したいのは以下の点です。
-
システムライブラリとして
sqlite3を要求しているモジュール -
sqlite3.cを直接ビルドしているモジュール -
Cモジュールラッパー経由でSQLiteを公開しているモジュール
-
Windows限定で分岐しているビルド設定の有無
この把握をせずにフラグだけ調整しても、根本解決にはなりません。
2. Swift Package Managerのmanifestを確認する
Package.swiftや関連設定で、どこがシステムライブラリ扱いになっているか、どこがターゲットにCソースを含めているかを見ます。
ここで注目したいのは、同じSQLiteに対して
-
あるターゲットは
.systemLibrary -
別のターゲットはCソースを直接コンパイル
という二重管理になっていないかです。
もしそうなっているなら、その時点で今回の問題の原因はかなり絞れます。
3. リンクコマンドラインを確認する
Windowsではビルドログが長くなりがちですが、最終的なリンク時に何が渡されているかを見ることが重要です。
-
sqlite3.libが明示的に含まれているか -
sqlite3.c.oが生成されているか -
両方が同時にリンク対象に入っていないか
重複シンボルが出ているなら、ほぼ確実にこの両方が載っています。つまり、ログ確認は原因の裏取りに有効です。
4. どちらのSQLiteを残すか決める
洗い出しが終わったら、「どちらを残すか」を先に決めます。ここを曖昧にしたまま修正すると、関連箇所を何度も行き来することになります。
一般的には、Windowsで既存環境と合わせたいならシステムSQLite寄せ、移植性や再現性を優先するなら同梱SQLite寄せが考えやすい選択です。
実務的にはリファクタリングが最短ルートになりやすい
「既知のうまい回避策があるか」と期待したくなる場面ですが、このケースでは依存の持ち方が衝突しているため、結局はリファクタリングが最短ルートになりやすいです。
とくに、あるモジュールがシステムSQLiteに依存し、別モジュールが内蔵SQLiteを抱えているなら、どちらかをやめる設計変更が必要になります。たとえば以下のような方向です。
共通のSQLite抽象層を用意する
アプリやツール側から直接複数のSQLite実装を触らず、共通の1実装だけを参照するようにします。これにより、最終リンク時の責任範囲が明確になります。
Windowsだけ依存先を切り替える
全プラットフォームで完全統一が難しい場合、Windows限定で使用するSQLite供給元を固定する方法もあります。条件分岐は増えますが、ビルドの安定性は上がります。
片方のパッケージをフォークして依存方針をそろえる
外部パッケージ同士の思想がぶつかっているなら、待っていても解決しないことがあります。必要ならフォークして依存方針を揃えたほうが、長期的には保守しやすくなります。
Windowsでllbuild-analyzeを安定運用するための考え方
今回の問題は、単なるビルドエラーではありません。WindowsでSwiftの周辺ツールを扱うときに頻出する、「依存ライブラリの供給源が分散している」問題の代表例です。
重要なのは、エラーメッセージを1件ずつ潰すことではなく、次の順番で考えることです。
まずヘッダが見つからないなら、インクルードパスの問題を解決する。次にリンクが失敗するなら、重複定義の有無を見る。そして重複が見つかったら、依存の一本化に舵を切る。この流れを守るだけで、かなり見通しが良くなります。
特にWindowsでは、ツールチェーン・ライブラリ形式・ビルド設定の相互作用が複雑になりやすいため、「とりあえず追加でリンクする」はむしろ悪化のもとです。足りないから足す、ではなく、何が二重になっているかを見るべきです。
まとめ:llbuild-analyzeのWindowsビルドはSQLiteの整理がカギ
llbuild-analyzeをWindowsでビルドしようとすると、最初はsqlite3.hが見つからないエラーに直面し、その後SQLiteを導入すると今度はduplicate symbolに苦しめられることがあります。しかし、この流れは偶然ではありません。
根本原因は、依存関係の中でSQLiteが「システムライブラリ」と「ソースビルド」の両方で取り込まれていることにあります。つまり、Windowsでこの問題を本当に解決するには、コンパイルオプションを追加するだけでは不十分で、SQLiteの供給元を1つに統一する設計判断が必要です。
ビルド時間の分析という本来の目的に早く戻りたいなら、回避策を探し続けるより、SQLite依存の一本化に踏み切るほうが結果的に早いことが多いです。llbuild-analyzeを確実にWindowsで動かしたいなら、最初に確認すべきは「SQLiteがどこから何回入っているか」です。この視点を持つだけで、同種のSwiftビルド問題にも強くなれます。