SNSへはこちら

Macでの/usr/binの罠と.zshenv そしてVim高速化へ…

長年の疑問、不満が完全ではないが一気に解決しましたのでここにまとめます。xcodebuild 許さんぞ

概要

Mac は UNIX 準拠の OS で、とても便利なコマンド資源が使えて良いのですが、開発関係のコマンド実行が異様に遅い時があるという問題を使い始めて間もなく感じるようになっていました。僕の使用用途として、以下がとても不満でした。

  • man ascii 等の man ページが表示されるのに5秒ほどかかることがある
  • gcc が実際に実行されるまでオーバーヘッドを感じることがある
  • Vim で Syntastic.vim というプラグインを使用して保存する際に、よく固まる

要はコマンドの実行が遅い時があり、しかしながら一度実行されてしまうと2回目以降からはしばらく高速だということです。なんだかとても中途半端な現象でググっても出てこず、色々とモヤモヤしていました。

コマンドの遅さにキレた

流石に人間我慢の限界があります。この gcc おかしいんじゃないのかとキレてxxd -au した結果を示します。

00002170: 0000 0040 0c00 0000 2000 5f5f 6d68 5f65  ...@.... .__mh_e
00002180: 7865 6375 7465 5f68 6561 6465 7200 5f6d  xecute_header._m
00002190: 6169 6e00 5f73 6869 6d5f 6d61 726b 6572  ain._shim_marker
000021a0: 005f 7863 7365 6c65 6374 5f69 6e76 6f6b  ._xcselect_invok
000021b0: 655f 7863 7275 6e00 6479 6c64 5f73 7475  e_xcrun.dyld_stu
000021c0: 625f 6269 6e64 6572 002f 4275 696c 6452  b_binder./BuildR
000021d0: 6f6f 742f 4c69 6272 6172 792f 4361 6368  oot/Library/Cach
000021e0: 6573 2f63 6f6d 2e61 7070 6c65 2e78 6273  es/com.apple.xbs
000021f0: 2f53 6f75 7263 6573 2f78 636f 6465 5f73  /Sources/xcode_s
00002200: 656c 6563 742f 7863 6f64 655f 7365 6c65  elect/xcode_sele
00002210: 6374 2d32 3334 392f 7372 632f 7368 696d  ct-2349/src/shim
00002220: 732f 0074 6f6f 6c2d 7368 696d 2e63 002f  s/.tool-shim.c./
00002230: 4275 696c 6452 6f6f 742f 4c69 6272 6172  BuildRoot/Librar
00002240: 792f 4361 6368 6573 2f63 6f6d 2e61 7070  y/Caches/com.app
00002250: 6c65 2e78 6273 2f42 696e 6172 6965 732f  le.xbs/Binaries/
00002260: 7863 6f64 655f 7365 6c65 6374 2f69 6e73  xcode_select/ins
00002270: 7461 6c6c 2f54 656d 7043 6f6e 7465 6e74  tall/TempContent
00002280: 2f4f 626a 6563 7473 2f78 636f 6465 5f73  /Objects/xcode_s
00002290: 656c 6563 742e 6275 696c 642f 546f 6f6c  elect.build/Tool
000022a0: 5368 696d 732e 6275 696c 642f 4f62 6a65  Shims.build/Obje
000022b0: 6374 732f 6763 632e 6f00 5f6d 6169 6e00  cts/gcc.o._main.
000022c0: 5f73 6869 6d5f 6d61 726b 6572 0000 0000  _shim_marker....

ムムッ!? Xcode!?!?!?`どうやらコイツが犯人のようです。

実際、Vim でシンタックスチェックを実行したら、iTerm2 のタイトルバーに

  • xcodebuild
  • xcrun
  • clang

という不穏なコマンド達が表示されていました。ちなみにパスは /usr/bin です。あ、最後の clang ですが、Mac デフォルトでは gccgcc ではなく、clang が擬態したものになっているんです。なんだそれ。でもまあ clang は遅さの元凶ではありません。

遅さの検証

実際に実行して見ましょう。

$ xcodebuild

なんとこの時点で 3秒のオーバーヘッド。Fxxk
お次は xcrun

$ xcrun
Usage: xcrun [options] <tool name> ... arguments ...

おっと。引数が必要なようです。気を取り直して

$ xcrun gcc

ここでも4秒ほど時間がかかりました。なお、どちらも一度実行してしまえば2回目以降はサクッと実行されます。状況が再現できましたね。

Workaround

で、この2つのクソコマンドをどうやってバイパスするかですが、まず各コマンド(gccやらgitやら)の所在を調べる必要があります。なんと偶然見つけました。

$ /usr/bin/gcc -v
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 9.1.0 (clang-902.0.39.2)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

はい。/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin ですね。ということでこのディレクトリをパスに追加しちゃいましょう。

export PATH="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin:$PATH"

これでにっくき xcodebuildxcrun が亡霊のように起き上がることはありません。

また、場合によってはそれでも PATH が /usr/bin を先頭に持ってきてしまうことがあるようです。Zsh を使っている人は以下の設定をすることをおすすめします。というか、Vim で開発コマンドを実行する場合は必須です。

Zshの設定 for Vimとか

.zshrc と .zshenv

どちらもホームディレクトリに置くべき Zsh の設定ファイルですが、どうやら設定を記述すべき項目が異なっているようです。今回は PATH について説明します。参考は以下。

Spacemacs を起動すると、.zshrc で PATH の設定をするな、と怒られた。ので、.zshenv に記述を移すと、今度は不具合が起きた。emacs を以下のページの設定をして呼び出すと ~/bin/emacs を実行していたのが、 .zshenv に PATH を移したことによって /usr/local/...

最初に .zshrc について説明しましょう。これは通常のシェルとして起動したときに読み込まれるファイルです。設定は主にこのファイルに書くと思われるのですが、実はシェルスクリプトで実行される時は読み込まれません。なので後述するように、Zsh をログインシェルとして使っていて、Vim から何らかのプログラムを実行するときには無視されるということです。

つまり Vim では上の Workaround は適用されないんです。自分は Vim でファイル保存時にシンタックスチェックが走るようにしているので、保存するたびにイライラしてしまうんですね。なので設定を示します。

.zshenvへの記述

まず皆さんが .zshrc に書いてある PATH の情報をカットして .zshenv に貼り付けます。これだけで実はいい感じに動くようになりうるのですが、実際は違います。このファイルの先頭行に次の文を書きましょう。

setopt no_global_rcs # avoid loading /etc/profile (not to execute /usr/libexec/path_helper)

説明はコメントのとおりなのですが、これを書くことで /etc/profile が読まれなくなります。これが読まれると何が良くないかというと、/usr/libexec/path_helper というコマンドが実行されデフォの /usr/bin が PATH の先頭付近に記述されてしまうのです。するとさっきの xcrun が実行されて結局状況は変わらないんですね。ちなみにこのコマンドは /etc/paths の内容が追加されるのですが、その中身は

$ cat /etc/paths
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin

なんですね。これを回避できるのが上の文なのです。

結果

各種コマンド実行時のオーバヘッドも減ったし、Vim のシンタックスチェックが爆速になりました!今の所不具合は出ていないので多分大丈夫だと思います。よかった〜〜〜〜〜〜