Homebrew

安装Homebrew

  • 只要主机联网,通过以下命令就能够直接安装homebrew:

通过网络安装Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

备注

会提示安装 Xcode command tools,请按照提示安装命令行工具,并继续安装Homebrew

备注

安装过程反复出现SSL错误:

==> Downloading and installing Homebrew...
fatal: unable to access 'https://github.com/Homebrew/brew/': LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 54
Failed during: git fetch origin master:refs/remotes/origin/master --tags --force

可能和curl版本有关,参考 cURL SSL_ERROR_SYSCALL (OpenSSLLibreSSL) #4099 尝试:

echo '--no-alpn' > ~/.curlrc
export HOMEBREW_CURLRC=1

有可能再出现error 60,不过那是因为网络超时导致(GFW干扰):

fatal: RPC failed; curl 56 LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 60
fatal: the remote end hung up unexpectedly

警告

实际上在墙内,执行第一步在线安装命令就会出错,原因是GFW屏蔽了 raw.githubusercontent.com 。不过,这个脚本实际上可以下载到本地执行(通过墙外VPS搬运回来)。这样只要开始执行安装脚本,接下来就是如何让 gitcurl 越过长城 了,我在下文提供了解决方法。

安装网络阻塞问题的解决方法

安装Homebrew的最大麻烦是 GFW 对GitHub的干扰(并不是完全不通,但是不断间歇阻塞会浪费大量的时间精力),解决的方法是使用代理。安装脚本中涉及到 curlgit 都需要配置代理。我采用的方法是:

socks代理

采用 SSH Tunneling: 动态端口转发 构建本地socks代理,然后结合简单的 curl代理

  • 我最初采用socks结合squid代理 ( Squid父级socks代理 方案可以在本地构建一个squid代理,通过墙外到二级代理实现无障碍访问),不过感觉对桌面来说有点复杂,所以改为更为简单的 curl代理

执行一条命令建立起动态端口转发的翻墙ssh tunnel
ssh -D 1080 -C user@vpn.example.com
配置curl的socks5代理环境变量
export ALL_PROXY=socks5h://localhost:1080
全局配置git使用socks5代理
git config --global http.proxy 'socks5h://127.0.0.1:1080'

squid代理 Squid父级socks代理

由于墙内访问VPS阻塞严重,所以我改进为采用阿里云墙内服务器转跳方式的 squid代理 Squid父级socks代理 也就是对于本地客户端而言,实际上是通过HTTP代理完成访问的

此外,参考 How to install an homebrew package behind a proxy? 有一个简单设置方法:

配置brew使用代理服务器
export ALL_PROXY=127.0.0.1:3128

或者类似 curl代理 配置环境变量:

配置curl的http/https代理环境变量
export http_proxy=http://127.0.0.1:3128
export https_proxy=$http_proxy
export no_proxy=localhost,127.0.0.0/8,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16

VPN Hotspot (简便且推荐)

我还采用了一种方法是借助 VPN Hotspot ,通过手机VPN共享给局域网使用,使得自己的桌面电脑能够翻墙直接访问Homebrew的软件仓库,才能顺利完成Homebrew安装。

我在完成 Homebrew 安装完成后,立即安装 OpenConnect VPN 客户单 openconnect ,这样可以方便 macOS 翻墙,实现很多必要的软件安装:

brew install openconnect

卸载homebrew

如果需要反向卸载homebrew,官方提供了一个交互方式卸载的脚本:

卸载homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/uninstall.sh)"

使用brew

  • brew使用帮助:

    brew help
    
  • 检查是否存在安装问题:

    brew doctor
    
  • 搜索应用程序:

    brew search
    
  • 安装:

    brew install packgename
    
  • 列出所有Homebrew安装的应用:

    brew list
    
  • 删除应用:

    brew remove packagename
    
  • 更新Homebrew自身:

    brew update
    
  • 查看是否有软件包没有及时更新:

    brew outdated
    
  • 更新所有软件包或单个软件包:

    brew update
    brew update packagename
    
  • 将一个软件包保持在某个版本:

    brew pin packagename
    
  • 解除软件包版本锁定:

    brew unpin packagename
    
  • brew 提供了重启服务的功能,例如重启 macOS中使用Homebrew部署nginx :

