package monkey/repl is not in GOROOT
「Go言語でつくるインタプリタ」のサイトからソースコードをダウンロードし、Goのコンパイラをインストールし、コンパイルしようとしたら
$ 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言語でつくるインタプリタ」のソースコードのコンパイル、実行ができるようにする。具体的には
$ 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を見に行ってしまっていた。参考
解決方針
作業ディレクトリにGOPATHを通し、モジュールモードを切る。
テキストのソースコードをダウンロードすると、waiig_code_1.4/01(02,03,04)
内に.envrc
が入っていて、direnv
を用いることで作業ディレクトリ(01/
とか)に入るたびにパスがうまく渡されるようになっている。そしてモジュールモードを無効にするためGO111MODULE = off または auto
(go.modが存在するとautoだとダメそうだが、今回はないのでautoにする)と設定する。参考
前提 テキストのソースコードをダウンロードする
ソースコードは「Go言語でつくるインタプリタ」書籍xiiページ(はじめに)のURLからダウンロードできます。
また、この記事では以下のようなディレクトリ構成を想定しています。
~/
┣programing/
┗ waiig_code_1.4/
┗ 01/
┃ ┗ src/
┃ ┗ monkey/
┃ ┗ main.go
┃ ┣ lexer/
┣02
┣03
そのため、不安な方はソースコードをダウンロードした後、ターミナルを開いて
programingというディレクトリ(フォルダ)を作成
$ mkdir programing
$ cd downloads
(~/downloads)
$ mv waiig_code_1.4 ~/programing
として図のようなディレクトリ構成になるようにしてください。Finderでやっても構いません。
1.Goのインストール
$ go version
インストールされていればgo version go1.19.2 darwin/arm64
のように返ってきます。インストールしてある方は飛ばしてください。
インストール方法
Goのインストールの仕方はいくつかありますが、MacならHomebrewからインストールするのが手っ取り早くていい気がします。
①Homebrewからインストール(推奨)
私がこのやり方でインストールしたので推奨しているだけですが、この後direnvをインストールするのにHomebrewを使うので、Homebrewで一緒にインストールしたほうがいいかと思います。
Homebrew
がインストールされてない方は下の記事からインストールし、brew -v
でバージョンが確認できたら進んでください。
Homebrewがインストールできたら,
$ brew install go
を実行し、終わるまでしばらく待ち、インストールが終了したらバージョンの確認をします。
$ go version
go version go1.19.2 darwin/arm64
②公式のホームページからインストール
シンプルに公式からインストールする方法です。
2.direnvのインストール
direnvとは
ディレクトリ毎に環境変数を定義して、そのディレクトリがカレントになった時だけ環境変数を有効/無効にしてくれるツール。開発中のアプリ毎に環境変数を変えたい時に重宝する。
(引用元 :https://qiita.com/kompiro/items/5fc46089247a56243a62)
Homebrew経由でdirenvをインストールします。(一応git cloneとか他のやり方もあります。上の引用元参照)
Homebrew
がインストールされてない方は下の記事からインストールし、brew -v
でバージョンが確認できたら進んでください。
Homebrewがインストールできたら以下のコマンドを実行します。
$ brew install direnv
インストールできたらバージョンを確認し、正常にインストールできたか確認します。
$ direnv version
2.32.1
なにかしらのバージョンが返ってきたら成功です。
3.シェルの設定ファイルにhookを追加
シェルの種類を確認した後、その設定ファイルにeval "$(direnv hook {shell})"
を追加します。
シェルの種類を確認する
$ echo $SHELL
(例)/bin/zsh
この場合zshが使われています。
/bin/bash
が返ってきたらbashが使われています。
zshの場合
$ open .zshrc
テキストファイルが開くので内容を消さずに改行を入れて
eval "$(direnv hook zsh)"
を追加します。追加したらcmd + s
で保存し、ターミナルに戻り以下のコマンドを打ってシェルの設定を反映させましょう。
$ source ~/.zshrc
bashの場合
$ open .bashrc
テキストファイルが開くので内容を消さずに改行を入れて
eval "$(direnv hook bash)"
を追加します。追加したらcmd + s
で保存し、ターミナルに戻り以下のコマンドを打ってシェルの設定を反映させましょう。
$ source ~/.bashrc
direnvの有効化
(追記2022.11.02 曖昧さ回避のため章を「direnvが正しくインストールされたかの確認」から変更)
正しくインストールされていれば、教科書のプログラムがインストールされたディレクトリ (ファルダ)に移動すると以下のようにエラーが出るかと思います。
$ 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
を実行。
$ direnv allow
direnv: loading ~/programing/waiig_code_1.4/01/.envrc
direnv: export +GOPATH
これでdirenvが有効化されました。
02や03のディレクトリに初めて入った際も同様のエラーが出るので、direnv allow
をその都度実行してください。
4.環境変数 GO111MODULE の設定
direnvの設定が完了した段階でmain.go
のあるディレクトリに移動し、コンパイルを試してみます。
$ 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
をシェルの設定ファイルに記載します。
今いるディレクトリからホームディレクトリ(~/
)に移動し、シェルの設定ファイルを再び開きます。
$ cd
(注)ホームディレクトリに移動
zshの場合
$ open .zshrc
テキストファイルが開くので内容を消さずに改行を入れて
export GO111MODULE=auto
を追加しcmd+s
で保存した後、ターミナルに戻り
$ source ~/.zshrc
で設定を更新します。
bashの場合
$ open .bashrc
テキストファイルが開くので内容を消さずに改行を入れて
export GO111MODULE=auto
を追加しcmd+s
で保存した後、ターミナルに戻り
$ source ~/.bashrc
で設定を更新します。
コンパイル実行できるか確認
環境変数の設定ができたら再びmain.go
があるディレクトリに移動しコンパイルできるか試します。
$ 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~
の文が出力されれば実行成功です。プロンプト(>>
)の後になにか打ってみましょう
>> let x = 5 + 5;
例として教科書1ページのコマンドを入力しました。
{Type:LET Literal:let}
{Type:IDENT Literal:x}
{Type:= Literal:=}
{Type:INT Literal:5}
{Type:+ Literal:+}
{Type:INT Literal:5}
{Type:; Literal:;}
以上のように出力されれば成功です。プロンプトからはctrl + d
で脱出できます。
これで環境構築はおしまいです。お疲れ様でした。