macOS `Catalina`に`clang 12.0.0`を入れて`ruby 3.0.0`を入れるだけ

### ある日，`rbenv`を見ていた

`brew upgrade ebenv`して，

```terminal
$ rbenv install -list
2.5.8
2.6.6
2.7.2
3.0.0
jruby-9.2.14.0
mruby-2.1.2
rbx-5.0
truffleruby-20.3.0
truffleruby+graalvm-20.3.0
```

昨年中に`ruby 3.0.0`が正式にリリースされ，`rbenv`も対応したらしい．入れてみよっかなぁ〜俺もなぁ〜…



# その`ruby 3.0.0`を入れようとしてしくじった

当時の環境は以下の通りだった．

+ MBP 2016 15inch
+ macOS `Catalina`
    + `clang Apple 11.0.0`←だいたいこいつのせいだった

## 吐かれたエラー

```text
...
linking miniruby
generating x86_64-darwin19-fake.rb
x86_64-darwin19-fake.rb updated
make: *** [exe/ruby] Segmentation fault: 11
make: *** Deleting file 'exe/ruby'

BUILD FAILED (Mac OS X 10.15.7 using ruby-build 20201225)

Inspect or clean up the working tree at /var/folders/rk/0hczm32x2znb6pr6h4858hpc0000gn/T/ruby-build.20210104003100.75691.mUe6Zo
Results logged to /var/folders/rk/0hczm32x2znb6pr6h4858hpc0000gn/T/ruby-build.20210104003100.75691.log

Last 10 log lines:
compiling enc/unicode.c
compiling enc/utf_8.c
compiling enc/trans/newline.c
./revision.h unchanged
compiling version.c
linking miniruby
generating x86_64-darwin19-fake.rb
x86_64-darwin19-fake.rb updated
make: *** [exe/ruby] Segmentation fault: 11
make: *** Deleting file 'exe/ruby'
```

どうやら最後の`make`のとこでしくじったらしい．


## 原因推定
`Segmentation fault: 11`，これはなんかコンパイラが悪い気がしたので，設定や経過を見たくなった．

```
rbenv install -v 3.0.0
```

`-v`しながら`rbenv install`すると諸々の経過が見える，その結果

```
Configuration summary for ruby version 3.0.0

   * Installation prefix: /Users/username/.rbenv/versions/3.0.0
   * exec prefix:         ${prefix}
   * arch:                x86_64-darwin19
   * site arch:           ${arch}
   * RUBY_BASE_NAME:      ruby
   * enable shared:       yes
   * ruby lib prefix:     ${libdir}/${RUBY_BASE_NAME}
   * site libraries path: ${rubylibprefix}/${sitearch}
   * vendor path:         ${rubylibprefix}/vendor_ruby
   * target OS:           darwin19
   * compiler:            clang -fdeclspec
   * with pthread:        yes
   * with coroutine:      amd64
   * enable shared libs:  yes
   * dynamic library ext: bundle
   * CFLAGS:              ${optflags} ${debugflags} ${warnflags}
   * LDFLAGS:             -L. \
                          -L/Users/username/.rbenv/versions/3.0.0/lib  \
                          -fstack-protector-strong -L/usr/local/lib
   * DLDFLAGS:            -L/Users/username/.rbenv/versions/3.0.0/lib  \
                          -Wl,-undefined,dynamic_lookup \
                          -Wl,-multiply_defined,suppress
   * optflags:            -O3
   * debugflags:          -ggdb3
   * warnflags:           -Wall -Wextra -Wdeprecated-declarations \
                          -Wdivision-by-zero \
                          -Wimplicit-function-declaration -Wimplicit-int \
                          -Wpointer-arith -Wshorten-64-to-32 \
                          -Wwrite-strings -Wmissing-noreturn \
                          -Wno-constant-logical-operand -Wno-long-long \
                          -Wno-missing-field-initializers \
                          -Wno-overlength-strings -Wno-parentheses-equality \
                          -Wno-self-assign -Wno-tautological-compare \
                          -Wno-unused-parameter -Wno-unused-value \
                          -Wunused-variable -Wextra-tokens
   * strip command:       strip -A -n
   * install doc:         rdoc
   * JIT support:         yes
   * man page type:       doc
   * BASERUBY -v:         ruby 2.7.2p137 (2020-10-01 revision 5445e04352) \
                          [x86_64-darwin19]
```

