前回の記事「Google ColabでGo言語を動かす」では、
Google Colab上でGoの実行環境を作り、Hello from Go on Google Colab を表示するところまでを紹介しました。
今回はその続編として、Goの標準的なパッケージ管理の仕組み(go.mod / go.sum) を、
あえて エラーを実際に発生させながら 体験していきます。
「なぜこのファイルが必要なのか」は、動いているうちは実感しづらいものです。
逆に言えば、このファイルが無いとどんなエラーになるのか を先に見てしまうのが、いちばん理解が早い近道です。
対象読者
- 前回記事で、Google ColabでGoの
Hello Worldを動かした人 -
go.mod/go.sumという単語は知っているが、役割を説明できない人 -
npmのpackage.json/package-lock.jsonや、Pythonのrequirements.txtとの違いが気になる人 - 「動かないエラー」を実際に見ながら学びたい人
すぐに使えるチートシートはこちら Google Colab版
すぐに実行して、試せるコードレシピはこちら。
この記事で扱う3つのエラー
実際に手を動かすと、以下の3種類のエラーに遭遇します。それぞれ意味が異なります。
| # | エラーメッセージ(要約) | 原因 |
|---|---|---|
| ① | go.mod file not found |
プロジェクトにgo.mod自体が無い |
| ② | no required module provides package ...; to add it: go get ... |
go.modはあるが、依存パッケージが記載されていない |
| ③ | missing go.sum entry for module providing package ... |
go.modに依存は書かれているが、go.sumにチェックサムが無い |
このエラーを1つずつ、実際にColab上で再現します。
0. 前回のおさらい:Go言語のインストール
前回記事と同じ手順です。冒頭のセルで、Linuxコマンドを使ってGoをインストールします。
!apt-get update -qq
!apt-get install -y golang-go
!go versionとし、go version go1.22.2 linux/amd64のようにバージョンが表示されれば成功です。
1. なぜ go.mod / go.sum が必要なのか
Goは、 Go Modules という仕組みで依存パッケージを管理する仕組みが採用されています。
| ファイル | 役割 |
|---|---|
go.mod |
モジュール名・Goのバージョン・依存パッケージの一覧を宣言 |
go.sum |
依存パッケージの中身が改ざんされていないかを確認する チェックサム(ハッシュ値) の一覧 |
go.modが「何を使うか」の宣言だとすると、go.sumは「それが本物であることの証明書」に近いイメージです。
どちらか一方が欠けても、Goは意図的にビルドを止めます。これは依存関係の改ざん・取り違えを防ぐためのGoの設計思想です。
それでは、実際にこの2つのファイルが無い状態から始めて、Goがどう振る舞うかを見ていきましょう。
2. プロジェクトディレクトリを作る
Colabのセルで!cd ディレクトリ名としても、次のセルには移動が引き継がれません。
(!はセルごとに独立したサブシェルでコマンドを実行するためです。)
ディレクトリ移動を次のセル以降にも引き継ぎたい場合は、Colab(IPython)のマジックコマンド%cdを使います。
!mkdir -p /content/go-modules-demo
%cd /content/go-modules-demo
ここに、外部パッケージを使う簡単なプログラムを作成します。
今回は github.com/google/uuid という、UUID(一意な識別子)を生成する定番の外部パッケージを使います。
%%writefile main.go
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
id := uuid.New()
fmt.Println("生成されたUUID:", id)
}
3. わざと実行してみる(① go.modが無いエラー)
go.modをまだ作っていない状態で、あえて実行してみます。
!go run main.go
すると、次のようなエラーとなります。
main.go:6:2: no required module provides package github.com/google/uuid: go.mod file not found in current directory or any parent directory; see 'go help modules'
これを解消するには、go mod initでモジュールを初期化します。
!go mod init example.com/hello
すると、こんなメッセージが出るはずです。
go: creating new go.mod: module example.com/hello
go: to add module requirements and sums:
go mod tidy
go mod initを実行すると、以下のような最小限のgo.modが生成されます。
module example.com/hello
go 1.22.2
-
module example.com/hello:このプロジェクトの名前(モジュールパス)。社内プロジェクトなら好きな文字列でOKです。 -
go 1.22.2:このモジュールが前提とするGoのバージョン。
4. もう一度実行してみる(② 依存が足りないエラー)
go.modはできましたが、まだgithub.com/google/uuidをこのプロジェクトが使う、という宣言はしていません。
もう一度実行してみましょう。
!go run main.go
度はエラーメッセージが変わります。
main.go:6:2: no required module provides package github.com/google/uuid; to add it:
go get github.com/google/uuid
エラー②の解説
go.mod自体は存在するようになりましたが、中身にgithub.com/google/uuidへの依存が 一切書かれていません。
そのため「このモジュールが提供するパッケージの中に、importされているものが無い」というエラーになります。
ありがたいことに、Goのエラーメッセージ自体が「go get github.com/google/uuidを実行してね」と解決策を教えてくれています。
これがGoツールチェインの使いやすいところです。指示どおり実行してみます。
!go get github.com/google/uuid
go: downloading github.com/google/uuid v1.6.0
go: added github.com/google/uuid v1.6.0
go getは、次の2つを同時に行います。
- パッケージをダウンロードし、
go.modにrequire行を追記する - ダウンロードしたパッケージの内容からチェックサムを計算し、
go.sumに記録する
実際に中身を確認してみましょう。
!cat go.mod
module example.com/hello
go 1.18
require github.com/google/uuid v1.6.0 // indirect
ファイルの記述内容が変わりました。続いて、go.sumも見てみます。
!cat go.sum
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
go.modにはrequire github.com/google/uuid v1.6.0のような行が追加され、
go.sumには、そのパッケージのバージョンごとにハッシュ値の羅列が記録されています。
go.sumの中身は人間が読むものではありませんが、「このバージョンのパッケージは、間違いなくこのハッシュ値の中身である」
ということをGoツールチェインが自動検証するための材料です。
それでは、あらためて実行してみましょう。
!go run main.go
今度は
生成されたUUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
のように、実際にUUIDが生成されて表示されれば成功です。go.modとgo.sumが揃って、初めてビルドが通ります。
5. あえて go.sum を壊してみる(③ チェックサムが無いエラー)
go.modはあるが、go.sumが無い(または不完全な)場合にどうなるかも体験しておきましょう。
たとえば「go.modだけをGitで共有してもらったが、go.sumをコピーし忘れた」というのは、実務でもよくある事故です。
これを再現するために、go.sumを一時的に退避します。
!mv go.sum go.sum.bak
!ls -la
この状態で実行すると、Goはネットワーク上から改めてパッケージを取得しようとします。
それを防ぎ、「今ローカルにある情報だけで解決できるか」を厳格にチェックさせるために、
-mod=readonlyというオプション(Go 1.16以降はデフォルトで有効)を明示して実行してみます。
!GOFLAGS=-mod=readonly go run main.go
次のようなエラーになります。
main.go:6:2: missing go.sum entry for module providing package github.com/google/uuid; to add:
go mod download github.com/google/uuid
エラー③の解説
go.modにはgithub.com/google/uuidへの依存が書かれているにもかかわらず、
go.sumにそのチェックサムが無いため、Goは「このパッケージの中身が本物かどうか検証できない」と判断し、あえて止まります。
これは、go.modだけ手元にあってもgo.sumが欠けていると、
チーム内の別のメンバーの環境ではビルドが再現できない ということを意味します。
go.modとgo.sumは必ずセットでGit管理し、レビューやCIの対象に含めるべきファイルです。
元に戻して、正常に動くことを確認しておきましょう。
!mv go.sum.bak go.sum
!go run main.go
今度は正常に実行できました。
生成されたUUID: b539b0fc-0263-4eed-a633-43ff152ba970
6. go mod tidy の役割
ここまではgo getで依存を1つずつ追加してきましたが、実務ではgo mod tidyをこまめに実行する運用が一般的です。
go mod tidyは次のことをまとめて行います。
- ソースコード中でimportされているが
go.modに無い依存を追加する -
go.modにはあるが、実際には使われていない依存を削除する -
go.sumを、現在の依存関係と矛盾がない状態に整える
つまり「今のソースコードの実態」と「go.mod・go.sumの記載」を一致させるコマンドです。
コミット前に一度実行しておくと、依存の記載漏れ・消し忘れを防げます。
!go mod tidy
!echo "---go.mod---"
!cat go.mod
!echo "---再実行---"
!go run main.go
---go.mod---
module example.com/hello
go 1.18
require github.com/google/uuid v1.6.0
---再実行---
生成されたUUID: 0f3e4c1f-8e57-451f-906b-f2b60192fb48
まとめ:3つのエラーの早見表
今回体験したエラーを、対処法とあわせて振り返ります。
| エラーメッセージ(抜粋) | 意味 | 対処 |
|---|---|---|
go.mod file not found |
プロジェクトが未初期化 | go mod init <モジュール名> |
no required module provides package ... |
依存の宣言漏れ |
go get <パッケージ名> または go mod tidy
|
missing go.sum entry for module providing package ... |
チェックサムの欠落 |
go mod tidy または go mod download <パッケージ名>
|
エラーメッセージを読めば、Go自身が次に打つべきコマンドをほぼ教えてくれる。
これがGoのツールチェインを触っていて感じる大きな安心感です。
関連記事
Google ColabでGoを動かす基本は、こちらの記事で解説しています。
ビルド(バイナリ作成)の流れは、こちらです。
弊社について
本記事を書いている 合同会社インクルーシブソリューションズ は、データ基盤構築・分析基盤設計・システム改善支援を中心に活動している小規模IT法人です。
主な領域は、
- データマート設計・データパイプライン構築
- SQL / Python を用いたデータ処理設計
- BI導入支援・分析基盤の整備
- 既存システムの運用改善・可視化支援
といった、「データを使える状態にする」ための活動です。
弊社の企業活動に興味がある方は、ぜひ公式サイトも覗いてみてください。