「Go言語でつくるインタプリタ」の実行環境構築 M1 Mac

# package monkey/repl is not in GOROOT
「Go言語でつくるインタプリタ」のサイトからソースコードをダウンロードし、Goのコンパイラをインストールし、コンパイルしようとしたら

```terminal:terminal src/monkey/
$ go run main.go
main.go:5:2: package monkey/repl is not in GOROOT (/opt/homebrew/Cellar/go/1.19.2/libexec/src/monkey/repl)
```
とエラーが返ってきてつまずいたので解決法を記事にしました。
# 環境
* macOS Monterey
* Apple Silicon(M1)
* Homebrew 3.6.7

# 目標
「Go言語でつくるインタプリタ」のソースコードのコンパイル、実行ができるようにする。具体的には
```terminal:src/monkey/
$ go run main.go
Hello {username}! This is the Monkey programming language!
Feel free to type in commands
>> 
```
と実行できるようにしたい。

# 原因と解決方針
## 原因 
Goをインストールした後パスなどの設定を一切していなかったので`$GOPATH = ~/go`であり、`GO111MODULE`も初期設定のままで、goのプロジェクトがGOPATH配下にないのでモジュールモードになりモジュールを探しにGOROOTを見に行ってしまっていた。[参考](https://qiita.com/Syoitu/items/f221b52231703cebe8ff)
## 解決方針
作業ディレクトリにGOPATHを通し、モジュールモードを切る。
テキストのソースコードをダウンロードすると、`waiig_code_1.4/01(02,03,04)`内に`.envrc`が入っていて、`direnv`を用いることで作業ディレクトリ(`01/`とか)に入るたびにパスがうまく渡されるようになっている。そしてモジュールモードを無効にするため`GO111MODULE = off または　auto`(go.modが存在するとautoだとダメそうだが、今回はないのでautoにする)と設定する。[参考](https://github.com/golang/go/wiki/Modules)

# 前提 テキストのソースコードをダウンロードする
ソースコードは「Go言語でつくるインタプリタ」書籍xiiページ(はじめに)のURLからダウンロードできます。
また、この記事では以下のようなディレクトリ構成を想定しています。
>~/
 &nbsp;┣programing/
&emsp;&emsp; ┗ waiig_code_1.4/
&emsp;&emsp;&emsp;&emsp;┗ 01/
&emsp;&emsp;&emsp;&emsp;┃&emsp;&emsp;┗ src/
&emsp;&emsp;&emsp;&emsp;┃&emsp;&emsp;&emsp;&emsp;┗ monkey/
&emsp;&emsp;&emsp;&emsp;┃&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;┗ main.go
&emsp;&emsp;&emsp;&emsp;┃&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;┣ lexer/
&emsp;&emsp;&emsp;&emsp;┣02
&emsp;&emsp;&emsp;&emsp;┣03

そのため、不安な方はソースコードをダウンロードした後、ターミナルを開いて
```terminal:terminal:~/
programingというディレクトリ(フォルダ)を作成
$ mkdir programing
```

```terminal:terminal:~/
$ cd downloads
(~/downloads)
$ mv waiig_code_1.4 ~/programing
```
として図のようなディレクトリ構成になるようにしてください。Finderでやっても構いません。

# 1.Goのインストール
```terminal:terminal
$ go version
```
インストールされていれば`go version go1.19.2 darwin/arm64`のように返ってきます。インストールしてある方は飛ばしてください。

## インストール方法
Goのインストールの仕方はいくつかありますが、MacならHomebrewからインストールするのが手っ取り早くていい気がします。

### ①Homebrewからインストール(推奨)
私がこのやり方でインストールしたので推奨しているだけですが、この後direnvをインストールするのにHomebrewを使うので、Homebrewで一緒にインストールしたほうがいいかと思います。
`Homebrew`がインストールされてない方は下の記事からインストールし、`brew -v`でバージョンが確認できたら進んでください。

https://qiita.com/zaburo/items/29fe23c1ceb6056109fd

Homebrewがインストールできたら,
```terminal:terminal
$  brew install go
```
を実行し、終わるまでしばらく待ち、インストールが終了したらバージョンの確認をします。
```terminal:terminal
$ go version
go version go1.19.2 darwin/arm64
```



### ②公式のホームページからインストール
シンプルに公式からインストールする方法です。

https://qiita.com/uhooi/items/f1bca01d76080d82fbef





# 2.direnvのインストール

#### direnvとは
>ディレクトリ毎に環境変数を定義して、そのディレクトリがカレントになった時だけ環境変数を有効/無効にしてくれるツール。開発中のアプリ毎に環境変数を変えたい時に重宝する。
(引用元 :https://qiita.com/kompiro/items/5fc46089247a56243a62)

Homebrew経由でdirenvをインストールします。(一応git cloneとか他のやり方もあります。上の引用元参照)
`Homebrew`がインストールされてない方は下の記事からインストールし、`brew -v`でバージョンが確認できたら進んでください。

https://qiita.com/zaburo/items/29fe23c1ceb6056109fd



Homebrewがインストールできたら以下のコマンドを実行します。
```terminal:terminal
$ brew install direnv
```
インストールできたらバージョンを確認し、正常にインストールできたか確認します。
```terminal:terminal
$ direnv version
2.32.1
```
なにかしらのバージョンが返ってきたら成功です。

# 3.シェルの設定ファイルにhookを追加
シェルの種類を確認した後、その設定ファイルに`eval "$(direnv hook {shell})"`を追加します。
### シェルの種類を確認する
```terminal:terminal
$　echo $SHELL
(例)/bin/zsh
```
この場合zshが使われています。
`/bin/bash`が返ってきたらbashが使われています。

#### zshの場合
```terminal:terminal:~/
$ open .zshrc
```
テキストファイルが開くので内容を<font color="Red">消さずに</font>改行を入れて
```:~/.zshrc
eval "$(direnv hook zsh)"
```
を追加します。追加したら`cmd + s`で保存し、ターミナルに戻り以下のコマンドを打ってシェルの設定を反映させましょう。
```terminal:terminal
$ source ~/.zshrc
```

#### bashの場合
```terminal:terinal:~/
$ open .bashrc
```
テキストファイルが開くので内容を<font color="Red">消さずに</font>改行を入れて
```:~/.bashrc
eval "$(direnv hook bash)"
```
を追加します。追加したら`cmd + s`で保存し、ターミナルに戻り以下のコマンドを打ってシェルの設定を反映させましょう。
```terminal:terminal
$ source ~/.bashrc
```
## direnvの有効化
(追記2022.11.02 曖昧さ回避のため章を「direnvが正しくインストールされたかの確認」から変更)
正しくインストールされていれば、教科書のプログラムがインストールされたディレクトリ (ファルダ)に移動すると以下のようにエラーが出るかと思います。
```terminal:terminal:~/
$ cd programing
$ cd waiig_code_1.4
$ cd 01
direnv: error /Users/{username}/programing/waiig_code_1.4/01/.envrc
 is blocked. Run `direnv allow` to approve its content
```
メッセージに従い`direnv allow`を実行。
```terminal:terminal: ~/programing/waiig_code_1.4/01/
$ direnv allow
direnv: loading ~/programing/waiig_code_1.4/01/.envrc                           
direnv: export +GOPATH
```
これでdirenvが有効化されました。
02や03のディレクトリに初めて入った際も同様のエラーが出るので、`direnv allow`をその都度実行してください。

# 4.環境変数 GO111MODULE の設定
direnvの設定が完了した段階で`main.go`のあるディレクトリに移動し、コンパイルを試してみます。
```terminal:terminal: ~/programing/waiig_code_1.4/01/
$ cd src/monkey
(~/programing/waiig_code_1.4/01/src/monkey)
$ go run main.go
main.go:5:2: package monkey/repl is not in GOROOT (/opt/homebrew/Cellar/go/1.19.2/libexec/src/monkey/repl)
```
まだコンパイルできません(正常)。環境変数`GO111MODULE`をシェルの設定ファイルに記載します。

今いるディレクトリからホームディレクトリ(`~/`)に移動し、シェルの設定ファイルを再び開きます。
```terminal:terminal: ~/programing/waiig_code_1.4/01/src/monkey
$ cd
(注)ホームディレクトリに移動
```

#### zshの場合
```terminal:terminal:~/
$ open .zshrc
```
テキストファイルが開くので内容を<font color="Red">消さずに</font>改行を入れて
```:~/.zshrc
export GO111MODULE=auto
```
を追加し`cmd+s`で保存した後、ターミナルに戻り
```terminal:terminal:~/
$ source ~/.zshrc
```
で設定を更新します。

#### bashの場合
```terminal:terminal:~/
$ open .bashrc
```
テキストファイルが開くので内容を<font color="Red">消さずに</font>改行を入れて
```:~/.bashrc
export GO111MODULE=auto
```
を追加し`cmd+s`で保存した後、ターミナルに戻り
```terminal:terminal:~/
$ source ~/.bashrc
```
で設定を更新します。

# 　コンパイル実行できるか確認

環境変数の設定ができたら再び`main.go`があるディレクトリに移動しコンパイルできるか試します。
```terminal:terminal:~/
$ cd programing
$ cd waiig_code_1.4
$ cd 01/src/monkey
$ go run main.go
Hello {username}! This is the Monkey programming language!
Feel free to type in commands
>>
```
`Hello~`の文が出力されれば実行成功です。プロンプト（`>>`）の後になにか打ってみましょう
```go:terminal:~/programing/waiig_code_1.4/01/src/monkey
>> let x = 5 + 5;
```
例として教科書1ページのコマンドを入力しました。
```go
{Type:LET Literal:let}
{Type:IDENT Literal:x}
{Type:= Literal:=}
{Type:INT Literal:5}
{Type:+ Literal:+}
{Type:INT Literal:5}
{Type:; Literal:;}
```
以上のように出力されれば成功です。プロンプトからは`ctrl + d`で脱出できます。
これで環境構築はおしまいです。お疲れ様でした。

# 参考リンク
* [Homebrewのインストール](https://qiita.com/zaburo/items/29fe23c1ceb6056109fd)
* [MacにGo言語の開発環境を構築する【準備編】 (direnv+go1.5Vendoring+glide)](http://blog.flup.jp/2016/02/16/dev_golang_keeping_vendoring/#GOPATH)
* [GOMODULE--Goのパッケージ管理](https://qiita.com/Syoitu/items/f221b52231703cebe8ff)
* [[Golang] 環境変数GO111MODULEの設定値の違いについて](https://hghyk023.hatenablog.jp/entry/2020/01/06/232331)
* [MacにGoをインストールする](https://qiita.com/sanogemaru/items/cabc700e6d9a28219cc8)
* [Go言語のインストール方法(Mac)](https://qiita.com/uhooi/items/f1bca01d76080d82fbef)
* [direnvを使おう](https://qiita.com/kompiro/items/5fc46089247a56243a62#fish)
* [Homebrew公式](https://brew.sh/index_ja)
* [Go公式](https://go.dev/)
* [direnvリポジトリ]https://github.com/direnv/direnv
* [Goリポジトリ]https://github.com/golang/go/wiki/Modules