使用brew重启nginx
brew services restart nginx

Homebrew Cask

Homebrew Cask 扩展了Homebrew并且将它提升到优雅、简洁、安装迅速,同时提供了管理macOS GUI程序的功能,例如可以安装Atom和Google Chrome。

备注

Homebrew Cask提供了安装图形软件的功能,也就是说,如果要使用 brew install 安装一个macOS上的图形软件,通常就是使用 brew install --cask XXX

例如,安装 macOS安装Docker 中安装Docker Desktop on Mac,应该使用:

通过Homebrew安装Docker Desktop for macOS
brew install --cask docker

如果使用 brew install docker 则只安装docker命令行

  • 不需要单独安装homebrew cask,你只需要使用,例如你想安装 atom 编辑器,则执行:

    brew cask install atom
    

然后你就可以使用atom编辑器了。

不过,2021年时候,使用上述命令会出现报错:

Updating Homebrew...
Error: Unknown command: cask

这是因为最新版本brew已经改变成:

brew install --cask atom

备注

你可以通过 Homebrew Formulae 查看所有cask tap列表。

这省却了我很多查找下载软件的时间,例如,最常用的开发IDE Visual Studio Code就可以直接安装:

brew install --cask visual-studio-code

升级

macOS升级系统,可能会导致brew的软件无法正常工作。例如,出现无法使用vim:

vim
dyld: Library not loaded: /System/Library/Perl/5.28/darwin-thread-multi-2level/CORE/libperl.dylib
  Referenced from: /usr/local/Cellar/macvim/8.2-171/MacVim.app/Contents/MacOS/Vim
  Reason: image not found
[1]    13046 abort      vim

这个报错,我参考 dyld: Library not loaded: libperl.dylib Referenced from: perl5.18 升级 brew 来修复:

brew update
brew upgrade

也可以单独升级某个异常软件:

brew upgrade macvim

软件版本检查

  • 使用 brew info 可以检查仓库提供的软件版本以及本地已经安装版本:

检查仓库和本地安装的openssl版本
brew info openssl

输出显示

可以看到仓库提供了3.3.0版本,本地是3.2.1
==> openssl@3: stable 3.3.0
Cryptography and SSL/TLS Toolkit
https://openssl.org/
Installed
/usr/local/Cellar/openssl@3/3.2.1 (6,876 files, 32.6MB) *
  Built from source on 2024-04-12 at 08:32:49
From: https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/o/[email protected]
License: Apache-2.0
==> Dependencies
Required: ca-certificates ✔
==> Caveats
A CA file has been bootstrapped using certificates from the system
keychain. To add additional certificates, place .pem files in
  /usr/local/etc/openssl@3/certs

and run
  /usr/local/opt/openssl@3/bin/c_rehash
==> Analytics
install: 310,920 (30 days), 1,055,029 (90 days), 4,322,082 (365 days)
install-on-request: 35,788 (30 days), 135,413 (90 days), 641,513 (365 days)
build-error: 4,016 (30 days)

服务起停

brew 提供了一个 services 方式来启动和停止服务以及管理服务的自动启动

  • 通过以下命令 tapping homebrew/services (只需要执行一次):

安装 brew services
brew tap homebrew/services
  • 通过以下命令可启动/停止 nginx 服务,其中 start 命令不仅启动nginx而且会设置nginx随着操作系统启动而启动:

brew 启动和停止nginx
# 启动nginx并且设置自动启动
brew services start nginx

# 停止nginx
brew services stop nginx
  • list 命令可检查当前系统所有服务:

brew 检查系统所有服务
brew services list

输出类似:

brew 检查系统所有服务输出案例
Name       Status  User        File
nginx      started huataihuang ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist
prometheus none
unbound    none

实践和必备安装

