この記事は、2026 年 11 月 7 日に上海 Google DevFest で行われた、Qiniu クラウド インフラストラクチャ開発エンジニアで XGo / LLGo / LLAR プロジェクトの貢献者である Guo Haolan (@meteorsliu) による基調講演を編集し、関連するコードと測定データを補足するためにオンサイトのデモ PPT と組み合わせたものです。

コンパイラーとその基礎となるエコシステムについて説明する前に、まず次の質問について考えてみましょう。AI時代に入っても、プログラマーはやはりプログラミング言語そのものに注意を払う必要があるのでしょうか?
70 年前の 1957 年に IBM は Fortran 言語をリリースし、プログラマーを「手書きアセンブリ時代」から「高級プログラミング言語時代」に押し上げました。今日のテクノロジーの進化もこれとよく似ています。 AI は私たちを「手書きの高級言語コード」から「AI 支援プログラミング」という新たな段階に連れて行きます。
高級言語コンパイラーが基盤となるハードウェア シナリオをすべてカバーすることはできず、一部のコア ロジックでは依然としてアセンブリ コードを手動で記述する必要があるのと同様に、今日の複雑なエンジニアリングの実践において、多くの深いビジネスや基盤となるアーキテクチャに対する AI の理解は依然として人間ほど完全ではありません。エンジニアはコードを頻繁に読み、理解し、レビューし、AI が期待どおりのロジックを生成できるように導く必要があります。
これは、AI 時代における理想的なプログラミング言語に対する中心的な需要も決定します。優れた可読性、シンプルなデザイン、厳格なロジック、および豊富な生態学的カバレッジ。
Go 言語は、「シンプルさ」という点で間違いなく信頼できるキャリアです。業界にはジョークがあります。AI 時代、Java プログラマーによって報告される最も一般的なエラーは、「週の使用制限に達しました」 (週の使用制限を使い果たした) かもしれません。 Rust プログラマはおそらくクォータの枯渇から逃れることができず、コンパイラによってスローされる大量の警告に直面することになるでしょう。したがって、AI 時代には、トークンを節約できるという理由で、Java プログラマーは私たち Go オタクよりも Go を好むかもしれません。 Rust プログラマーは、Go が好きとは言わないことがよくあります。彼らはもっと頑固で、Rust が世界で最高の言語であると常に言います。もちろん、彼らのコンパイラは同意しないかもしれないと思います。
もちろん、冗談はやめてエンジニアリングの現実に戻りましょう。 XGo チームの目標は、すべての開発者が独自のプログラムを簡単かつ簡単に作成できるようにすることです。これを達成するには、囲碁の境界に立ち向かい、過去数十年にわたって蓄積されてきた異種テクノロジーのエコシステムを接続する必要があります。
Go はクラウド ネイティブ開発やサーバーサイド開発で広く使用されていますが、それは最新のソフトウェア エンジニアリングの一部にすぎません。さらに多くのシナリオに視野を広げても、Go は依然として相互運用性とプラットフォームの課題に直面しています。
- C/C++ の基礎となる生態学的再利用は制限されています: C と C++ は、基盤となるインフラストラクチャとコア ライブラリ資産を数十年にわたって蓄積してきました。デスクトップ ソフトウェア、オペレーティング システム カーネル、および基盤となるさまざまなドライバーは、C エコシステムに大きく依存しています。
- 組み込みおよび WebAssembly のボリューム制約: マイクロコントローラーなどのリソースに制約のあるデバイスには軽量のランタイムが必要であり、ブラウザなどの WebAssembly 環境にも軽量のビルド製品が必要です。ただし、標準の Go コンパイラーには完全なランタイムが付属しており、ビルド製品が大きすぎることがよくあります。
- Go で Python ライブラリを再利用する: Python は、現在の主流の AI モデル、データ サイエンス ライブラリ、ツール チェーンを統合します。 Go が NumPy や PyTorch などの環境資産を直接自然に再利用することは困難です。
C エコシステムの場合、Go の公式ソリューションは cgo です。しかし、cgo を書いたことのある開発者は、cgo が双方向呼び出し、関数コールバック、クロスコンパイルでどれほど面倒かを知っています。
C 標準ライブラリ stdlib.h のクイック ソート関数 qsort を例にとると、カスタム比較関数を渡す必要があります。 cgo でこの基本的な呼び出しを完了するには、まず //export を通じて Go シンボルを公開し、次に呼び出しを転送するための Wrapper 関数を C 言語で作成する必要があります。
// cgo 方案:Go 侧导出符号并调用 C 包装函数
//export goCompare
func goCompare(a, b unsafe.Pointer) C.int { ... }
a := []C.int{3, 1, 2}
C.sortInts(&a[0], C.int(len(a)))
// cgo 方案:C 侧编写 Wrapper 中转
int compare(const void *a, const void *b) {
return goCompare((void *)a, (void *)b);
}
void sortInts(int *a, int n) {
qsort(a, n, sizeof(int), compare);
}
//export goCompare
func goCompare(a, b unsafe.Pointer) C.int { ... }
a := []C.int{3, 1, 2}
C.sortInts(&a[0], C.int(len(a)))
対照的に、Zig 言語の C での qsort の実装は、はるかにクリーンです。
const c = @cImport({
@cInclude("stdlib.h");
});
fn compare(...) callconv(.c) c_int { ... }
c.qsort(..., &compare);
これは私たちの核心的な質問につながります。C レベルのネイティブ相互運用機能と LLVM バックエンド機能を備えながら、Go 言語の開発経験を完全に保持できるか?
この目的のために、私たちが導入したのは、 LLGo。一言でまとめると、LLGo を使用すると、Go 構文を使用してプログラムを作成し、コンパイルに LLVM を使用し、外部と通信するために C を使用できます。
LLGo の全体的なアーキテクチャは、次の 3 つのコア レベルに分かれています。
- フロントエンド (Go 型チェックと SSA): go/types と go/ssa に基づいて構築され、Go 言語の公式セマンティクスとの一貫性を最大限に高めます。
- ミッドバックエンド (LLVM に切り替え): Go SSA を LLVM IR に変換し、LLVM のコード最適化機能とマルチターゲット プラットフォーム生成サポートを直接再利用し、このレイヤーで C ABI 互換の変換を完了します。
- 相互運用性レイヤー (C/C++/Python とのネイティブ ドッキング): cgo に別れを告げ、Go コードでの C ライブラリの直接呼び出しをサポートし、Python モジュールをインポートします。
前の qsort の例に戻ると、LLGo では C ラッパー ブリッジは必要ありません。 Go の匿名クロージャ関数を c.Qsort に直接渡して並べ替えを完了できます。
import (
"unsafe""github.com/goplus/lib/c"
)
values := []c.Int{3, 1, 2}
c.Qsort(c.Pointer(&values[0]), ...,
func(a, b c.Pointer) c.Int { ... })
// values: [1 2 3]
Go エコシステムでは、同じく LLVM に基づいている公式コンパイラー gc、TinyGo、LLGo がさまざまなエンジニアリング シナリオ向けに設計されており、それぞれに独自の長所があります。