を吐きながら，同じように失敗した．

```
   * target OS:           darwin19
   * compiler:            clang -fdeclspec
```

を見るに，macOS備え付けの`clang`を使っていることは察せた（私はいまだにコンパイラに手を出した事がない）．

```terminal
$ clang -v
Apple clang version 11.0.0 (clang-1100.0.33.8)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```

どうもビルドにはコイツを使ったらしい．
悩んでTwitterを彷徨っていたら，[`clang Apple 12.0.0`](https://twitter.com/kyohsuke14/status/1344316249090625536?s=20)で[`ruby 3.0.0`を入れたっぽい](https://twitter.com/kyohsuke14/status/1344315807589810176?s=20)方を発見した．
また[こ↑こ↓](http://www.cc.kyoto-su.ac.jp/~atsushi/Programs/SoftwareVersions/index-j.html)によると，macOS `Big Sur`でちゃんと`XCode`を入れている人は

```terminal
$ clang --version
Apple clang version 12.0.0 (clang-1200.0.32.27)
Target: x86_64-apple-darwin20.2.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
```

となるらしい（私は`XCode`を入れた後に**消した**，だってあれデカイし重いし…）．

つまり`clang`のバージョンが古いせいでしくじったんじゃね？と考えた．



# 解決編

## 概要
`CommandLineTools`を強制的に入れ直すと`clang 12.0.0`になるのでヨシ！`ruby 3.0.0`も入れられる！

## 手順
`Catalina`で`softowareupdate`に任せてもそれ以上に`CommandLineTools`は新しくならない（つまりclang 12.0.0はどう足掻いても手に入らない）ので，いっそ手動で入れ直す．

```terminal
$ sudo rm -rf /Library/Developer/CommandLineTools
...
$ xcode-select --install
```

バージョン確認すると

```terminal
$ clang -v
Apple clang version 12.0.0 (clang-1200.0.32.28)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
```

こうなるはず，やっぱり`XCode`がなくても大丈夫だったじゃないか…

これで

```terminal
$ rbenv install 3.0.0
```

すれば

```
Installed ruby-3.0.0 to /Users/username/.rbenv/versions/3.0.0
```

が出るはず，バージョンを変えるか変えないかはあなた次第だが

```
rbenv local 3.0.0
```

とかでできる．

**終わり！閉廷！以上！みんな解散！~~君もう帰って良いよ~~**



# おまけ
`clang 11.0.0`(やそれ以前の任意のバージョンの`clang`)を使いたい時にどうするかを考えた．

## 概要
`homebrew`で`llvm`を入れて，それ経由で`clang`のバージョンを任意に変えられるようにしようぜ？

### `llvm`とは
`llvm`を開発している組織さんの公式ページは[こ↑こ↓](https://llvm.org)，llvmまわりのダウンロードやドキュメント等は[こ↑こ↓](https://releases.llvm.org)．
`llvm`自体は`c`や`c++`のコンパイラ`clang`のバックで動いているような中間言語を生成するシステムで，というか`clang`が`c`の仕様に対応しながら`llvm`と並行で開発・維持され続けているものになっている…らしいな？
つまりある時から`llvm`のバージョンが`clang`のバージョンになっている，そして`brew`で手に入れられる最新版は今だと`llvm 11.0.0`で，それを入れると`clang 11.0.0`がもれなくそれについてくる…という流れになる．

ただあくまで言語やアーキテクチャに依存せずより効率の良い中間言語を生成しようとするのが`llvm`で，それを利用して`objective-c`などをコンパイルするのが`clang`，そんで`clang`の開発の言い出しっぺはやっぱりAppleで…だからあっ`XCode`にちゃんと最新版の`clang 12.0.0`が入って提供されている，やっぱ林檎ってすげぇわマジで…

…なので`clang`は`gcc`よりも性能と使い勝手が共に良い…らしい（私は開発者ではないので全くわからないが）．

## 事前準備
`homebrew`を導入しておく．

## 最新版の`llvm`だけで良いなら
まずは入れてみる．

```terminal
$ brew install llvm <versions>
...
$ brew info llvm
...
```

ちゃんと注意書きを読む（抜粋）．

```
To use the bundled libc++ please add the following LDFLAGS:
  LDFLAGS="-L/usr/local/opt/llvm/lib -Wl,-rpath,/usr/local/opt/llvm/lib"

llvm is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.

If you need to have llvm first in your PATH run:
  echo 'export PATH="/usr/local/opt/llvm/bin:$PATH"' >> /Users/SolunaEureka/.bash_profile

For compilers to find llvm you may need to set:
  export LDFLAGS="-L/usr/local/opt/llvm/lib"
  export CPPFLAGS="-I/usr/local/opt/llvm/include"
```

`keg-only`…つまりシンボリックリンクが生成されないタイプのパッケージだけど，中身はちゃんとあるからパスだけは通そうね！あとコンパイラに知らせたいフラッグにも対応しているから，使いたければパスだけは通そうね！（意訳）

…ということで，コマンドとしての`llvm`はどうもなさそうなので，それを打って`llvm`経由の`clang`が有効になるような感じにするために，`.bash_profile`をいじる([参考：学生たちの技術ブログ](https://students-tech.blog/post/install-clang.html#パスを通す))．~~まだbashでごめんなさい~~

```bash:~/.bash_profile
function llvm (){ #関数を定義している
    export PATH="/usr/local/opt/llvm/bin:$PATH" #以下，先の注意書きの通りにパスを追加・変更する
    export LDFLAGS="-L/usr/local/opt/llvm/lib"
    export CPPFLAGS="-I/usr/local/opt/llvm/include"
    unset -f llvm #いったん呼び出されたら定義されたこの関数を破壊する
}
```

ここまで終わったら`terminal`を立ち上げ直して

```terminal
$ llvm
$ clang -v
clang version 11.0.0
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
```

になるはず．
新しいタブを開けば元に戻るので安心だね！

## 旧版の`llvm`を使いたいなら
`homebrew`は基本的に最新版以外は絶対に認めないマンな上に過去版のインストールに関しては仕様が変わるらしい，そんな中で個人的に現在の参考になったのは[こ↑こ↓](https://christina04.hatenablog.com/entry/install-old-version-with-homebrew)．
`brew tap-new`と`brew extract`を用いて，自家製の`tap`に公式の`formula`をぶち込んで，その`tap`から更に`brew install`すれば良い，らしい．これを発案した人，本当に賢い…

ということで試しに`llvm 10.0.0`を入れて`clang 10.0.0`に切り替えようとしてみる(主要な出力を抜き出す)．

```terminal
$ brew tap-new llvm/1000
Initialized empty Git repository in /usr/local/Homebrew/Library/Taps/llvm/homebrew-1000/.git/
[master (root-commit) d649d61] Create llvm/1000 tap
 3 files changed, 85 insertions(+)
 create mode 100644 .github/workflows/publish.yml
 create mode 100644 .github/workflows/tests.yml
 create mode 100644 README.md
==> Created llvm/1000
/usr/local/Homebrew/Library/Taps/llvm/homebrew-1000

$ brew extract llvm llvm/1000 --version 10.0.0
==> Searching repository history
==> Writing formula for llvm from revision 96544f6 to:
/usr/local/Homebrew/Library/Taps/llvm/homebrew-1000/Formula/llvm@10.0.0.rb

$ brew install llvm/1000/llvm@10.0.0
==> Installing llvm@10.0.0 from llvm/1000
llvm@10.0.0: A full installation of Xcode.app is required to compile
this software. Installing just the Command Line Tools is not sufficient.

Xcode can be installed from the App Store.
Error: An unsatisfied requirement failed this build.
```

`XCode`がないとダメと言われた．なんだコレは，たまげたなぁ…
もしちゃんと入れている人がいたら試してみて欲しい．

あとはどうにかしてバージョンを切り替えてみて欲しい…



# 感想
コンパイラって色々あって大変だな〜とづまりすとこ
絶対もっと良いやり方があるのでは？brewはバージョン管理に不向きだし`llvm`と`clang`は公式サイトからDLして突っ込んで自分でちゃんと関数を組み上げた方がいいんじゃないか？問題は解決したからもう何も考えられないけど…