brew很好地弥补了 macOS 的开源软件版本滞后的短板,强烈建议在拿到macOS笔记本新系统时完成以下安装:

在macOS新系统必装的brew软件
brew update

# 参考 "Homebrew初始化"
# 按需安装自己需要的工具包
# neovim替换了vim
brew install pssh neovim tmux tree webp gawk gsed openconnect nginx

# 可选安装
brew install --cask keepassxc
#brew install --cask docker
#brew install --cask iterm2
#brew install golang

备注

  • (现在我改为使用 neovim ))macOS内置的vim不支持python3,会导致类似 jedi-vim 缺失错误(即使 Python virtualenv 安装了 jedi 模块也无效),所以强烈推荐Homebrew的vim with-python3。

  • neovim 是现代化vim的实现,目前我采用 neovim 代替 Vim 以便实现快速的IDE构建

  • tmux多会话终端管理 是常用的多路会话软件,虽然从iterm2官网下载安装包也内置了安装 tmux多会话终端管理 功能,但是为了方便升级并使用最新版本,采用 homebrew 来安装 iterm2

  • macOS内置awk和sed,但是语法和GNU版本有差异,编写Linux上运行脚本采用较为通用的GNU版本

  • OpenConnect VPN 客户端方便翻越GFW

  • KeepassXC 是跨平台开源密码管理器

  • iterm2提供了最佳终端 ,可以采用 结合Vim,Tmux,iTerm和Oh-my-Zsh开发环境 (资源消耗太大,放弃)

  • 采用 kitty 作为终端,兼顾快速和便捷

  • Homebrew提供了 Docker Desktop 集成安装,可以方便实现Docker官方版本安装部署(现在改为使用 Colima )

安装必要brew工具
# 实际上只需要安装缺少的tmux和tree
# 其他软件可选安装,只是为了获得比macOS系统默认集成版本更新的官方版本
brew install tmux tree
brew install curl rsync git-svn python3 ruby

# 安装我的devops工具, neovim替换了vim
brew install neovim pssh webp gawk gsed
# 如有需要则安装openconnect nginx

# 可选安装
brew install --cask keepassxc

# 我现在不再使用docker,改为colima
# iterm2太消耗资源,改为alacritty
brew install colima
brew install --cask alacritty

#brew install --cask docker
#brew install --cask iterm2
#brew install golang

安装了homebrew Vimneovim 之后,会依赖安装多种开发语言,其中包括 Python 3的最新版本,比macOS内置版本更好,所以建议切换到homebrew版本:

切换macOS(Apple Silicon版本)的python3版本到homebrew提供的版本
cd /opt/homebrew/bin
ln -s python3.11 python3
ln -s python3.11 python
ln -s pip3.11 pip3
ln -s pip3.11 pip

备注

  • ARM版本的macOS安装目录是 /opt/homebrew/bin

  • Intel版本的macOS安装目录是 /usr/local/bin

默认情况下 /usr/local/bin 的PATH优先级较高,所以通常会找到homebrew的对应应用程序,例如 python3 pip3

Sequoia安装homebrew

最近一次安装,发现在 git fetch 指令时候报错,不论我启用了http proxy还是直接访问都是如此:

brew 安装时git报错
...
Press RETURN/ENTER to continue or any other key to abort:
==> /usr/bin/sudo /usr/sbin/chown -R huatai:admin /usr/local/Homebrew
==> Downloading and installing Homebrew...
remote: Enumerating objects: 289702, done.
remote: Counting objects: 100% (176/176), done.
remote: Compressing objects: 100% (130/130), done.
error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: CANCEL (err 8)
error: 5920 bytes of body are still expected
fetch-pack: unexpected disconnect while reading sideband packet
fatal: early EOF
fatal: fetch-pack: invalid index-pack output
Failed during: /usr/bin/git fetch --quiet --progress --force origin

这个问题实际上是网络不稳定导致的,网上大致的建议是采用VPN访问。不过,我已经启动了 Squid父级socks代理 也尝试了 SSH Tunneling: 动态端口转发 ,照理应该能够解决这个问题。但是反复报错让我不胜烦恼。