同時に、LLGo は標準の Go ソース コードと互換性のあるコンパイラーでもあります。最も基本的な hello.go を例にとると、同じソース コードが go build と llgo build を使用してコンパイルされ、実行結果はまったく同じになります。ただし、macOS の実際のテスト環境では、ビルドされた 2 つの製品のサイズに大きな違いがあります。
- 作りに行く 製品を構築する:2,429,874B(約) 2.43MB)
- ビルドしてみます 製品を構築する:1,280,832B(約) 1.28MB)
実際の測定によると、LLGo によって生成される実行可能ファイルのサイズは、公式 gc のサイズとほぼ同じです。 53%ほぼ半分に減りました。さらに、LLGo は、「Go + C」混合コードを WebAssembly ターゲット環境に直接コンパイルして実行することをネイティブにサポートしています。

コンパイラ レベルで ABI を開くことは、最初のステップにすぎません。実際の C/C++ クロスプラットフォーム プロジェクトの構築は、多くの場合さらに困難です。
USB ハードウェア ウォレットへのアクセスには、イーサリアム クライアント Go-Ethereum の独立したパッケージ ethereum/hid が使用されます。例: さまざまなオペレーティング システムと互換性を持たせるために、プロジェクトは、Linux、macOS、および Windows 用の基礎となる C ソース コードの複数のセットを hidapi/ ディレクトリに維持する必要があります。クロスコンパイルする場合、cgo を有効にしてターゲット プラットフォームの C クロスコンパイラーを設定する必要があるだけでなく、cgo を閉じるとデバイス列挙が空になります。大規模な C/C++ プロジェクトでは、多くの場合、そのようなプラットフォームに関連するソース コードとビルド構成が数十存在するため、メンテナンス コストが非常に高くなります。
シンボルの導入と C/C++ ライブラリのクロスコンパイルの問題を解決するために、連携して動作する 4 つのコンポーネントで構成される閉ループ ツール チェーンを設計しました (一部のクラウド自動構築機能は現在計画および推進段階にあります)。
- llcppg: C/C++ ヘッダー ファイルを読み取り、AST を抽出して、自己完結型の Go バインディング パッケージを自動的に生成します。
- ラール: C++ エコシステムのコナンと同様に、数式を使用して C/C++ プロジェクトを取得、コンパイル、インストールする方法を記述し、複雑なクロスコンパイルとツール チェーンをクラウド上に置いて処理します。
- LLAR ハブのインデックス ウェアハウス: 一元化された製品インデックス ウェアハウスとして、各 C/C++ プロジェクトの短縮名を登録し、対応する式と llcppg 構成を記録します。コミュニティは PR を llarhub/.index に送信するだけで済み、マージ後、cibot は自動的にウェアハウスを作成し、対応する Go パッケージを公開できます。
- LLGo: C/C++ 関数を直接呼び出し、リンク フェーズ中にネイティブ ライブラリのプルとインストールを自動的にトリガーします。
このシステムが成熟すると、将来的には Go への C/C++ 依存関係の導入がネイティブ Go モジュールと同じくらい簡単になるでしょう。ローカルの C ツール チェーンを手動でいじる必要はなく、2 行のコマンドを実行するだけですぐに使用できるようになります。
$ go get llar.io/zlib
$ llgo build
llcppg を使用してバインディング パッケージを生成する場合、必要なのは単純な JSON 構成ファイルを提供することだけです。 llcppg は、FuncPrefix および TypePrefix を通じて C 言語の命名プレフィックスを自動的に削除して Go 仕様に準拠する名前を生成できるだけでなく、MethodPrefix を通じて特定のプレフィックスを持つ C 関数を Go 構造メソッドに自動的に変換することもできます。
技術的により難しい部分は、「C/C++ にはあるが Go 言語には無い」低レベルの構文機能を Go を使って表現する方法です。共用体、ビット フィールド、および C++ 仮想関数については、llcppg が対応する設計提案を完成させ、エンジニアリング実装を完了しました。

