
刚换到 M1 芯片的 Mac 时我做的第一件事就是拉下一个 iOS 工程跑pod install结果一连串报错直接把终端刷成了天书。那段时间在群里问了一圈发现几乎每台 M1 上都倒下过一批人报错五花八门但根源都指向同一个东西CocoaPods 这套 Ruby gem 生态在 Apple Silicon 上的架构兼容性。这篇文章就聚焦一个主题M1以及后续的 M2、M3 系列上pod install报错的完整解法。我会把我在实际项目里碰到的典型报错、排查思路、最终能稳定跑通的配置都写出来也会解释每一步操作背后的逻辑。不管你是刚拿到 M1 的新手还是从 Intel 迁移过来的老开发这套流程照着走基本都能把问题解决。1. 先说清楚M1 上 pod install 到底是怎么挂掉的很多人在 M1 上第一次装 CocoaPods会用 Intel 时代的旧习惯把 Terminal 切换到 Rosetta 模式、装一个 x86_64 的 Homebrew然后sudo gem install cocoapods。这套操作在某些场景下确实能跑通但会让你的开发环境变得很奇怪而且会引出更多问题。1.1 这不等同于 Intel Mac 的普通报错M1 上的报错和 Intel 时代最常见的“gem 权限不足”“源不对”完全不一样。Intel 机器上的问题大多是 Ruby 版本太低、gem 源被墙、或者某个依赖包没装全通常搜几个sudo gem install命令就能解决。M1 的问题则集中在 CPU 指令集差异上Intel 装的是 x86_64 的二进制M1 上 Apple Silicon 原生跑的是 arm64。问题就在这个“差异”上。如果你用的是 M1 原生 Terminal系统的/usr/bin/ruby是给这个 arm64 环境使用的但很多 gem 的原生扩展库尤其是ffi默认安装时会去编译 x86_64 版本结果在 arm64 的 Ruby 进程中加载失败直接抛出一堆晦涩的崩溃信息。更麻烦的是很多人为了解决这个问题会切换到 Rosetta 终端这样 gem 又被装到了另一个架构的路径下。两边架构的 gem 互相污染最后就是pod命令时而存在时而不存在报错信息还每次都不一样。1.2 我踩过的典型报错清单先把常见报错摆出来方便你对号入座报错信息出现阶段根因bad CPU type in executable安装 gem 后运行 pod当前 shell 是 arm64但 pod/pod 依赖的原生扩展是 x86_64Errno::EPERM: Operation not permitted apply2filespod install执行中途旧版 activesupport / 系统文件权限冲突xcrun: error: invalid active developer path任何需要编译的阶段Xcode 命令行工具没装好或路径失效Failed to build gem native extension/ffi编译失败gem install时Ruby 原生扩展编译失败多半是 ffi 或相关依赖不兼容pod: command not found换终端后gem 装到了不同架构/不同用户目录下PATH 不一致Killed或进程崩溃无输出pod install执行时内存/线程模型问题常见于 Rosetta 环境看到这些报错不要慌。它们没有一个需要重装系统或换电脑来修只需要搞清楚“你的机器上到底跑的是哪套 Ruby、哪套 gem、哪套依赖库”然后统一架构问题自然消失。2. 为什么推荐“优先走原生 arm64”而非无脑 Rosetta先说结论现在的 CocoaPods 版本1.11.0 之后已经完整支持 Apple Silicon你完全可以用原生 arm64 环境跑pod install不需要把终端切成 Rosetta。只有极少数场景才需要退回 x86_64比如某些老旧的闭源第三方 SDK 只发布了 x86_64 的静态库并硬性要求在 x86 环境编译。遇到这种情况我会单独开一个 Rosetta shell其余情况下都推荐原生 arm64。2.1 底层原因CocoaPods 本身是 Ruby gem而 gem 能不能在 arm64 下跑取决于它的原生扩展。核心依赖ffi在 1.15.0 版本之后提供了 arm64-darwin 的预编译二进制这是官方社区修复的里程碑。紧随其后的依赖如activesupport也早已消除对旧版 Ruby 的依赖。所以只要你装的 CocoaPods 版本足够新就完全没必要再委屈自己跑 x86 环境。我见过两个看起来很唬人但其实是自欺欺人的操作第一把整个 Homebrew 装成 x86_64。这样 brew 和 gem 全走 Rosetta确实兼容但每次运行都损耗性能而且以后所有安装都要用arch -x86_64前缀连路径都分裂成/usr/localx86和/opt/homebrewarm64两套。第二装两套 Ruby 两套 gemset一套跑 arm64、一套跑 x86。这在多项目管理里是灾难你永远搞不清当前终端用的是哪边。2.2 什么时候必须从 x86 转成 Apple Silicon坦白讲2023 年之后的方案已经很少需要手动切 Rosetta 了。我只坚持一种例外情况如果你的某个 Pod 依赖在pod install时强制生成x86_64的二进制 Framework并且供应商没有给出 Apple Silicon 版本那么只在这一步上临时用 Rosetta 终端执行arch -x86_64 pod install注意这只影响当前命令行进程不会污染你的环境。跑完这个命令之后我还是会把默认终端切回 arm64 模式在原生环境下继续日常开发。3. 完整操作从零把 CocoaPods 在 M1 上装到能跑下面我把一次完整的、最稳妥的 CocoaPods 安装流程写出来。这套流程我在 M1 和 M2 上都实测过适用于目前绝大多数 iOS 项目。3.1 第一步确定 Apple Silicon 需要的系统环境首先确认你的 Mac 是 arm64 架构uname -m如果输出arm64说明你在 Apple Silicon 原生终端里。如果输出x86_64说明当前终端运行在 Rosetta 下需要先退出 Rosetta 模式重开 Terminal。接着确认 Xcode 命令行工具xcode-select -p正常应该输出类似/Applications/Xcode.app/Contents/Developer。如果输出报错或者提示找不到路径执行sudo xcode-select --reset sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer这一步卡住的概率很高因为不少人是刚装了 Xcode 但命令行工具还未完成初始化pod install一跑到编译阶段就直接挂掉。3.2 第二步通过 Ruby 版本管理器安装 Ruby我强烈不建议直接用系统自带的/usr/bin/ruby。它是 Apple 为系统工具保留的 Ruby 2.6不仅版本旧而且权限管理很别扭sudo gem install装完以后经常因为系统签名问题写不进 /usr/bin 外的地方。用 Ruby 版本管理器是最干净的方案。我常用的是rbenv因为它没有rvm那么重也不要求 shell 函数注入。先安装 rbenvbrew install rbenv ruby-build然后初始化rbenv init按提示把eval $(rbenv init -)写进~/.zshrc。接下来安装一个较新的 Ruby。这里有个参数要特别注意不要装 2.6 之前的老版本也不要装太新的预览版。我当时用的版本是 3.x 稳定版通过rbenv install 3.2.2 rbenv global 3.2.2rbenv global会切换当前用户默认 Ruby不会影响系统其他脚本所以很安全。安装完成后检查ruby -v which rubywhich ruby应该指向~/.rbenv/shims/ruby而不是/usr/bin/ruby。如果还在系统路径说明rbenv init没生效检查~/.zshrc里的顺序或者直接重启终端。3.3 第三步更换 gem 源并安装 CocoaPods国内网络环境下建议先把 gem 源换成可访问的镜像源避免下载依赖时卡死。命令行执行gem sources --remove https://rubygems.org/ gem sources --add 你的可用镜像源地址这里我不过分推荐某个具体源你自己验证可用即可。换源后安装 CocoaPodsgem install cocoapods安装完成后关键一步是重新加载 shimrbenv rehash pod --version如果pod输出了版本号那么基础安装就成功了。这里我可以分享一个容易踩的坑rbenv rehash忘记执行会导致pod命令明明存在但就是找不到大多数“装完后 command not found”其实都是这一步漏了。3.4 修复 ffi 与原生扩展的构建问题很多 M1 用户的pod install报错其实发生在gem install cocoapods过程中或者首次运行时的 ffi 编译失败。我在 Rosetta 环境下遇到过这种情况在原生 arm64 下也遇到过。如果编译 ffi 失败可以尝试指定安装带预编译二进制的版本gem install ffi -v 1.15.5然后再装 CocoaPodsgem install cocoapods -v 最新的稳定版本号如果你们项目对这个 ffi 和我一样遇到过Failed to build gem native extension还有一个很阴间的细节旧版本的 Command Line Tools 会在 arm64 上错误地选择 x86_64 的编译器。那就升级命令行工具sudo rm -rf /Library/Developer/CommandLineTools sudo xcode-select --install升级完之后重新编译一次 ffi基本都能过。注意不要删掉 Xcode 自带的 developer path只清理和重装 CommandLineTools 就够。4. 实操过程与核心环节实现理论讲完下面是一套可以“照着抄”的完整实操流程。我会穿插说明每步检查的目的这样你能根据自己的报错卡在哪一步来动态调整。4.1 全终端路径检查在项目目录跑pod install之前先给终端做一个体检uname -m # 必须是 arm64除非你明确要用 Rosetta which ruby # 必须是 rbenv shims 路径 ruby -v # 建议 2.7 which pod # 必须是 gem 安装到的路径 bundle --version # 如果项目有 Gemfile这四行命令的输出确定了下面几件事CPU 架构、Ruby 解释器来源、pod 可执行文件位置、依赖管理方式。任何一个输出不符合预期都不要急着开跑先修正环境比事后排查快得多。如果你的项目里有Gemfile我建议在bundle init生成的 Gemfile 里补一行 ruby 版本约束避免同事在不同 Mac 上用不同版本的 Ruby 导致 Podfile.lock 里记录出不一致的结果。4.2 安装脚本和配置解析我习惯把下面的内容写成一个setup.sh脚本放到团队仓库根目录新成员 clone 完项目直接执行#!/bin/zsh set -e # 检查架构 if [[ $(uname -m) ! arm64 ]]; then echo 请在 Apple Silicon 原生终端中运行 exit 1 fi # 检查 Xcode 路径 xcode-select -p /dev/null 21 || echo 请先安装 Xcode # 安装依赖 brew install rbenv ruby-build eval $(rbenv init -) rbenv install 3.2.2 --skip-existing rbenv global 3.2.2 rbenv rehash # 安装 CocoaPods gem install bundler bundle install bundle exec pod install --repo-update注意这里有两个细节。第一我用bundle exec pod install而不是裸pod install这样能确保项目使用的是 Gemfile 中锁定的 CocoaPods 版本而不是系统里哪个“最新”版本。第二--repo-update只在你首次拉取项目时加日常开发不要每次加否则每次都会去拉全量 spec 仓库非常耗时。团队协作时如果你们不打算引入 Gemfile至少把 CocoaPods 大版本固定下来。可以写.swift-version或.ruby-version帮助不同成员的 rbenv 自动切到正确的 Ruby 版本。4.3 pod install 实战环境配好后进入工程目录拉依赖cd /path/to/your/ios_project pod install我见过 M1 上跑pod install一次失败第二次就成功的情况原因是第一次执行时 Homebrew 会做brew update网络慢的话会超时。如果你在国内网络环境可以先把 pod repo 更新限制住git config --global --add url.你的镜像地址.insteadOf https://github.com/但这属于网络基础设施配置不建议在团队脚本里写死只在个人环境手动调整即可。第一次pod install成功之后之后每次安装依赖都会快很多。如果中途你还是遇到坑就往下一节看基本都是同一个根因的不同变体。5. 常见问题与排查技巧实录这里整理我在 M1 上遇到的、以及在帮别人排查过程中见过的典型问题。5.1zsh: bad CPU type in executable与 x86 gem 残留这个报错非常典型说明当前终端是 arm64但你执行的某个可执行文件是 x86_64 架构macOS 拒绝运行。它经常出现在你曾经在 Rosetta 终端里安装过 CocoaPods、后来换回原生终端的环境里。排查思路是两个方向。第一移除 Rosetta 环境下的 gem 残留arch -x86_64 gem list cocoapods如果列出来有版本说明 Rosetta 环境装过一份。对应清理方式是直接在 Rosetta 模式下卸载arch -x86_64 gem uninstall cocoapods第二检查当前pod可执行文件的架构file $(which pod)如果输出里包含x86_64说明 gem 装错了环境。最干净的解决办法是删掉重新用 arm64 装一遍不要保留两个架构的版本。5.2Errno::EPERM: Operation not permitted apply2files这个报错曾经是我排查最久的问题。它发生在pod install中段看着像是文件权限不够但用户已经是管理员权限。最后定位到是旧版activesupportgem 在复制文件时调用了系统不支持的 API。解决方案是升级 activesupportgem uninstall activesupport gem install activesupport -v 6.1.7.3或者更简单直接把 CocoaPods 升级到新版新版依赖的 activesupport 不再触发这个 API。实践下来升级 CocoaPods 到 1.12 以上后Errno::EPERM基本绝迹。5.3xcrun: error: invalid active developer path这个报错多数发生在升级系统或升级 Xcode 之后。CocoaPods 要调用 xcrun 去查询 SDK 路径而 CommandLineTools 的路径失效了。执行sudo xcode-select --reset之后验证xcode-select -p xcrun --show-sdk-path如果xcrun --show-sdk-path还是空就需要重装命令行工具。注意重装后重新执行gem install cocoapods或重新编译原生扩展否则 ffi 的编译缓存里还记录着旧路径。5.4 Ruby 2.6 已停止维护后怎么办M1 上市时的 macOS 自带 Ruby 2.6很多人接手老项目时还被锁定在这个版本。Ruby 2.6 对 Apple Silicon 的支持不完整而且官方早已停止维护再遇到 ffi 之类的原生依赖构建问题几乎是无解的。我的建议是不要守旧直接在容器里用 rbenv 装新 Ruby。如果你实在拗不过项目里的.ruby-version约束我的操作习惯是在项目根目录放一个.ruby-version文件指向项目要求的版本然后用rbenv local切版本。项目内部版本切换和全局版本互不干扰老项目也能在新机器上安心跑。5.5 需要注意 Pods 的架构信息最后提醒一个非常容易被忽略的点M1 上pod install成功不等于构建成功。当你执行 Xcode 构建时如果遇到Building for iOS Simulator, but the linked library ... was built for iOSUndefined symbols for architecture x86_64这通常是 Pod 里的静态库架构不匹配。CocoaPods 是帮你构建依赖的但最终产物是否支持模拟器 arm64取决于每个 Pod 的设置。你可以打开 Xcode 的Build Settings查看VALID_ARCHS和EXCLUDED_ARCHS。我的经验做法在 Podfile 顶部为 framework 设置post_install do |installer| installer.pods_project.targets.each do |target| target.build_configurations.each do |config| config.build_settings[IPHONEOS_DEPLOYMENT_TARGET] 12.0 end end end这里顺手把部署版本统一到 12.0 以上避免某些老依赖在 iOS 版本上出现兼容问题。架构问题如果还出现再在 Build Settings 里确认ONLY_ACTIVE_ARCH是否为 YES模拟器 Debug 下应保持 YES避免同时编译多个架构导致报错。6. 把配置固化下来到此M1 上pod install已经能跑通了。但环境的稳定性还需要你把配置固化。我最后贴一段日常项目里会直接复制进~/.zshrc的环境配置。6.1 添加环境变量和 PATHexport PATH$HOME/.rbenv/shims:$PATH eval $(rbenv init -) export LDFLAGS-L/opt/homebrew/opt/openssl3/lib export CPPFLAGS-I/opt/homebrew/opt/openssl3/includeopenssl环境变量是为了保证某些原生 gem 在编译时能找到正确的头文件和库文件。M1 的 Homebrew 默认装到/opt/homebrew如果你发现装 gem 时经常卡在 openssl 相关的编译报错这两个环境变量就能救你一次。我个人还喜欢加一个函数用来一键进入 Rosetta 环境处理老依赖alias x86arch -x86_64 zsh这样只要极少数的老 SDK 场景才切 x86平时都是原生环境。6.2 日常操作脚本模板每次新建 iOS 工程我建议按以下步骤走能避免一大半环境问题git clone 项目地址 cd 项目目录 rbenv local 3.2.2 gem install bundler bundle install bundle exec pod install如果你的项目没有 Gemfile就直接gem install cocoapods pod install记得在项目的Podfile里加上固定版本注释例如团队成员统一使用 1.12.1避免有人 auto-update 到不同版本造成 Podfile.lock 冲突。6.3 关于团队协作的建议最后给新入行的开发者一句实际经验碰到 M1 上的 pod 问题不要在群里发一张终端报错截图就伸手要答案把uname -m、which ruby、which pod、pod --version四条命令的结果贴出来别人帮你定位的速度会快十倍。我在实际项目中还发现一个额外的好处用 rbenv 管理 Ruby 之后团队里不再出现“我机器上明明装好了怎么你那边就报错”的失配问题。每个人都有独立 Ruby 版本、独立 gemsetpod 相关的问题能从环境层面降到真正的依赖树层面这对长期维护项目来说非常值得。个人体会是M1 上的 CocoaPods 问题90% 以上是环境构建不一致造成的真正需要改代码或改 Podfile 的情况反而是少数。只要统一终端架构、统一 Ruby 版本管理、统一 gem 源日常开发就不会再被 pod 支配。再遇到新的报错时先问自己一句当前这个进程是让哪个架构跑的有没有把 gem 装到对应的 Ruby 里搞清楚这一点后面就都是按图索骥了。