View on GitHub

cat-oscillator-sync

cat-oscillator-sync

Go版PortAudio CGO要件の調査報告

問題の本質

gordonklaus/portaudio パッケージはCGO(C言語バインディング)を使用しており、以下のコードでC言語のPortAudioライブラリを直接呼び出しています:

/*
#cgo pkg-config: portaudio-2.0
#include <portaudio.h>
extern PaStreamCallback* paStreamCallback;
*/
import "C"

CGOとは何か

重要: CGOは「Goのexeをビルドする際に、C言語コンパイラを内部的に使用する仕組み」です。

ビルド時の流れ:

  1. go build コマンドを実行
  2. Goコンパイラが gordonklaus/portaudio パッケージ内のCGOコードを発見
  3. C言語コンパイラ(GCC/Clang/MSVC)を呼び出してCGOコードをコンパイル
  4. コンパイルされたCコードとGoコードをリンク
  5. PortAudio DLL(libportaudio64bit.dll)と動的リンク
  6. 最終的なexe(sync_simple.exe)を生成

なぜC言語コンパイラ(GCC)が必要なのか

つまり、「C言語のソースからDLLを作る」のではなく、「Goのexeをビルドする際に、パッケージ内のCGOコードをコンパイルするためにGCCが必要」ということです。

なぜCGOが必要なのか

  1. PortAudioはC言語ライブラリ: オーディオI/Oを扱うPortAudioはC言語で書かれており、Goから直接呼び出せない
  2. Pure GoのPortAudio実装は存在しない: オーディオの低レベル制御は各OS固有のAPIを使う必要があり、Pure Goでの実装は現実的でない
  3. すべてのGo PortAudioバインディングがCGOを使用: 他のパッケージも同様にCGOが必須

調査結果

1. MSBuild(MSVC)での実現可能性

結論: 現状では困難

理由:

実現する場合の要件:

判断: プロジェクトを複雑化させるため推奨しない

2. プリコンパイル済みバイナリの利用

Go言語の制約:

3. 外部リポジトリでstaticライブラリを生成してリンクする案

結論: 解決策にならない

理由:

  1. PortAudio DLLは既に完成したバイナリとして存在
    • download_portaudio.py で取得可能
    • 新たにビルドする必要はない
  2. 問題はCGOコードのコンパイル
    • gordonklaus/portaudio パッケージ内部にCGOコードがある
    • このCGOコードは go build 時に自動的にコンパイルされる
    • CGOコードのコンパイルにGCCが必須
  3. 回避不可能
    • staticライブラリを事前に作っても、CGOコード自体は残る
    • gordonklaus/portaudio を使う限り、ビルド時のGCC要件は変わらない
    • Pure Goのパッケージに移行しない限り回避不可能

補足:

現在のアプローチ:

3. 別プロジェクトでのコンパイル担当

提案: Goバイナリをプリコンパイルして配布する専用プロジェクトを作成

必要なビルドコマンド(Windows)

# 環境設定
set CGO_ENABLED=1
set GOOS=windows
set GOARCH=amd64

# ビルド(GCCが必要)
go build -ldflags="-s -w" -o sync_simple.exe .\cmd\sync_simple
go build -ldflags="-s -w" -o sync_smooth.exe .\cmd\sync_smooth

生成されるバイナリ

配布プロジェクトの構成案

cat-oscillator-sync-go-binaries/
├── .github/
│   └── workflows/
│       └── build.yml          # GitHub Actionsでビルド
├── releases/
│   └── windows/
│       ├── sync_simple.exe
│       ├── sync_smooth.exe
│       └── libportaudio64bit.dll
└── README.md

GitHub Actionsビルド設定例

name: Build Go Binaries

on:
  push:
    tags:
      - 'v*'

jobs:
  build-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Go
        uses: actions/setup-go@v4
        with:
          go-version: '1.21'
      
      - name: Setup MinGW
        uses: msys2/setup-msys2@v2
        with:
          install: mingw-w64-x86_64-gcc
      
      - name: Download PortAudio DLL
        run: python download_portaudio.py
      
      - name: Build
        run: |
          go build -ldflags="-s -w" -o sync_simple.exe .\cmd\sync_simple
          go build -ldflags="-s -w" -o sync_smooth.exe .\cmd\sync_smooth
      
      - name: Upload Release
        uses: softprops/action-gh-release@v1
        with:
          files: |
            sync_simple.exe
            sync_smooth.exe
            bin/libportaudio64bit.dll

本リポジトリでの利用方法

# プリコンパイル版のダウンロード
curl -L -o sync_simple.exe https://github.com/cat2151/cat-oscillator-sync-go-binaries/releases/latest/download/sync_simple.exe
curl -L -o sync_smooth.exe https://github.com/cat2151/cat-oscillator-sync-go-binaries/releases/latest/download/sync_smooth.exe
curl -L -o libportaudio64bit.dll https://github.com/cat2151/cat-oscillator-sync-go-binaries/releases/latest/download/libportaudio64bit.dll

# 実行
.\sync_simple.exe

推奨アプローチ

オプションA: プリコンパイル済みバイナリの配布(推奨)

メリット:

デメリット:

実装手順:

  1. 別リポジトリ cat-oscillator-sync-go-binaries を作成
  2. GitHub Actionsで自動ビルド設定
  3. リリースを作成してバイナリを配布
  4. 本リポジトリの build_and_run.py でバイナリをダウンロード

オプションB: 現状維持(GCC/MinGWが必要)

メリット:

デメリット:

まとめ

  1. CGOは技術的に必須: PortAudioのC言語バインディングのため回避不可
  2. MSBuildは現実的でない: pkg-config依存の問題があり、複雑化する
  3. 最適解: 別プロジェクトでプリコンパイルしたバイナリを配布
  4. 実装が容易: GitHub Actionsで自動化できる

次のステップとして、オプションAの実装をお勧めします。