C 言語のビット フィールドを例にとると、1 ビット フィールドを含む C 構造体は、llcppg による処理後に次のタイプ セーフな Go アクセサー コードを自動的に生成します。
// C 位域定义
struct Flags {
unsigned int a : 1;
...
};
// llcppg 自动生成的 Go 访问器
func (p *Flags) XGof_get_a c.Uint {
return c.Uint(bitfield.Unsigned(
unsafe.Pointer(p), 0, 1))
}
現在、C/C++ 標準ライブラリは完全にカバーされており、高頻度の C/C++ オープン ソース ライブラリ用の多数の Go バインディングを検証してリリースしました。
- データとテキスト:cjson、libxml2、libxslt、sqlite、zlib
- 安全性:openssl
- インフラストラクチャとコンパイラ:bdw-gc、libuv、llvm-c、clang-c
- スクリプトとグラフィックス:ルア、レイリブ
C/C++ のオープン化に加えて、LLGo エコシステムのもう 1 つの重要な要素は、Python の AI およびデータ サイエンス エコシステムの直接再利用です。私たちの技術的なパスは 2 つのステップに分かれています。
- まず、llcppg を使用して基礎となるファイルを変換します。 Python C API Go バインディング パッケージに変換します。
- その後、特別に開発された llpyg ツールを使用して、Python の標準ライブラリとサードパーティ ライブラリを対応する Go パッケージに自動的に変換します。
現在、py/math、py/json、py/inspect、py/statistics などの Python 標準ライブラリ、および py/numpy、py/pandas、py/torch、py/matplotlib などの主流のサードパーティ科学計算および深層学習ライブラリはバインディング変換を完了し、LLGo での直接呼び出しをサポートしています。
import (
"github.com/goplus/lib/py"
"github.com/goplus/lib/py/math"
"github.com/goplus/lib/py/std"
)
x := math.Sqrt(py.Float(2))
std.Print(py.Str("sqrt(2) ="), x)
// 输出:sqrt(2) = 1.414…
LLGo のクロスエコロジー混合機能を視覚的に示すために、実際の内部ツール pydump を見てみましょう。
pydump は、llpyg が Python ライブラリ バインディングを生成するときの基礎となる依存関係ツールです。その機能は、Python ライブラリ名を入力し、ライブラリ内のすべてのシンボルの型、名前、ドキュメント、および関数シグネチャをエクスポートし、それを JSON 出力としてフォーマットすることです。
LLGo を使用して pydump を記述する場合、C 標準ライブラリ、C オープン ソース ライブラリ、Python C API、および Python 標準ライブラリを直接結合して、数十行の Go コードを作成します。
// 初始化 Python,创建 cJSON 根对象,导入目标 Python 模块
pyLib := c.Index(c.Argv, 1)
py.Initialize
root := cjson.CreateObject
root.AddItemToObject(c.Str("name"), cjson.CreateString(pyLib))
items := cjson.CreateArray
mod := py.ImportModule(pyLib)
keys := mod.ModuleGetDict.DictKeys
// 遍历模块符号,通过 Python inspect 提取签名,并用 cJSON 输出
for i, n := 0, keys.ListLen; i < n; i++ {
key := keys.ListItem(i)
val := mod.GetAttr(key)
sym := cjson.CreateObject
sym.AddItemToObject(c.Str("name"), cjson.CreateString(key.CStr))
if val.Callable != 0 {
sig := inspect.Signature(val)
sym.AddItemToObject(c.Str("sig"), cjson.CreateString(sig.Str.CStr))
}
cjson.AddItemToArray(items, sym)
}
root.AddItemToObject(c.Str("items"), items)
c.Printf(c.Str("%s\n"), root.Print)
このコードは完全に Go 構文で書かれていますが、Go 標準ライブラリは参照しません。すべての機能は、基盤となる C および Python エコシステムによって提供されます。 macOS で llgo ビルドを使用してコンパイルした後、生成される pydump 実行可能ファイルのサイズはわずか 53,152 B (約 52 KB) です。
質問:クライアント側や組み込みハードウェアなど、メモリ リソースが非常に限られているシナリオでは、通常の Go ランタイムのガベージ コレクション (GC) が自動的に実行されることを考慮すると、言語をまたいだ開発に LLGo を使用する場合、または制限されたデバイスで実行する場合、メモリはどのように管理されますか? C/C++ のようにメモリを手動で管理する必要がありますか?
グオ・ハオラン: GC に関しては、LLGo では 2 つのシナリオを区別する必要があります。1 つは通常の PC/サーバーの言語間通話シナリオで、もう 1 つは組み込みシナリオです。
通常の PC 呼び出しシナリオでは、C 言語自体は GC をサポートしておらず、GC によって管理されないため、明確な境界分離原則に従います。つまり、C エコロジカルな側に割り当てられたメモリは依然として C 自体によって管理されます。リソースに制約のある組み込みシナリオでは、メモリ空間が非常に小さいため、現在のソリューションは、組み込みオペレーティング環境全体をホスティング用の保守的な GC アルゴリズムに直接接続することです。