Auto-Editor を Haiku でビルドする ― FFmpeg メガビルドと向き合う

みなさん、こんにちは。

先日の記事「Haiku で msxterm をビルドする」では Haiku へ比較的小規模なRustアプリの移植をお届けしましたが、今回はさらにハードルを上げた大がかりなチャレンジの記録です。

今回は、Nim 製の自動動画編集ツール auto-editor を Haiku 上でビルドしてみました!

msxterm が単体の小さなターミナルソフトだったのに対し、auto-editor は FFmpeg 本体に加えて whisper.cpp、SVT-AV1、x264、x265、libvpx、opus、lame といった C/C++ の依存ライブラリをソースから丸ごとビルドする という、非常に大がかりな nimble タスク(nimble makeff)を抱えています。依存関係の数だけ Haiku 特有のつまずきポイントがあり、1つ直しては次が出てくる……というまさに格闘の連続でした。

作業自体は Claude Code に任せた部分がほとんどですが、自分自身の理解を深めるためにも躓いた点をまとめておきたいと思います。

ちょっとした前提と注意点

auto-editor は非常に活発に開発が続いているプロジェクトです。今回作業に使ったソースは数ヶ月前にLinuxでビルドした時のものですが、その後の最新版を覗いてみると既に 300 コミット以上進んでおり、SVT-AV1 のバージョンアップに伴うオプション追加や列挙子名の変更など、直し方が変わっている部分がありました。

そのため、今回は本家からForkしてコードを公開することは止めました。

かわりに、「Haiku でこの種のメガビルドに挑むとき、どうやって原因を切り分けていったか」というトライアンドエラーの考え方として読んでいただければと思います!

まずは作業前に、Haiku のパッケージ管理(HaikuDepot / pkgman)から Nim 環境やビルドツールをインストールしておきます。

pkgman install nim
pkgman install cmake meson ninja

環境が整ったら、いよいよビルドに挑みます。

auto-editor のビルドは大きく2段階に分かれています。

  • nimble makeff
    • FFmpeg 本体とコーデック用依存ライブラリ群をソースからビルドし、番地としての静的ライブラリを build/lib 以下に配置する(時間のかかる重い処理)
  • nimble make
    • src/ 以下の Nim コード(auto-editor 本体)をコンパイルし、build/lib のライブラリとリンクして実行ファイルを作る

ここからは、nimble makeff の中で遭遇した問題から順に振り返っていきます。


問題1. whisper だけ .pc はあるのにヘッダもライブラリも無い!

最初の関門は、nimble makeff を流していたときに FFmpeg の configure で起きたこのエラーでした。

ERROR: whisper >= 1.7.5 not found using pkg-config

手元で pkg-config --modversion whisper を叩くと正しいバージョンが返ってきますし、whisper.pc の中身も一見正常です。詳しく調べると、configure が実際に行っていたのは pkg-config の存在確認だけでなく、実際に whisper.h を #include してコンパイルできるかのテストでした。

BEGIN /tmp/ffconf.xxx/test.c
    1 #include <whisper.h>
...
fatal error: whisper.h: No such file or directory

なんと build/include/whisper.h も build/lib/libwhisper.a も存在せず、.pc ファイルだけがポツンと取り残されている状態でした。

原因は過去の自分自身でした。以前、whisper の CMake 設定をデバッグするためにビルドディレクトリ(build/pkg/whisper)で cmake を手動実行していたのですが、そのときに残った CMakeCache.txt を nimble 側が「このパッケージはすでにビルド済みだ」と誤認してしまっていたのです。

ae.nimble 側の該当処理は次のような構造になっていました。

withDir cmakeBuildDir:
  if not fileExists("CMakeCache.txt"):
    let cmakeCmd = "cmake " & cmakeArgs.join(" ") & " " & sourceDir
    exec cmakeCmd
    makeInstall()

CMakeCache.txt さえあれば cmake の実行も make install も丸ごとスキップされ、.pc ファイルの生成だけが別の後処理で無条件に行われていたため、「ファイルはあるのに実体がない」という紛らわしい状態になっていました。

【対応】
build/pkg/whisper ごとディレクトリを削除し、クリーンな状態から再ビルドして無事に解決しました。デバッグ用には別ディレクトリを切るか、終わったら必ず綺麗に掃除するべきですね。


問題2. SVT-AV1 の -fstack-protector-strong が巻き起こす連鎖失敗

次にぶつかったのは、SVT-AV1(libsvtav1)の CMake 設定での大量のエラーでした。

-- Performing Test HAVE_BUILTIN_EXPECT - Failed
-- Performing Test HAVE_BUILTIN_ASSUME - Failed
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Checking C flag support for: [-msse2] - No
...
CMake Error at Source/Lib/CMakeLists.txt (target_link_libraries):
  Target "SvtAv1Enc" links to: Threads::Threads
  but the target was not found.

