GCC/Clangの診断結果をAIで自動修正!LLMとコンパイラログを連携させる自律型ビルドパイプラインの構築
テックリードの皆さん、日々のC/C++開発において「テンプレートメタプログラミングの深淵で爆発した数千行のコンパイルエラー(Diagnostic)」や「ポインタの不整合に起因するセグメンテーション違反の予兆」と格闘し、精神をすり減らしていないだろうか。
現代のLLM(GPT-4やClaude 3.5 Sonnetなど)は、コードの文脈理解において人間のシニアエンジニアに匹敵するパフォーマンスを発揮する。しかし、多くの開発者は「ブラウザを開き、コンソールログをコピーし、ChatGPTの画面に貼り付けて修正を乞う」という、石器時代のような非効率なワークフローを未だに続けている。
本稿では、GCC/Clangのコンパイラ診断結果(Diagnostic)をフックし、LLMのAPIへ文脈を最適化したプロンプトとして流し込み、即座に安全な修正パッチを生成・適用する自律型コンパイル・修復パイプライン(LLM-Driven Diagnostic Pipeline)の構築手法を、実務レベルのコードと共についに公開する。
—
なぜ「ログの丸投げ」では失敗するのか?(アーキテクチャの要件定義)
コンパイルエラーをそのままLLMに投げても、期待した修正コードは返ってこない。それどころか、幻想(ハルシネーション)に基づいた存在しないヘッダーファイルをインクルードしたり、APIのシグネチャを勝手にねじ曲げたりする。
実務で破綻しないパイプラインを構築するためには、以下の3つのレイヤーを厳密に制御する必要がある。
1. コンパイラ出力の構造化(Diagnostic Extraction): 雑多なカラーコードやパス名を除外し、問題の核心(エラーメッセージと該当ファイルの行番号、スニペット)だけを抽出する。
2. コンテキストの最小化(Token Optimization): 巨大なプロジェクト全体を投げるのではなく、依存関係とエラー箇所の周辺(±15行)のみをスライスしてプロンプトに封入する。
3. 安全性の担保(Automated Verification & Sandbox): LLMが生成した修正案をそのまま適用するのではなく、必ず静的解析・単体テスト(Unit Test)のサンドボックス環境を通し、回帰バグがないことを機械的に検証する。
—
実装:コンパイラログ・オートリペア・シェルスクリプト
以下のスクリプトは、`make` や `ninja` などのビルドプロセスをラップし、コンパイルエラーが発生した瞬間に自動でLLM(ここではOpenAI API)を叩いてパッチを生成・適用する実用的なBashスクリプト(`ai-fix.sh`)である。
!/usr/bin/env bash
厳格なエラーハンドリングの有効化(パイプライン途中の失敗を検知する)
set -euo pipefail
設定変数
BUILD_CMD=”${1:-make -j$(nproc)}” # 引数がなければ並列makeを実行
MODEL=”gpt-4o” # 高精度かつ高速な推論モデルを指定
LOG_FILE=”.cc_error.log” # コンパイルログの一時保存先
PATCH_FILE=”.cc_fix.patch” # LLMが生成するパッチの保存先
echo “==> 🚀 ビルドプロセスを開始します: ${BUILD_CMD}”
1. ビルドを実行し、標準エラー出力(診断結果)をファイルとコンソールの両方にキャプチャ
pipefailにより、makeが非ゼロ終了ステータスを返した場合にスクリプトが中断される
if eval “${BUILD_CMD}” 2> >(tee “${LOG_FILE}” >&2); then
echo “==> ✨ ビルドが正常に完了しました。エラーはありません。”
rm -f “${LOG_FILE}” “${PATCH_FILE}”
exit 0
fi
echo “==> ⚠️ コンパイルエラーを検出しました。LLMによる自動修復プロセスを開始します…”
2. ログサイズが大きすぎる場合の対策(直近の致命的なエラー箇所を抽出)
Clang/GCCの出力から、エラーと警告の核心部分を切り出す
ERROR_SNIPPET=$(grep -E “error:|fatal error:” “${LOG_FILE}” -A 3 -B 1 || true)
if [ -z “${ERROR_SNIPPET}” ]; then
echo “==> ❌ 構造化できるエラーメッセージが見つかりませんでした。手動での確認が必要です。”
exit 1
fi
echo “==> 🤖 LLM (${MODEL}) にコンテキストを送信し、修正案を生成しています…”
3. JSONペイロードの構築(jqコマンドを使用してエスケープ漏れを防ぐ)
システムプロンプトで「C/C++の厳格な構文規則を守り、差分パッチのみを出力する」よう制約を与える
SYSTEM_PROMPT=”You are an expert C/C++ compiler engineer. Analyze the provided compiler diagnostic log, locate the bug, and provide a unified diff patch to fix the compilation error. Output ONLY the raw unified diff format without markdown code blocks.”
USER_PAYLOAD=$(cat <
exit 1
fi
パッチファイルを書き出し
echo “${LLM_PATCH}” > “${PATCH_FILE}”
echo “==> 📝 生成されたパッチ:”
cat “${PATCH_FILE}”
6. 安全性の検証:パッチのドライラン(git apply –check)
if git apply –check “${PATCH_FILE}” 2>/dev/null; then
echo “==> 🔒 パッチの整合性検証に成功しました。コードベースに適用します。”
git apply “${PATCH_FILE}”
# 7. 自己修復のループ(再ビルドによる検証)
echo “==> 🔄 修正を適用して再ビルドを実行します…”
if eval “${BUILD_CMD}”; then
echo “==> 🎉 自動修復に完全成功しました!”
rm -f “${LOG_FILE}” “${PATCH_FILE}”
exit 0
else
echo “==> ❌ 修正後の再ビルドに失敗しました。パッチをロールバックします。”
git checkout — .
exit 1
fi
else
echo “==> ❌ 生成されたパッチは現在のコードベースに適用できません(競合または構文不正)。”
rm -f “${PATCH_FILE}”
exit 1
fi
—
LLMのハルシネーションを防ぐ「サンドボックス・検証ルール」
AIが生成するコードには常に「嘘」が混ざるリスクがある。特にC/C++では、未定義動作(Undefined Behavior)やメモリリークを誘発するコードが混入する可能性をゼロにすることはできない。
これを防ぐため、前述のスクリプトは以下の多重防御(Defense in Depth)アーキテクチャを採用している。
1. `git apply –check` による静的構文チェック:
LLMが生成した出力が「正しいUnified Diff形式」であり、現在のソースコードの行番号やコンテキストと完全に一致しているかをGitのエンジンで厳密に検証する。不一致があれば即座に弾く。
2. 決定論的パラメータの設定(`temperature: 0.1`):
創造性を極限まで削ぎ落とし、コンパイラエラーの解決という「正解が明確なタスク」に対して最もロジカルで再現性の高い出力を強制する。
3. 自動ロールバック機構(`git checkout — .`):
AIによる修正後に再ビルドが失敗した場合、または単体テスト(`make test` 等)が一つでも破綻した場合は、即座にgitの管理下にある元のクリーンな状態へ巻き戻す。これにより、開発者のローカル環境が「AIによって汚染される」リスクを完全に遮断する。
—
チーム開発への導入とスケーリング
このパイプラインをチーム全体で標準化するためのベストプラクティスを共有する。
1. 開発環境の統一(VS Code / CLI)
VS Codeのタスクランナー(`.vscode/tasks.json`)にこのスクリプトを統合することで、開発者は`Ctrl + Shift + B`(またはCmd + Shift + B)を押すだけで、「ビルド ➔ エラー検知 ➔ AI自動修復 ➔ 再テスト」の全自動ループを指一本で実行できるようになる。
{
“version”: “2.0.0”,
“tasks”: [
{
“label”: “AI-Driven Build & Auto-Fix”,
“type”: “shell”,
“command”: “./ai-fix.sh”,
“group”: {
“kind”: “build”,
“isDefault”: true
},
“problemMatcher”: [
“$gcc”
],
“presentation”: {
“reveal”: “always”,
“panel”: “shared”
}
}
]
}
2. CI/CDパイプライン(GitHub Actions)への統合
ローカルだけでなく、GitHub ActionsなどのCI環境でもこの仕組みを応用できる(ただし、CI環境では自動コミット&プッシュの安全性を考慮し、PRにコメントとして修正パッチを投稿するボットとして動作させるのが望ましい)。これにより、レビュアーが細かいタイポや型ミスの指摘に時間を奪われることが劇的に減少する。
—
総括:機械に任せるべきもの、人間が集中すべきもの
コンパイラの吐き出す機械的なエラーメッセージを人間が読み解き、数文字のタイポや型キャストのミスを直す作業は、高度な創造性を必要とするエンジニアリングではない。それは単なる「文字合わせ」の苦役(Toil)に過ぎない。
GCC/Clangの診断結果とLLMをパイプラインで直結させることで、私たちはこの苦役から完全に解放される。浮いた膨大なエネルギーを、アーキテクチャの設計、アルゴリズムの最適化、そしてドメインロジックの深淵なる追求へと全振りしてほしい。
プロフェッショナルなエンジニアたるもの、道具に働かされるのではなく、道具に限界まで働かせるのだ。今日のビルドから、この自律型パイプラインをあなたの開発環境に組み込んでみてほしい。生産性の桁が違うことに気づくだろう。