参考 Solving "error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: CANCEL (err 8)" During Homebrew Installation 思路,将 git 的 HTTP版本从 HTTP/2 降低到 HTTP/1.1 可以缓解网络不良的问题,简单命令如下:

将git的HTTP协议降低到 1.1 来解决Homebrew安装过程中网络不稳定的问题
# Git的HTTP传输协议降低为HTTP/1.1
git config --global http.version HTTP/1.1

# 增加Git超时设置
git config --global http.postBuffer 524288000
git config --global http.lowSpeedLimit 0
git config --global http.lowSpeedTime 999999

然后重新安装就发现能够正常完成了。

Big Sur安装homebrew

备注

参考 Homebrew Documentation: Installation 说明,当前(2024年初)要求操作系统是 macOS Monterey(12)或更高版本。更早的10.11(EI Capitan) - 11(Big Sur)不被官方支持,仅提示可能工作,更早的10.10(Yosemite)及之前版本已明确不支持。

早期的10.4(Tiger)-10.6(Snow Leopard)以及PPC支持则需要采用fork出来的 Tigerbrew

由于我的笔记本非常古老,只能安装 Big Sur (11),所以安装非常折腾。

警告

我的实践证实, 2024年4月时期的macOS 11(Big Sur)可以正确安装运行Homebrew。虽然官方没有明确支持。

我的安装花费了断断续续数天时间,但是并不是homebrew问题,而是GFW的阻挡导致的。大部分精力都在和GFW缠斗,非常令人沮丧。

Command Line Tools版本过低

我现在使用的笔记本电脑都是10年前的古旧硬件,无法安装最新的macOS,最高只能支持Big Sur,也就是 macOS 11.7.10 。这带来一个问题,就是默认初始安装的 Command Line Tools 版本比较旧。此时Homebrew安装应用会提示报错:

由于Command Line Tools版本过低导致Homebrew安装应用报错
Error: You are using macOS 11.
We (and Apple) do not provide support for this old version.
It is expected behaviour that some formulae will fail to build in this old version.
It is expected behaviour that Homebrew will be buggy and slow.
Do not create any issues about this on Homebrew's GitHub repositories.
Do not create any issues even if you think this message is unrelated.
Any opened issues will be immediately closed without response.
Do not ask for help from Homebrew or its maintainers on social media.
You may ask for help in Homebrew's discussions but are unlikely to receive a response.
Try to figure out the problem yourself and submit a fix as a pull request.
We will review it but may or may not accept it.


Error: A newer Command Line Tools release is available.
Update them from Software Update in System Preferences.

If that doesn't show you any updates, run:
  sudo rm -rf /Library/Developer/CommandLineTools
  sudo xcode-select --install

Alternatively, manually download them from:
  https://developer.apple.com/download/all/.
You should download the Command Line Tools for Xcode 13.2.1.

需要注意安装Command Line Tools后等待升级提示并完成升级到 13.2 版本之后再安装Homebrew才能避免错误。如果系统没有提升升级(例如我的实践),则可以按照上面输出提示尝试删除掉已经安装的Command Line Tools之后再次安装。过一会就有提示升级,可以升级Command Line Tools 到 13.2

pip安装失败

另一个问题是安装过程出现pip错误:

安装过程pip报错
...
==> Installing neovim dependency: certifi
==> Downloading https://formulae.brew.sh/api/formula.jws.json
############################################################################################## 100.0%
==> /usr/local/opt/[email protected]/libexec/bin/python -m pip install .
==> /usr/local/opt/[email protected]/libexec/bin/python -m pip install .
Last 15 lines from /Users/huataihuang/Library/Logs/Homebrew/certifi/02.python:
  │ exit code: 1
  ╰─> See above for output.
  
  note: This error originates from a subprocess, and is likely not a problem with pip.
  full command: /usr/local/opt/[email protected]/bin/python3.12 /usr/local/lib/python3.12/site-packages/pip/__pip-runner__.py install --ignore-installed --no-user --prefix /private/tmp/pip-build-env-8c7ruq4n/overlay --no-warn-script-location --no-binary :all: --only-binary :none: -i https://pypi.org/simple -- 'setuptools>=40.8.0'
  cwd: [inherit]
  Installing build dependencies: finished with status 'error'