__builtin_expect も pthread も、GCC 13 なら本来普通に使えるはずなのに軒並み失敗しています。これは「個々の機能がない」のではなく、「最初に行われた何気ないリンクテストが失敗したせいで、以後のすべての機能テストが巻き添えで失敗扱いになった」 というパターンでした。

cmake --debug-trycompile でテスト用ディレクトリを残して直接 make VERBOSE=1 を実行し、実際のリンクコマンドを追うと原因が判明しました。

/bin/cc -fstack-protector-strong ... CMakeFiles/cmTC_xxx.dir/src.c.o -o cmTC_xxx
.../ld: cannot find -lssp_nonshared: No such file or directory

GCC は -fstack-protector-strong を使うと、glibc系環境では自動的にスタック保護用の補助ライブラリ -lssp_nonshared をリンクしようとします。しかし Haiku の libroot はこの仕組みを別ライブラリに分離せず自前で実装しているため、libssp_nonshared 自体が存在しません。たったこの1つのフラグのせいで、以降のあらゆる試験コンパイルがリンクの時点でコケていたのです。

SVT-AV1 の CMakeLists.txt を見ると、該当箇所は条件分岐なしで無条件にこのフラグを追加していました。

if(MINGW)
    check_flags_add(C -mxsave -fno-asynchronous-unwind-tables)
else()
    check_both_flags_add(-fstack-protector-strong)
    ...
endif()

【対応】
ここを Haiku だけ迂回するように直接パッチを当てました。

     if(MINGW)
         check_flags_add(C -mxsave -fno-asynchronous-unwind-tables)
     else()
+        if(NOT CMAKE_SYSTEM_NAME STREQUAL "Haiku")
         check_both_flags_add(-fstack-protector-strong)
+        endif()
         if(NOT EMSCRIPTEN)

auto-editor の ae.nimble には他の依存ライブラリ向けにパッチを自動適用する仕組み(patches/{package名}.patch)が元々用意されていたので、patches/libsvtav1.patch として配置し、ビルドの度に自動適用されるようにしました。


問題3. 不要なハードウェアアクセラレーションの無効化

次に現れたのは、ハードウェアエンコード関連のエラーです。

ERROR: libvpl >= 2.6 not found
ERROR: nvenc requested, but not all dependencies are satisfied: ffnvcodec

どちらも、私の検証環境(AMD Ryzen + Haiku)には存在しない、ベンダー固有の機能でした。

  • libvpl(Intel QuickSync用)
    • ae.nimble には元々 DISABLE_VPL=1 という環境変数で無効化する仕組みがあったので、これをビルド時に指定するだけでクリア。
  • nvenc / AMD AMF
    • Haiku を除外する判定がそもそも書かれておらず、x86_64 というだけで無条件に有効化されていました。こちらは ae.nimble 側に Haiku 除外の条件を追加しました。
# 修正例
elif kind != armv7 and kind != llvmWin and not defined(haiku):
    enableEncoders.add "av1_nvenc,h264_nvenc,hevc_nvenc"

問題4. Haiku の実行ファイルは、内部的に「shared object」である!

ここまでの苦労で nimble makeff は無事に完走し、FFmpeg 一式がビルドできました。しかし、auto-editor 本体をビルドする nimble make の最終リンクの段階で、今回の中では一番 Haiku 特有といえるエラーに直面しました。

