🚀

miseでCocoaPodsを管理してみた

に公開

mise でrubyを導入するようにしてみた。その流れで、脱Bundlerというほどでもないが CocoaPods をmise経由で導入してみることにした。
miseはGemパッケージのインストールも使えるという。iOS向けの開発をしている自分にとって、最も身近なruby製のツールだ。

環境

  • mise: 2025.7.10 macos-arm64 (2025-07-14)
  • ruby: 3.4.4 が mise によってグローバルインストール済み

試行錯誤の記録

Gemパッケージをインストールしてみる

mise settings experimental=true

が必要だと言われた。

mise use -g gem:cocoapods

たったこれだけでインストールされた。

type -a pod
# pod is /{ホームディレクトリへのパス}/.local/share/mise/installs/gem-cocoapods/1.16.2/bin/pod

どうやら mise/installsgem- のプレフィックスが付いて導入されるらしい。中身を確認してみた。

# インストール先まで移動
cd /{ホームディレクトリへのパス}/.local/share/mise/installs/gem-cocoapods/1.16.2

cat bin/pod
#!/usr/bin/env bash
GEM_HOME="/{ホームディレクトリへのパス}/.local/share/mise/installs/gem-cocoapods/1.16.2/libexec" exec /{ホームディレクトリへのパス}/.local/share/mise/installs/gem-cocoapods/1.16.2/libexec/bin/pod "$@"

GEM_HOME を指定して libexec配下の pod を実行するように包んでいるらしい。libexec配下のpodを見てみる。

#!/{ホームディレクトリへのパス}/.local/share/mise/installs/ruby/3.4.4/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'cocoapods' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require 'rubygems'
# ...

基本的にRubyGemが作る内容らしい。pod以外のファイルも同じフォーマットの内容だった。ただし、冒頭の1行に着目する必要がある。

#!/{ホームディレクトリへのパス}/.local/share/mise/installs/ruby/3.4.4/bin/ruby

shebang がmiseで導入したrubyを指し示している。
つまり「rubyの環境更新だ〜」、といって 3.4.4 をアンインストールしたら壊れるということだ。

一方で、このグローバルインストールした pod については、たとえばruby2のみが有効となる環境においても影響を受けずに実行できそうだ。

また、libexecの他の内容確認してみる。
どうやら cocoapods に関連するものがまとめて隔離されているらしい。いわゆるバンドルされている、ってやつだ。

pwd
# /{ホームディレクトリへのパス}/.local/share/mise/installs/gem-cocoapods/1.16.2

ls libexec
# bin            build_info     cache          doc
# extensions     gems           plugins        specifications

ls libexec/bin
# fuzzy_match httpclient  pod         sandbox-pod xcodeproj

ls libexec/gems
# activesupport-7.2.2.2       bigdecimal-3.2.3
# cocoapods-downloader-2.1    concurrent-ruby-1.3.5
# ...

つまりmiseで導入したRubyの領域にgemが置かれることはない。
複数バージョンのgemを入れたらその分だけ依存パッケージが重複するとみられるが、クリーンな運用に対する代償だろう。

消してみる

ところで cocoapods は別にグローバルに必要ではない。特定のプロジェクトで見えれば十分だ。use の反対は unuse である。

mise unuse -g gem:cocoapods

加えてアンインストールするかというインタラクティブな確認が発生した。消した。

# remove gem:cocoapods@1.16.2 ? Yes
# mise gem:cocoapods@1.16.2 ✓ remove ~/Library/Caches/mise/gem-cocoapods/1.16.2

なんか知らんとこから消えた。

ls ~/.local/share/mise/installs
# node   python ruby   usage

とりあえず消えたらしい。

ローカルインストール→ローカルユース

最小限の場所で有効にしてみる。

cd /path/to/{cocoapodsが必要なプロジェクト}

mise use gem:cocoapods

type -a pod
# pod is /{ホームディレクトリへのパス}/.local/share/mise/installs/gem-cocoapods/1.16.2/bin/pod

なんか見たことあるパスが出てきた。
どうやらmiseによってインストールされるものは installs/ に詰め込まれ、コンテキストに応じてどれが有効になるかをコントロールすることで環境を制御しているらしい。

だから使うときには mise install pkg ではなく mise use pkg なのかと合点がいった。まぁ、「installとは使えるようにするまで含むだろ」という観点もないことはないが、CLIに生きるときってパス通すのは自分の仕事だしな。

PATH方式と呼ばれるらしい

pod はどのように発見されているのかというと、PATHに直接挿入されているらしい。

echo $PATH | tr ':' '\n'
# /{ホームディレクトリへのパス}/.local/share/mise/installs/gem-cocoapods/1.16.2/bin
# ...

必要なバイナリへの到達方法をPATHに挿入することでランタイム管理を実現する場合、PATH方式と呼ばれるらしい。これはプロンプトを表示する度に対応したパスをPATHに挿入することで実行可能にするという。

Shim方式

その他にはShim方式と呼ばれるものがあり、miseは対応しているらしい。
PATH方式は対話型シェルに適しているが、IDEからの利用には適していない。たとえばRunで実行したい node コマンドがPATHから見つけられない、などだ。

そこで、一旦コマンドすべてのシンボリックリンク相当になるものを詰め込んだディレクトリを用意し、それを参照させる。

ls -l /{ホームディレクトリへのパス}/.local/share/mise/shims
# bundle -> /{ホームディレクトリへのパス}/.local/bin/mise
# bundler -> /{ホームディレクトリへのパス}/.local/bin/mise
# ...
# pod -> /{ホームディレクトリへのパス}/.local/bin/mise
# ...

ここに mise でインストールしたコマンドが全て列挙されるが、すべて同じバイナリを指し示す。叩いたコマンドと基点のパスに基づいてコマンドが有効かどうかを別途判定する、ということだろう。

miseのドキュメントShimsに詳しい。

感想

こいつぁ良さそうだ。

メンテナンスモードにも入って、いよいよ役目を終えつつあるCocoaPodsだが、これは依存関係が多い。グローバルに入れると環境が汚れるし、かといって必要なプロジェクト配下にだけbundlerで配置するとあちこちで同じようにゴチャ付いた vendor/bundle が生成されてしまう。

パッケージ単位で、隔離された環境が状況に応じて管理されるため、ほどよく無駄がない。

GitHubで編集を提案

Discussion