error: subprocess-exited-with-error

× pip subprocess to install build dependencies did not run successfully.
│ exit code: 1
╰─> See above for output.
...

既然是执行 pip 报错,那么完整执行命令:

完整执行pip命令
/usr/local/opt/python@3.12/bin/python3.12 /usr/local/lib/python3.12/site-packages/pip/__pip-runner__.py install --ignore-installed --no-user --prefix /private/tmp/pip-build-env-8c7ruq4n/overlay --no-warn-script-location --no-binary :all: --only-binary :none: -i https://pypi.org/simple -- 'setuptools>=40.8.0'

报错信息如下:

完整执行pip命令报错信息
ERROR: Could not install packages due to an OSError: Missing dependencies for SOCKS support.

WARNING: There was an error checking the latest version of pip.

这个问题比较尴尬,之所以会启用socks代理,是为了解决 越过长城 ,但是网络看来欠佳。我最后是通过改进为通过墙内部署 SSH隧道 转发端口来加速网络,最终完成安装

openssl卡在make test

一个奇怪的问题,openssl编译成功,但是 make test 会卡住:

卡在make test的openssl安装
==> Installing neovim dependency: openssl@3
==> perl ./Configure --prefix=/usr/local/Cellar/openssl@3/3.3.0 --openssldir=/usr/local/etc/openssl@3
==> make
==> make install MANDIR=/usr/local/Cellar/openssl@3/3.3.0/share/man MANSUFFIX=ssl
==> make test

我尝试单独安装

单独安装openssl 3
brew install openssl@3

输出显示

单独安装openssl 3输出显示
openssl@3 3.2.1 is already installed but outdated (so it will be upgraded).
...
==> Fetching openssl@3
==> Downloading https://raw.githubusercontent.com/Homebrew/homebrew-core/1ebef261e5b820b6d00f219c90a7
############################################################################################## 100.0%
==> Downloading https://github.com/openssl/openssl/releases/download/openssl-3.3.0/openssl-3.3.0.tar.
Already downloaded: /Users/huataihuang/Library/Caches/Homebrew/downloads/bda1d745a83ead4bc9934f3e065b75bd56145b78b88df757f37193a8c8cb54aa--openssl-3.3.0.tar.gz
==> Upgrading openssl@3
  3.2.1 -> 3.3.0 
==> perl ./Configure --prefix=/usr/local/Cellar/openssl@3/3.3.0 --openssldir=/usr/local/etc/openssl@3
==> make
==> make install MANDIR=/usr/local/Cellar/openssl@3/3.3.0/share/man MANSUFFIX=ssl
==> make test

然后检查 ~/Library/Logs/Homebrew/ 目录下日志 tail -f openssl@3/04.make 可以看到进展情况

openssl make test错误日志输出
...
# ------------------------------------------------------------------------------
# cmp_main:apps/cmp.c:3225:CMP info: using section(s) 'Mock commands' of OpenSSL configuration file '../Mock/test.cnf'
# opt_str:apps/cmp.c:2571:CMP warning: -newkey option argument is empty string, resetting option
# opt_str:apps/cmp.c:2571:CMP warning: -key option argument is empty string, resetting option
# opt_str:apps/cmp.c:2571:CMP warning: -cert option argument is empty string, resetting option
# setup_client_ctx:apps/cmp.c:2220:CMP info: will contact http://127.0.0.1:49251/pkix/ via 127.0.0.1:3128
# CMP info: sending IR
# read_PKIMESSAGE:apps/cmp.c:804:CMP info: actually sending ../../../../test-runs/test_cmp_http/ir2.der
# CMP error: received error:code=503, reason=Service Unavailable
# CMP error: error receiving:server=http://127.0.0.1:49251 proxy=127.0.0.1:3128
# CMP error: transfer error:request sent: IR, expected response: IP
../../../../util/wrap.pl ../../../../apps/openssl cmp -server '127.0.0.1:49251' -config ../Mock/test.cnf -section 'Mock commands' -certout ../../../../test-runs/test_cmp_http/test.cert.pem -proxy '127.0.0.1:3128' -cmd ir -reqin ../../../../test-runs/test_cmp_http/ir2.der -rspout ../../../../test-runs/test_cmp_http/ip2.der -newkey "" --key "" -cert "" -secret 'pass:test' -popo -1 => 1
    not ok 106 - reqin ir and rspout - no newkey but -popo -1