.../ld: ./build/lib/libavcodec.a(simple_idct10.o): relocation R_X86_64_PC32 against
symbol `ff_pw_32' can not be used when making a shared object; recompile with -fPIC
collect2: error: ld returned 1 exit status

「shared object を作る際には使えない」……?

auto-editor は普通の単体実行ファイルをビルドしているはずなのに、リンカはまるで共有ライブラリを作っているかのように振る舞っています。

これは Haiku の GCC ポートの仕様で、Haiku では通常の実行ファイルも内部的に -shared オプション付きでリンクされるというローダーの構造に起因しています。試しに素の cc test.c -o test -v を叩くと、裏側で呼ばれる collect2 には確かに -shared が含まれています。

つまり、Haiku 上でリンクされるあらゆる実行ファイルは、事実上「すべての静的ライブラリが -fPIC(位置独立コード)でコンパイルされていること」を要求されます。しかし FFmpeg や x264、x265、SVT-AV1 などの依存ライブラリはデフォルトで非 PIC になっているため、ここで引っかかっていたのです。

【対応】
依存ライブラリのビルドシステムごとに合わせて、計4箇所の修正を行いました。

  • CMake ベース(whisper, libsvtav1)
    • "-DCMAKE_POSITION_INDEPENDENT_CODE=ON" を追加。
  • x265 専用ビルド関数
    • 同様に -DCMAKE_POSITION_INDEPENDENT_CODE=ON を追加。
  • FFmpeg 本体の configure
    • --enable-pic を追加。
  • autotools ベース(x264, libvpx, opus, lame)
    • x264 や libvpx には --enable-pic、libtool ベースの opus や lame には --with-pic を動的に付与。

これで依存ライブラリを一式 PIC 付きで作り直しました。


問題5. 最後に1つだけ残った NASM アセンブリのリロケーション問題

すべてをクリーンにして再ビルドしたところ、ほとんどのエラーは消えたものの、先ほどの simple_idct10.o のエラーだけが1点だけ再発しました。ビルドログをよく見ると、このファイルは C 言語ではなく X86ASM(NASM 製のアセンブリファイル) としてコンパイルされていました。

X86ASM  libavcodec/x86/simple_idct10.o

--enable-pic は C コンパイラ用のフラグであり、NASM には -DPIC という定義を別途渡す必要があります。しかし FFmpeg の configure は、NASM 用の X86ASMFLAGS に PIC 用フラグを追加するロジックを持っていませんでした(Linux の ld はそのあたりを寛容に扱うため問題にならなかったようです)。

ここを configure スクリプト側で根本から直すのは影響範囲が広いため、今回は最終リンクの段階でリンカに歩み寄ってもらう解決策をとりました。

switch("passL", "-Wl,-Bsymbolic")

-Bsymbolic を指定することで、実行ファイル内部のシンボル参照を外部から上書きされないものとして直接解決させ、ff_pw_32 のような内部定数への R_X86_64_PC32 参照が無事に通るようになりました!

そしてついに……!

$ ./auto-editor --version
31.0.1

$ ./auto-editor info example.mp4
example.mp4:
 - video:
   - track 0:
     - codec: h264
     - resolution: 1280x720
     ...

無事に実際の mp4 ファイルの情報を読み取り、デコードできることを確認できました。Haiku 上で動く FFmpeg と auto-editor の誕生です!


今回のトラブルと対応一覧

No症状原因対応
1whisper の .pc はあるのに実体がない手動デバッグ時の残骸 (CMakeCache.txt) を nimble が誤認ビルドディレクトリを削除してクリーンビルド
2SVT-AV1 の全チェックが連鎖的に失敗-fstack-protector-strong が -lssp_nonshared(Haiku未提供)を要求CMakeLists.txt に Haiku 除外ガードを追加するパッチを作成
3libvpl not foundIntel専用 QuickSync が AMD 環境で動作しようとした既存の DISABLE_VPL=1 を指定して無効化
4nvenc 等の依存エラーベンダー固有のハードウェア支援が無条件で有効化されていたスクリプトのターゲット判定に and not defined(haiku) を追加
5最終リンクで can not be used when making a shared objectHaiku の実行ファイル仕様(内部的に shared object)により全静的ライブラリに PIC が必要各ビルドシステムの引数に PIC 有効化フラグを追加
6simple_idct10.o だけ同じエラーが再発FFmpeg の configure が NASM 用フラグに -DPIC を追加し忘れる仕様リンク時に -Wl,-Bsymbolic を追加してシンボル参照を強制解決

ひとつひとつの原因は小さくても、FFmpeg のような巨大な依存ツリーを持つプロジェクトでは、こうした「Haiku だから起きる違い」が積もり積もってやってきます。特に問題2や問題5のように「大量の失敗が連鎖する」トラブルでは、エラーメッセージをそのまま信じず、VERBOSE=1 などで実際のコンパイラやリンカの挙動を追うことが大切だと改めて実感しました。

記事の冒頭でも触れた通り、auto-editor は日夜すごい勢いで進化しているプロジェクトです。この記事が「この通りやれば一発で動くレシピ」というよりは、「Haiku でメガビルドに挑むとき、どこを疑ってどう切り分けていくか」という視点の参考になれば幸いです。

本日も最後までお読みいただきありがとうございました。

それでは、よい Haiku OSライフを!


「今回の記事を読んで自分も何か作ってみたい」と思われた方、そのアイデア、頭の中で寝かせておくのはもったいないかもしれません。

ビューローみかみでは、構想段階の壁打ちからPoC・実装・現場導入まで、現場で「使い続けられる」ものづくりを支援しています。

アイデアを短期間で「動くもの」にし、PoCで終わらせず、実運用まで伴走します。まずは「これ、作る価値ありますか?」という壁打ちからでも大歓迎です。

▶ PoC・MVP開発サービスの詳細はこちら

気になることがあればお気軽にご相談ください。

カテゴリ: その他

コメントする

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

上部へスクロール