[インデックス 17601] ファイルの概要
このコミットは、Go言語のビルドシステムにおけるファイルマッチングロジックの改善を目的としています。具体的には、go/build
パッケージにctxt.MatchFile
という新しいメソッドを追加し、既存のファイル選択ロジックをこの新しいメソッドに集約することで、コードの重複を排除し、保守性を向上させています。これにより、特定のファイルがビルドプロセスに含まれるべきかどうかを、より柔軟かつ正確に判断できるようになります。
コミット
commit aa53b37fa6aeb4ea378b5fc833f0aea5d6f9711e
Author: Russ Cox <rsc@golang.org>
Date: Sun Sep 15 11:29:47 2013 -0400
go/build: add ctxt.MatchFile
Fixes #6369.
R=dsymonds, r
CC=golang-dev
https://golang.org/cl/13708043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/aa53b37fa6aeb4ea378b5fc833f0aea5d6f9711e
元コミット内容
go/build: add ctxt.MatchFile
Fixes #6369.
変更の背景
このコミットの背景には、Go言語のビルドプロセスにおけるファイル選択ロジックの複雑さと重複がありました。Goのビルドシステムは、ソースファイルのファイル名(例: _test.go
、_windows.go
)やファイル内のビルドタグ(// +build linux,amd64
)に基づいて、どのファイルをビルドに含めるかを決定します。
以前のgo/build
パッケージでは、ImportDir
関数内でファイルシステムを走査し、各ファイルがビルド対象となるべきかを判断するロジックが直接記述されていました。このロジックは、ファイル名によるフィルタリング(_
や.
で始まるファイルの無視、OS/アーキテクチャ固有のファイル名の処理)と、ファイル内容を読み込んでビルドタグを解析する部分に分かれていました。
しかし、このファイル選択ロジックがImportDir
内に密結合しているため、以下のような問題がありました。
- コードの重複:
ImportDir
以外の場所で同様のファイル選択ロジックが必要になった場合、コードを重複させる必要がありました。 - テストの困難さ:
ImportDir
全体をテストすることなく、特定のファイルがビルド対象となるかどうかの判断ロジックだけを単体でテストすることが困難でした。 - 保守性の低下: ロジックが分散しているため、変更やデバッグが複雑になりがちでした。
これらの問題を解決し、ファイル選択ロジックを再利用可能でテストしやすい形にするために、ctxt.MatchFile
という新しい公開メソッドが導入されました。これにより、ファイル選択の責任がImportDir
からMatchFile
に分離され、よりクリーンな設計が実現されました。
関連するIssue #6369は、「go/build
パッケージに、特定のファイルがビルド対象となるかどうかを判断する関数を追加してほしい」という要望でした。このコミットは、その要望に応えるものです。
前提知識の解説
このコミットを理解するためには、以下のGo言語およびビルドシステムに関する前提知識が必要です。
-
go/build
パッケージ: Go言語の標準ライブラリの一つで、Goパッケージの構造を解析し、ビルドに必要な情報を取得するための機能を提供します。go build
コマンドやgo install
コマンドなどの内部で利用されています。主な機能として、指定されたディレクトリからGoパッケージをインポートしたり、ソースファイルの依存関係を解決したりする能力があります。 -
ビルドタグ (
// +build
コメント): Goのソースファイルには、ファイルの先頭に// +build
コメントを記述することで、そのファイルが特定のビルド条件(OS、アーキテクチャ、カスタムタグなど)が満たされた場合にのみビルドに含まれるように指定できます。例えば、// +build linux,amd64
と書かれたファイルは、LinuxかつAMD64アーキテクチャの場合にのみビルドされます。複数のタグはスペースまたはカンマで区切られ、カンマはAND条件、スペースはOR条件として扱われます。 -
OS/アーキテクチャ固有のファイル名: Goは、ファイル名にOS名やアーキテクチャ名を含めることで、特定の環境でのみビルドされるファイルを指定する慣習があります。例えば、
foo_windows.go
はWindowsでのみビルドされ、foo_amd64.go
はAMD64アーキテクチャでのみビルドされます。foo_linux_amd64.go
のように組み合わせることも可能です。 -
Context
構造体:go/build
パッケージのContext
構造体は、ビルド環境に関する情報(現在のOS、アーキテクチャ、GOPATHなど)を保持します。ファイル選択ロジックは、このContext
の情報に基づいて行われます。 -
ImportDir
関数: 指定されたディレクトリからGoパッケージの情報をインポートする関数です。この関数は、ディレクトリ内のファイルを走査し、ビルド対象となるGoソースファイル、C/C++/アセンブリソースファイル、その他の関連ファイルを識別します。 -
readImports
とreadComments
: Goソースファイルからインポートパスを読み取るためのヘルパー関数(readImports
)と、ファイルの先頭からコメントを読み取るためのヘルパー関数(readComments
)です。ビルドタグはコメントとして扱われるため、これらの関数がファイル選択ロジックで利用されます。
技術的詳細
このコミットの主要な技術的変更は、go/build
パッケージにおけるファイル選択ロジックのモジュール化です。
-
ctxt.MatchFile
メソッドの導入:Context
構造体に新しい公開メソッドMatchFile(dir, name string) (match bool, err error)
が追加されました。このメソッドは、指定されたディレクトリ(dir
)内のファイル名(name
)が、現在のビルドコンテキスト(ctxt
)においてビルド対象となるべきかどうかを判断します。 -
内部ヘルパー関数
ctxt.matchFile
:MatchFile
メソッドの実体として、内部ヘルパー関数ctxt.matchFile(dir, name string, returnImports bool, allTags map[string]bool)
が導入されました。この関数は、以下のロジックをカプセル化しています。- ファイル名のフィルタリング:
_
または.
で始まるファイル、および既知の拡張子を持たないファイルを無視します。 - OS/アーキテクチャ固有のファイル名のチェック:
ctxt.goodOSArchFile
を呼び出し、ファイル名が現在のOS/アーキテクチャに合致するかどうかを判断します。この際、allTags
マップが提供されていれば、ファイル名から検出されたOS/アーキテクチャタグを記録します。 - ファイル拡張子による初期フィルタリング:
.go
,.c
,.cc
,.cxx
,.cpp
,.s
,.h
,.hh
,.hpp
,.hxx
,.S
,.swig
,.swigcxx
などのソースファイル、および.syso
ファイル(バイナリオブジェクト)を対象とします。.syso
ファイルは内容を読み込まずにマッチと判断されます。 - ファイル内容の読み込みとビルドタグの解析: 対象となるソースファイルの場合、
ctxt.openFile
でファイルを開き、readImports
(Goファイルの場合)またはreadComments
(その他のファイルの場合)を使用してファイル内容の冒頭部分を読み込みます。 - ビルドタグによる最終判断: 読み込んだ内容から
// +build
コメントを解析し、ctxt.shouldBuild
を呼び出して、現在のビルドコンテキストでファイルがビルドされるべきかを最終的に判断します。
- ファイル名のフィルタリング:
-
ImportDir
からのロジックの抽出: 既存のImportDir
関数から、各ファイルを処理する際のファイル選択ロジックがctxt.matchFile
の呼び出しに置き換えられました。これにより、ImportDir
のコードが大幅に簡素化され、ファイル選択の複雑な詳細がmatchFile
内に隠蔽されました。 -
nameExt
ヘルパー関数の追加: ファイル名から拡張子を安全に抽出するための小さなヘルパー関数nameExt(name string) string
が追加されました。これは、ファイル名に.
が含まれない場合でも適切に空文字列を返すように設計されています。 -
テストの追加:
go/build/build_test.go
にTestMatchFile
という新しいテスト関数が追加されました。このテストは、さまざまなファイル名とビルドタグの組み合わせに対してctxt.MatchFile
が正しく動作するかどうかを検証します。これにより、ファイル選択ロジックの単体テストが可能になり、将来の変更に対する回帰テストの基盤が強化されました。
これらの変更により、go/build
パッケージのファイル選択ロジックはよりモジュール化され、再利用性、テスト容易性、および保守性が向上しました。
コアとなるコードの変更箇所
このコミットにおけるコアとなるコードの変更は、主に以下の2つのファイルに集中しています。
-
src/pkg/go/build/build.go
:nameExt
ヘルパー関数の追加。ctxt.MatchFile
公開メソッドの追加。ctxt.matchFile
内部ヘルパー関数の追加(これが実際のファイル選択ロジックをカプセル化)。ImportDir
関数内のファイル走査ループから、既存のファイル選択ロジックを削除し、新しく追加されたctxt.matchFile
の呼び出しに置き換え。ctxt.goodOSArchFile
関数内で、allTags
マップがnil
でない場合にのみタグを記録するように変更(matchFile
からの呼び出しでallTags
がnil
の場合があるため)。
-
src/pkg/go/build/build_test.go
:readNopCloser
というテスト用のヘルパー型を追加。これはio.ReadCloser
インターフェースを満たし、テスト中にファイルの内容をシミュレートするために使用されます。matchFileTests
というテストケースの配列を追加。TestMatchFile
という新しいテスト関数を追加。この関数は、matchFileTests
の各ケースに対してctxt.MatchFile
を呼び出し、期待される結果と比較します。テストでは、ctxt.OpenFile
とctxt.JoinPath
をモックすることで、実際のファイルシステムアクセスなしにテストを実行できるようにしています。
src/pkg/go/build/build.go
の変更点(抜粋)
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -408,6 +408,14 @@ func (e *NoGoError) Error() string {
return "no buildable Go source files in " + e.Dir
}
+func nameExt(name string) string {
+ i := strings.LastIndex(name, ".")
+ if i < 0 {
+ return ""
+ }
+ return name[i:]
+}
+
// Import returns details about the Go package named by the import path,
// interpreting local import paths relative to the srcDir directory.
// If the path is a local import path naming a package that can be imported
@@ -591,58 +599,15 @@ Found:
if d.IsDir() {
continue
}
- name := d.Name()
- if strings.HasPrefix(name, "_") ||
- strings.HasPrefix(name, ".") {
- continue
- }
-
- i := strings.LastIndex(name, ".")
- if i < 0 {
- i = len(name)
- }
- ext := name[i:]
-
- if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
- if ext == ".go" {
- p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
- }
- continue
- }
-
- switch ext {
- case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
- // tentatively okay - read to make sure
- case ".syso":
- // binary objects to add to package archive
- // Likely of the form foo_windows.syso, but
- // the name was vetted above with goodOSArchFile.
- p.SysoFiles = append(p.SysoFiles, name)
- continue
- default:
- // skip
- continue
- }
+ name := d.Name()
+ ext := nameExt(name)
- filename := ctxt.joinPath(p.Dir, name)
- f, err := ctxt.openFile(filename)
+ match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags)
if err != nil {
return p, err
}
-
- var data []byte
- if strings.HasSuffix(filename, ".go") {
- data, err = readImports(f, false)
- } else {
- data, err = readComments(f)
- }
- f.Close()
- if err != nil {
- return p, fmt.Errorf("read %s: %v", filename, err)
- }
-
- // Look for +build comments to accept or reject the file.
- if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles {
+ if !match {
if ext == ".go" {
p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
}
@@ -672,6 +637,79 @@ Found:
case ".swigcxx":
p.SwigCXXFiles = append(p.SwigCXXFiles, name)
continue
+ case ".syso":
+ // binary objects to add to package archive
+ // Likely of the form foo_windows.syso, but
+ // the name was vetted above with goodOSArchFile.
+ p.SysoFiles = append(p.SysoFiles, name)
+ continue
}
pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
@@ -782,6 +753,79 @@ Found:
return p, pkgerr
}
+// MatchFile reports whether the file with the given name in the given directory
+// matches the context and would be included in a Package created by ImportDir
+// of that directory.
+//
+// MatchFile considers the name of the file and may use ctxt.OpenFile to
+// read some or all of the file's content.
+func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
+ match, _, _, err = ctxt.matchFile(dir, name, false, nil)
+ return
+}
+
+// matchFile determines whether the file with the given name in the given directory
+// should be included in the package being constructed.
+// It returns the data read from the file.
+// If returnImports is true and name denotes a Go program, matchFile reads
+// until the end of the imports (and returns that data) even though it only
+// considers text until the first non-comment.
+// If allTags is non-nil, matchFile records any encountered build tag
+// by setting allTags[tag] = true.
+func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool) (match bool, data []byte, filename string, err error) {
+ if strings.HasPrefix(name, "_") ||
+ strings.HasPrefix(name, ".") {
+ return
+ }
+
+ i := strings.LastIndex(name, ".")
+ if i < 0 {
+ i = len(name)
+ }
+ ext := name[i:]
+
+ if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
+ return
+ }
+
+ switch ext {
+ case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
+ // tentatively okay - read to make sure
+ case ".syso":
+ // binary, no reading
+ match = true
+ return
+ default:
+ // skip
+ return
+ }
+
+ filename = ctxt.joinPath(dir, name)
+ f, err := ctxt.openFile(filename)
+ if err != nil {
+ return
+ }
+
+ if strings.HasSuffix(filename, ".go") {
+ data, err = readImports(f, false)
+ } else {
+ data, err = readComments(f)
+ }
+ f.Close()
+ if err != nil {
+ err = fmt.Errorf("read %s: %v", filename, err)
+ return
+ }
+
+ // Look for +build comments to accept or reject the file.
+ if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles {
+ return
+ }
+
+ match = true
+ return
+}
+
func cleanImports(m map[string][]token.Position) ([]string, map[string][]token.Position) {
all := make([]string, 0, len(m))
for path := range m {
@@ -1114,16 +1158,22 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
}\n := len(l)
if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
- allTags[l[n-2]] = true
- allTags[l[n-1]] = true
+ if allTags != nil {
+ allTags[l[n-2]] = true
+ allTags[l[n-1]] = true
+ }
return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
}
if n >= 1 && knownOS[l[n-1]] {
- allTags[l[n-1]] = true
+ if allTags != nil {
+ allTags[l[n-1]] = true
+ }
return l[n-1] == ctxt.GOOS
}
if n >= 1 && knownArch[l[n-1]] {
- allTags[l[n-1]] = true
+ if allTags != nil {
+ allTags[l[n-1]] = true
+ }
return l[n-1] == ctxt.GOARCH
}
return true
src/pkg/go/build/build_test.go
の変更点(抜粋)
--- a/src/pkg/go/build/build_test.go
+++ b/src/pkg/go/build/build_test.go
@@ -5,10 +5,12 @@
package build
import (
+ "io"
"os"
"path/filepath"
"reflect"
"runtime"
+ "strings"
"testing"
)
@@ -142,3 +144,43 @@ func TestShouldBuild(t *testing.T) {
t.Errorf("shoudBuild(file3) tags = %v, want %v", m, want3)\n }\n }\n+\n+type readNopCloser struct {\n+\tio.Reader\n+}\n+\n+func (r readNopCloser) Close() error {\n+\treturn nil\n+}\n+\n+var matchFileTests = []struct {\n+\tname string\n+\tdata string\n+\tmatch bool\n+}{\n+\t{\"foo_arm.go\", \"\", true},\n+\t{\"foo1_arm.go\", \"// +build linux\\n\\npackage main\\n\", false},\n+\t{\"foo_darwin.go\", \"\", false},\n+\t{\"foo.go\", \"\", true},\n+\t{\"foo1.go\", \"// +build linux\\n\\npackage main\\n\", false},\n+\t{\"foo.badsuffix\", \"\", false},\n+}\n+\n+func TestMatchFile(t *testing.T) {\n+\tfor _, tt := range matchFileTests {\n+\t\tctxt := Context{GOARCH: "arm", GOOS: "plan9"}\n+\t\tctxt.OpenFile = func(path string) (r io.ReadCloser, err error) {\n+\t\t\tif path != "x+"+tt.name {\n+\t\t\t\tt.Fatalf("OpenFile asked for %q, expected %q", path, "x+"+tt.name)\n+\t\t\t}\n+\t\t\treturn &readNopCloser{strings.NewReader(tt.data)}, nil\n+\t\t}\n+\t\tctxt.JoinPath = func(elem ...string) string {\n+\t\t\treturn strings.Join(elem, "+")\n+\t\t}\n+\t\tmatch, err := ctxt.MatchFile("x", tt.name)\n+\t\tif match != tt.match || err != nil {\n+\t\t\tt.Fatalf("MatchFile(%q) = %v, %v, want %v, nil", tt.name, match, err, tt.match)\n+\t\t}\n+\t}\n+}\n```
## コアとなるコードの解説
### `nameExt` 関数
```go
func nameExt(name string) string {
i := strings.LastIndex(name, ".")
if i < 0 {
return ""
}
return name[i:]
}
この小さなヘルパー関数は、与えられたファイル名から拡張子を抽出します。strings.LastIndex
で最後の.
の位置を見つけ、それ以降の文字列を返します。もし.
が見つからなければ(つまり拡張子がないファイル名であれば)、空文字列を返します。これは、以前のImportDir
内のロジックで拡張子を抽出していた部分を共通化したものです。
Context.MatchFile
メソッド
func (ctxt *Context) MatchFile(dir, name string) (match bool, err error) {
match, _, _, err = ctxt.matchFile(dir, name, false, nil)
return
}
これはgo/build
パッケージの外部から呼び出されることを意図した公開APIです。内部のctxt.matchFile
を呼び出していますが、returnImports
はfalse
に、allTags
はnil
に設定されています。これは、MatchFile
が単にファイルがマッチするかどうかを報告するだけで、インポート情報を返す必要がなく、またビルドタグの収集もこのメソッドの主要な目的ではないためです。
Context.matchFile
メソッド (内部ヘルパー)
func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map[string]bool) (match bool, data []byte, filename string, err error) {
// 1. ファイル名のフィルタリング
if strings.HasPrefix(name, "_") ||
strings.HasPrefix(name, ".") {
return // "_" または "." で始まるファイルは無視
}
// 2. 拡張子の抽出
i := strings.LastIndex(name, ".")
if i < 0 {
i = len(name)
}
ext := name[i:]
// 3. OS/アーキテクチャ固有のファイル名のチェック
if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles {
return // 現在のOS/アーキテクチャに合致しないファイルは無視
}
// 4. 拡張子による初期フィルタリング
switch ext {
case ".go", ".c", ".cc", ".cxx", ".cpp", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
// 暫定的にOK - 内容を読んで最終確認
case ".syso":
// バイナリファイルは内容を読まずにマッチと判断
match = true
return
default:
return // その他の拡張子は無視
}
// 5. ファイルの読み込み
filename = ctxt.joinPath(dir, name)
f, err := ctxt.openFile(filename)
if err != nil {
return // ファイルを開けない場合はエラー
}
if strings.HasSuffix(filename, ".go") {
data, err = readImports(f, false) // Goファイルはインポート部分まで読み込む
} else {
data, err = readComments(f) // その他のファイルはコメント部分まで読み込む
}
f.Close()
if err != nil {
err = fmt.Errorf("read %s: %v", filename, err)
return // ファイル読み込みエラー
}
// 6. ビルドタグによる最終判断
if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles {
return // ビルドタグの条件を満たさないファイルは無視
}
match = true // 全ての条件をクリアした場合、マッチと判断
return
}
この関数は、ファイルがビルド対象となるべきかを判断する中心的なロジックを含んでいます。
- ファイル名のプレフィックスチェック:
_
や.
で始まるファイルは、通常、一時ファイルや隠しファイルとして扱われるため、ビルド対象から除外されます。 - 拡張子抽出:
nameExt
関数を使って拡張子を取得します。 - OS/アーキテクチャチェック:
ctxt.goodOSArchFile
を呼び出し、ファイル名が現在のOSやアーキテクチャに合致するかどうかを確認します。例えば、foo_windows.go
はWindows環境でのみマッチします。allTags
がnil
でない場合、検出されたOS/アーキテクチャタグがそのマップに記録されます。 - 拡張子による初期分類:
.go
、.c
、.s
などのソースファイルは、さらに内容を読み込んでビルドタグをチェックする必要があります。.syso
のようなバイナリファイルは内容を読まずにマッチと判断されます。その他の不明な拡張子は無視されます。 - ファイル内容の読み込み:
ctxt.openFile
でファイルを開き、GoファイルであればreadImports
(インポート文まで)、それ以外であればreadComments
(コメント部分まで)を呼び出して、ビルドタグが含まれる可能性のある冒頭部分を読み込みます。 - ビルドタグの評価: 読み込んだデータと
ctxt.shouldBuild
を使って、ファイル内の// +build
コメントが現在のビルドコンテキストに合致するかどうかを判断します。 - 最終的なマッチ判断: 上記の全てのチェックを通過した場合にのみ、ファイルはマッチすると判断されます。
ImportDir
関数の変更
ImportDir
関数では、以前はmatchFile
のロジックが直接記述されていましたが、このコミットにより、その部分がctxt.matchFile
の呼び出しに置き換えられました。
// 変更前 (簡略化)
// ...
// for _, d := range list {
// name := d.Name()
// // ここにファイル名、拡張子、OS/Arch、ビルドタグのチェックロジックが直接記述されていた
// // ...
// if !ctxt.goodOSArchFile(name, allTags) && !ctxt.UseAllFiles { ... }
// // ...
// if !ctxt.shouldBuild(data, allTags) && !ctxt.UseAllFiles { ... }
// // ...
// }
// 変更後 (簡略化)
// ...
// for _, d := range list {
// name := d.Name()
// ext := nameExt(name) // 新しいヘルパー関数を使用
// match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags) // matchFileを呼び出し
// if err != nil {
// return p, err
// }
// if !match {
// if ext == ".go" {
// p.IgnoredGoFiles = append(p.IgnoredGoFiles, name)
// }
// continue
// }
// // ... (マッチしたファイルの処理は継続)
// }
この変更により、ImportDir
はファイル選択の詳細から解放され、より高レベルなパッケージインポートのロジックに集中できるようになりました。
ctxt.goodOSArchFile
の変更
--- a/src/pkg/go/build/build.go
+++ b/src/pkg/go/build/build.go
@@ -1114,16 +1158,22 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
}\n := len(l)
if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
- allTags[l[n-2]] = true
- allTags[l[n-1]] = true
+ if allTags != nil { // allTagsがnilでない場合のみ記録
+ allTags[l[n-2]] = true
+ allTags[l[n-1]] = true
+ }
return l[n-2] == ctxt.GOOS && l[n-1] == ctxt.GOARCH
}
if n >= 1 && knownOS[l[n-1]] {
- allTags[l[n-1]] = true
+ if allTags != nil { // allTagsがnilでない場合のみ記録
+ allTags[l[n-1]] = true
+ }
return l[n-1] == ctxt.GOOS
}
if n >= 1 && knownArch[l[n-1]] {
- allTags[l[l-1]] = true
+ if allTags != nil { // allTagsがnilでない場合のみ記録
+ allTags[l[n-1]] = true
+ }
return l[n-1] == ctxt.GOARCH
}
return true
ctxt.goodOSArchFile
関数は、ファイル名からOSやアーキテクチャのタグを抽出し、それらが現在のビルドコンテキストに合致するかどうかを判断します。このコミットでは、allTags
マップがnil
でない場合にのみ、抽出されたタグをそのマップに記録するように変更されました。これは、ctxt.MatchFile
のようにタグ収集が不要な呼び出し元からallTags
がnil
で渡される可能性があるため、nil
ポインタ参照を防ぐための安全策です。
関連リンク
- Go Issue #6369:
go/build: add a function to check if a file would be built
- Go Code Review (CL 13708043):
go/build: add ctxt.MatchFile
参考にした情報源リンク
- Go言語公式ドキュメント:
go/build
パッケージ - Go言語公式ドキュメント: ビルド制約 (Build Constraints)
- Go言語のビルドタグに関する解説記事 (例: Go言語のビルドタグを理解する)
- (一般的なGoのビルドタグに関する解説記事を検索し、内容を参考にしました。特定のURLは記載しませんが、
go build tags
などで検索すると多数見つかります。)
- (一般的なGoのビルドタグに関する解説記事を検索し、内容を参考にしました。特定のURLは記載しませんが、
- Go言語のソースコード (特に
src/cmd/go/internal/load/pkg.go
やsrc/cmd/go/internal/work/build.go
など、go/build
パッケージを利用している箇所) - Go言語のテストフレームワークに関する情報 (例:
testing
パッケージ) - Go言語の
strings
パッケージ - Go言語の
io
パッケージ - Go言語の
fmt
パッケージ - Go言語の
go/parser
パッケージ - Go言語の
go/token
パッケージ - Go言語の
path/filepath
パッケージ - Go言語の
reflect
パッケージ - Go言語の
runtime
パッケージ - Go言語の
os
パッケージ