😺

M1 MacでのNode.js/Pythonネイティブモジュールビルド失敗(gyp ERR!)を解決する

に公開

M1 MacでのNode.js/Pythonネイティブモジュールビルド失敗(gyp ERR!)を解決する

はじめに

本稿は、特定の開発環境において、Node.js (npm) および Python (pip) のネイティブモジュールを含むパッケージのインストール時に発生するビルドエラー、特に gyp ERR! で始まるエラーの解決策を記録するものである。

本稿が対象とする環境は以下の通りである。

  • マシン: MacBook Pro (14-inch, M1 Pro)
  • OS: macOS Sequoia 15.6
  • シェル: Zsh (macOS標準)
  • Node.js: v20.12.2 (nvm 0.39.7経由でインストール)
  • Python: 3.11.8 (pyenv 2.4.0経由でインストール)

この環境下で npm install または pip install を実行した際、C/C++で記述されたネイティブアドオンのコンパイルに失敗し、インストールが中断される事象が確認された。

原因

この問題の主な原因は、Apple M1 (arm64) アーキテクチャと、従来のIntel (x86_64) アーキテクチャ向けに設計されたビルドシステムやライブラリとの間の非互換性にある。

  1. ビルドツールの設定不備:
    gyp は、Node.jsのネイティブアドオンをビルドするためのツールである。これが参照するXcode Command Line Toolsのパスや、macOS SDKのバージョンが正しく設定されていない場合、ビルドプロセスを開始できない。

  2. 依存ライブラリの欠如またはパスの不一致:
    ネイティブモジュールが依存する外部ライブラリ(例: OpenSSL, zlib)がHomebrew経由でインストールされている場合、そのライブラリへのパスがコンパイラに正しく渡されないことがある。arm64版のHomebrewは /opt/homebrew ディレクトリにパッケージをインストールするため、このパスを明示的に指定する必要がある。

  3. アーキテクチャの非互換性:
    一部の古いパッケージはarm64アーキテクチャに正式対応しておらず、x86_64環境でのビルドを前提としている。このようなパッケージをarm64ネイティブ環境でビルドしようとすると失敗することがある。

解決策

問題の状況に応じて、以下の手順を試行する。

解決策1: Xcode Command Line Toolsの確認と再設定

ビルドツールチェインの基本的な問題を解決するため、Xcode Command Line Toolsの状態を確認し、必要であれば再インストールする。

  1. Command Line Toolsのインストールパスを確認する。

    xcode-select -p
    

    期待される出力は /Library/Developer/CommandLineTools である。異なるパスが表示されるか、エラーが発生した場合は次の手順に進む。

  2. Command Line Toolsをインストールまたは再インストールする。

    xcode-select --install
    

    GUIのインストーラが起動するので、指示に従ってインストールを完了させる。

  3. インストール後、アクティブな開発者ディレクトリのパスをリセットする。

    sudo xcode-select --reset
    

    この操作により、システムが正しいツールチェインを参照するようになる。

解決策2: 依存ライブラリのパスを環境変数で指定

Homebrewでインストールしたライブラリをビルドプロセスが発見できない場合、コンパイラフラグを通じてパスを明示的に指定する。これは、OpenSSLやzlibなどのライブラリに依存するパッケージで有効である。

  1. arm64版Homebrewのインストール先 (/opt/homebrew) を参照するよう、環境変数 LDFLAGS (リンカフラグ) と CPPFLAGS (Cプリプロセッサフラグ) を設定する。

    export LDFLAGS="-L/opt/homebrew/lib"
    export CPPFLAGS="-I/opt/homebrew/include"
    
  2. 特定のライブラリ(例: openssl@3)をリンクする必要がある場合は、より具体的なパスを指定する。

    export LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib"
    export CPPFLAGS="-I/opt/homebrew/opt/openssl@3/include"
    
  3. 設定後、同じターミナルセッションでインストールコマンドを再実行する。

    # Node.jsの場合
    npm install
    
    # Pythonの場合
    pip install <package_name>
    

この設定を恒久的に適用する場合は、~/.zshrc ファイルに上記 export コマンドを追記する。

解決策3: Rosetta 2を利用したx86_64環境でのビルド

arm64ネイティブでのビルドが成功しないレガシーなパッケージの場合、Rosetta 2を利用してx86_64アーキテクチャとしてビルドプロセス全体を実行する。

  1. arch コマンドを使用して、x86_64アーキテクチャで動作する新しいZshセッションを開始する。

    arch -x86_64 zsh
    
  2. プロンプトが新しいシェルに切り替わったら、その環境でパッケージのインストールを試みる。このシェル内では、Homebrewを含めすべてのコマンドがIntel版として実行される(Intel版Homebrewが /usr/local にインストールされている場合)。

    # このx86_64シェル内で実行
    npm install
    # または
    pip install <package_name>
    
  3. インストール完了後、exit コマンドでこのシェルを終了し、通常のarm64ネイティブ環境に戻る。

この方法でインストールされたモジュールはx86_64バイナリであるため、アプリケーションの実行も arch -x86_64 node ... のようにRosetta 2経由で行う必要がある場合がある。

まとめ

M1 (arm64) Mac環境でのネイティブモジュールビルド失敗は、多くの場合、ビルドツールチェインの設定を見直すことで解決可能である。第一の選択肢は、Xcode Command Line Toolsを正しく設定し、Homebrewで管理されている依存ライブラリへのパスを明示することで、arm64ネイティブでのビルドを成功させることである。これが困難な場合に限り、Rosetta 2を用いたx86_64エミュレーション環境でのビルドを検討する。

参照

Discussion