# ------------------------------------------------------------------------------
    #   Failed test 'reqin ir and rspout - no newkey but -popo -1'
    #   at test/recipes/80-test_cmp_http.t line 151.
    #          got: '0'
    #     expected: '1'
read_PKIMESSAGE:apps/cmp.c:802:CMP error: cannot read PKIMessage from file '../../../../test-runs/test_cmp_http/ip2.der'
# cmp_main:apps/cmp.c:3225:CMP info: using section(s) 'Mock commands' of OpenSSL configuration file '../Mock/test.cnf'
# opt_str:apps/cmp.c:2571:CMP warning: -newkey option argument is empty string, resetting option
# opt_str:apps/cmp.c:2571:CMP warning: -key option argument is empty string, resetting option
# opt_str:apps/cmp.c:2571:CMP warning: -cert option argument is empty string, resetting option
# opt_str:apps/cmp.c:2571:CMP warning: -server option argument is empty string, resetting option
# setup_client_ctx:apps/cmp.c:2065:CMP warning: ignoring -proxy option since -server is not given
# setup_client_ctx:apps/cmp.c:2158:CMP warning: -reqin is ignored since -rspin is present
# setup_client_ctx:apps/cmp.c:2220:CMP info: will contact no server only if -rspin argument gives too few filenames
# CMP error: No such file or directory:calling fopen(../../../../test-runs/test_cmp_http/ip2.der, rb)
# CMP error: no such file
# CMP error: transfer error:request sent: IR, expected response: IP
../../../../util/wrap.pl ../../../../apps/openssl cmp -config ../Mock/test.cnf -section 'Mock commands' -certout ../../../../test-runs/test_cmp_http/test.cert.pem -proxy '127.0.0.1:3128' -cmd ir -reqin ../../../../test-runs/test_cmp_http/ir2.der -rspin ../../../../test-runs/test_cmp_http/ip2.der -newkey "" -key "" -cert "" -secret 'pass:test' -popo -1 -server "" -disable_confirm => 1
    not ok 107 - reqin ip and rspin  - no newkey but -popo -1
# ------------------------------------------------------------------------------
    #   Failed test 'reqin ip and rspin  - no newkey but -popo -1'
    #   at test/recipes/80-test_cmp_http.t line 151.
    #          got: '0'
    #     expected: '1'
    # Looks like you failed 52 tests of 107.
not ok 4 - CMP app CLI Mock commands
# ------------------------------------------------------------------------------
...

观察看到 make test 会请求本地回环地址端口进行测试,但是我为了解决网络连接问题,特意使用了代理,似乎存在冲突。

我最初想采用类似curl的 no_proxy 环境配置,但是发现无效。看来 make test 访问http/https没有采用curl的方式。要么就安装openconnect执行完整VPN,要么跳过升级(本地已经有openssl 3.2.1)

备注

brew install openconnect 也是需要依赖安装 openssl@3 ,所以我没有办法绕开这个版本升级(当使用 brew pin openssl@3 锁定版本不升级时,安装 neovim 会提示必须 brew unpin openssl@3 一安装最新的依赖版本。

所以这里的解决方案 依然是采用 Android手机安装 openconnect 来实现 OpenConnect VPN 连接

参考