Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 14285] ファイルの概要

このコミットは、Go言語の標準ビルドツールである cmd/go における gccgo サポートの改善に関するものです。具体的には、src/cmd/go/build.go ファイルが変更されており、gccgo コンパイラとの連携をよりスムーズにするための様々な修正が含まれています。

コミット

commit f284a3ff4d525da4fb1dff6580588cabdbeab423
Author: Ian Lance Taylor <iant@golang.org>
Date:   Thu Nov 1 11:13:50 2012 -0700

    cmd/go: fixes to gccgo support
    
    * Use -fgo-pkgpath and -gccgopkgpath rather than -fgo-prefix
      and -gccgoprefix.
    * Define GOPKGPATH when compiling .c or .s files for gccgo.
    * Use -fgo-relative-import-path.
    * Produce .o files for gccgo, not .[568] files.
    * Pass -E when linking if using cgo.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6820064

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/f284a3ff4d525da4fb1dff6580588cabdbeab423

元コミット内容

cmd/go ツールにおける gccgo サポートの修正。

  • -fgo-prefix および -gccgoprefix の代わりに -fgo-pkgpath および -gccgopkgpath を使用する。
  • gccgo 用に .c または .s ファイルをコンパイルする際に GOPKGPATH を定義する。
  • -fgo-relative-import-path を使用する。
  • gccgo 用に .[568] ファイルではなく .o ファイルを生成する。
  • cgo を使用している場合、リンク時に -E を渡す。

変更の背景

このコミットは、Go言語の公式ビルドツールである cmd/go が、代替コンパイラである gccgo を使用する際の互換性と機能性を向上させるために行われました。

Go言語には主に2つのコンパイラ実装があります。一つは公式のGoコンパイラ(通称 gc または cmd/compile)で、もう一つはGCCのフロントエンドとして実装された gccgo です。cmd/go ツールは、デフォルトでは gc を使用しますが、gccgo を使用するように設定することも可能です。

このコミット以前は、cmd/gogccgo を利用する際にいくつかの不整合や機能不足がありました。具体的には、以下のような問題が考えられます。

  1. フラグ名の不一致: gccgo が期待するパッケージパス関連のフラグ名と、cmd/go が生成していたフラグ名が異なっていた可能性があります。これにより、gccgo がパッケージパスを正しく認識できない問題が発生していました。
  2. C/アセンブリコードとの連携不足: gccgo でビルドする際に、Goのパッケージパス情報がCやアセンブリのソースコードに適切に渡されていなかったため、これらの言語で書かれた部分がGoのパッケージ構造を認識できない可能性がありました。
  3. オブジェクトファイル形式の不統一: gc コンパイラは、ターゲットアーキテクチャに応じて .5 (ARM), .6 (x86-64), .8 (x86) といった独自のオブジェクトファイル拡張子を使用します。しかし、gccgo は標準的なGCCのツールチェーンの一部であるため、通常は .o 拡張子を使用します。この不一致がビルドシステム内で混乱を招いたり、他のGCCツールとの連携を妨げたりする可能性がありました。
  4. Cgoと動的リンクの問題: cgo を使用してC/C++コードをGoプログラムに組み込む場合、特にLinuxのようなシステムでは、動的リンク時のシンボル解決に特定のリンカフラグが必要となることがあります。このフラグが不足していると、実行時にリンクエラーが発生する可能性がありました。

これらの問題を解決し、cmd/gogccgo の間の連携をより堅牢で標準的なものにすることが、このコミットの主な背景です。

前提知識の解説

Go言語のビルドシステム (cmd/go)

cmd/go は、Go言語のソースコードをビルド、テスト、インストール、管理するための公式コマンドラインツールです。Goのワークスペース、モジュール、パッケージの概念を理解し、依存関係の解決、コンパイル、アセンブル、リンクといった一連のビルドプロセスを自動化します。 cmd/go は内部的に、Goコンパイラ (gc)、アセンブラ (go tool asm)、リンカ (go tool link) などのツールを呼び出して実行します。

gccgo

gccgo は、Go言語のプログラムをGCC (GNU Compiler Collection) のフロントエンドとしてコンパイルするツールチェーンです。標準のGoコンパイラ (gc) とは独立して開発されており、GCCの最適化や既存のC/C++ライブラリとの連携といったGCCエコシステムの利点を活用できます。gccgo はGoの仕様に準拠していますが、内部実装や生成されるバイナリの特性は gc と異なる場合があります。

Cgo

cgo は、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのツールです。Goのソースファイル内にCのコードを直接記述し、cgo がGoとCの間のインターフェースコードを生成します。これにより、既存のCライブラリをGoから利用したり、パフォーマンスが重要な部分をCで記述したりすることが可能になります。

パッケージパス (Package Path)

Go言語において、パッケージパスはパッケージの一意な識別子です。例えば、"fmt""github.com/user/repo/mypackage" のように、通常はインポートパスとして使用されます。コンパイラやリンカは、このパッケージパス情報を使用して、依存関係を解決したり、生成されるバイナリ内でパッケージを識別したりします。

オブジェクトファイル (.o, .5/.6/.8)

オブジェクトファイルは、コンパイラやアセンブラによって生成される中間ファイルで、ソースコードを機械語に変換したものです。まだ完全に実行可能な形式ではなく、他のオブジェクトファイルやライブラリとリンクされて最終的な実行可能ファイルやライブラリになります。

  • .o: これはUnix系システムで一般的なオブジェクトファイルの拡張子で、GCCを含む多くのコンパイラが使用します。
  • .5, .6, .8: これらはGoの標準コンパイラ (gc) が使用する独自のオブジェクトファイル拡張子です。それぞれ、gc がサポートする異なるアーキテクチャ(例: .5 はARM、.6 はx86-64、.8 はx86)に対応しています。この独自の命名規則は、Goのビルドシステムが特定のアーキテクチャ向けのオブジェクトファイルを識別するために使われていました。

リンカフラグ (-Wl,-E)

リンカは、複数のオブジェクトファイルやライブラリを結合して最終的な実行可能ファイルを作成するツールです。リンカには様々なオプション(フラグ)を渡すことができ、その挙動を制御します。 -Wl,option は、GCCなどのコンパイラドライバがリンカに直接 option を渡すための一般的な構文です。 -Wl,-E は、特にLinuxシステムにおいて、動的リンカの挙動に影響を与える重要なフラグです。このフラグは、実行可能ファイルがロードされる際に、環境変数 LD_PRELOAD で指定されたライブラリや、実行可能ファイル自体に埋め込まれた DT_RPATHDT_RUNPATH エントリで指定されたパスを検索対象に含めるようにリンカに指示します。cgo を使用してGoプログラムがCライブラリに依存する場合、このフラグがないと、実行時に必要なシンボルが見つからずにエラーとなることがあります。

技術的詳細

このコミットで行われた技術的な変更は、cmd/gogccgo ツールチェーンとより密接に、かつ標準的な方法で連携できるようにするためのものです。

  1. フラグ名の統一 (-fgo-prefix -> -fgo-pkgpath):

    • 以前は gccgo にパッケージパスを渡す際に -fgo-prefix というフラグが使われていましたが、これは gccgo の内部的な命名規則や他のGCCフロントエンドとの整合性を考慮して -fgo-pkgpath に変更されました。この変更は、gccgo コンパイラ (gc メソッド内) と cgo ツール (cgo メソッド内) の両方に適用されています。
    • gccgoPrefix 関数は削除され、より汎用的な gccgoPkgpath 関数が導入されました。gccgoPkgpath は、コマンドではないパッケージや強制的にライブラリとして扱われるパッケージに対しては p.ImportPath をそのまま返し、それ以外の場合は空文字列を返します。これにより、パッケージパスの概念がより直接的に gccgo に伝わるようになります。
  2. GOPKGPATH マクロの定義:

    • gccgo.c または .s (Cまたはアセンブリ) ファイルをコンパイルする際、プリプロセッサマクロ GOPKGPATH が定義されるようになりました。このマクロの値は、Goのパッケージパスをサニタイズ(非英数字をアンダースコアに変換)したものです。
    • これは gccgcToolchain.asm および gccgcToolchain.cc メソッドで行われます。Cやアセンブリのコード内で #ifdef GOPKGPATH のような形でこのマクロを利用することで、Goのパッケージパスに基づいて条件付きコンパイルを行ったり、デバッグ情報を埋め込んだりすることが可能になります。これにより、GoとC/アセンブリの間の連携が強化されます。
  3. 相対インポートパスのサポート (-fgo-relative-import-path):

    • gccgcToolchain.gc メソッドにおいて、パッケージに p.localPrefix が設定されている場合、-fgo-relative-import-path フラグが gccgo に渡されるようになりました。これは、Goモジュール内で相対的なインポートパスが使用されるシナリオに対応するためのものです。gccgo がこれらの相対パスを正しく解決できるようになり、より複雑なプロジェクト構造をサポートします。
  4. オブジェクトファイル拡張子の統一 (.[568] -> .o):

    • cmd/go は、gccgo を使用する場合、C (.c) およびアセンブリ (.s) ファイルのコンパイル結果として、Goの標準コンパイラが使用する .5, .6, .8 ではなく、標準的な .o 拡張子のオブジェクトファイルを生成するようになりました。
    • これは build.goobjExt 変数の設定と、cc および asm メソッドの出力ファイル名生成ロジックの変更によって実現されています。この変更により、gccgo が生成するオブジェクトファイルが他のGCCツールや標準的なビルドシステムと互換性を持つようになり、ビルドプロセスの整合性が向上します。
  5. リンカの -E フラグの追加:

    • gccgcToolchain.ld メソッドにおいて、cgo ファイルが使用されている (usesCgo が true) かつOSがLinux (goos == "linux") の場合、リンカに -Wl,-E フラグが渡されるようになりました。
    • このフラグは、特にLinux環境で cgo を介して動的にリンクされるCライブラリのシンボル解決を助けます。これにより、cgo を使用したGoプログラムが、実行時に必要な共有ライブラリを正しく見つけられるようになり、リンクエラーや実行時エラーのリスクが低減されます。
  6. gccgoCleanPkgpath 関数の導入:

    • 新しいヘルパー関数 gccgoCleanPkgpath が追加されました。この関数は、gccgoPkgpath から得られたパッケージパスを受け取り、英数字以外の文字をアンダースコア (_) に置換します。これは、パッケージパスをCプリプロセッサマクロ (-D) の値として安全に使用できるようにするためです。マクロ名やその値には特定の文字しか使用できないため、このサニタイズ処理は必須です。

これらの変更は、cmd/gogccgo をバックエンドとして使用する際のビルドの信頼性、互換性、および機能性を大幅に向上させるものです。

コアとなるコードの変更箇所

変更は主に src/cmd/go/build.go ファイルに集中しています。

  1. オブジェクトファイル拡張子の決定ロジックの変更 (L745-760):

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -745,8 +745,13 @@ func (b *builder) build(a *action) (err error) {
     		}
     	}
     
    +	objExt := archChar
    +	if _, ok := buildToolchain.(gccgcToolchain); ok {
    +		objExt = "o"
    +	}
    +
     	for _, file := range cfiles {
    -		out := file[:len(file)-len(".c")] + "." + archChar
    +		out := file[:len(file)-len(".c")] + "." + objExt
     		if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
     			return err
     		}
    @@ -755,7 +760,7 @@ func (b *builder) build(a *action) (err error) {
     
     	// Assemble .s files.
     	for _, file := range sfiles {
    -		out := file[:len(file)-len(".s")] + "." + archChar
    +		out := file[:len(file)-len(".s")] + "." + objExt
     		if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
     			return err
     		}
    

    gccgcToolchain を使用する場合、オブジェクトファイルの拡張子を archChar (例: 5, 6, 8) から "o" に変更。

  2. gccgcToolchain.gc (Goコンパイラ) のフラグ変更 (L1355-1364):

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -1355,8 +1360,11 @@ func (gccgcToolchain) gc(b *builder, p *Package, obj string, importArgs []string
     	out := p.Name + ".o"
     	ofile = obj + out
     	gcargs := []string{"-g"}
    -	if prefix := gccgoPrefix(p); prefix != "" {
    -		gcargs = append(gcargs, "-fgo-prefix="+gccgoPrefix(p))
    +	if pkgpath := gccgoPkgpath(p); pkgpath != "" {
    +		gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
    +	}
    +	if p.localPrefix != "" {
    +		gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
     	}
     	args := stringList("gccgo", importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
     	for _, f := range gofiles {
    

    -fgo-prefix-fgo-pkgpath に変更し、p.localPrefix があれば -fgo-relative-import-path を追加。

  3. gccgcToolchain.asm (アセンブラ) での GOPKGPATH 定義 (L1367-1373):

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -1367,7 +1375,11 @@ func (gccgcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
     func (gccgcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
     	sfile = mkAbs(p.Dir, sfile)
     	return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, "-DGOOS_"+goos, "-DGOARCH_"+goarch, sfile)
    +	defs := []string{"-DGOOS_" + goos, "-DGOARCH_" + goarch}
    +	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
    +		defs = append(defs, `-DGOPKGPATH="`+pkgpath+`"`)\n+	}
    +	return b.run(p.Dir, p.ImportPath, "gccgo", "-I", obj, "-o", ofile, defs, sfile)
     }
    

    .s ファイルコンパイル時に GOPKGPATH マクロを定義。

  4. gccgcToolchain.ld (リンカ) での cgo 検出と -E フラグ追加 (L1392-1433):

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -1392,6 +1404,7 @@ func (tools gccgcToolchain) ld(b *builder, p *Package, out string, allactions []
     	sfiles := make(map[*Package][]string)
     	ldflags := []string{}
     	cgoldflags := []string{}
    +	usesCgo := false
     	for _, a := range allactions {
     		if a.p != nil {
     			if !a.p.Standard {
    @@ -1400,12 +1413,16 @@ func (tools gccgcToolchain) ld(b *builder, p *Package, out string, allactions []
     				}
     			}
     			cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
    +			if len(a.p.CgoFiles) > 0 {
    +				usesCgo = true
    +			}
     			if a.p.usesSwig() {
     				sd := a.p.swigDir(&buildContext)
     				for _, f := range stringList(a.p.SwigFiles, a.p.SwigCXXFiles) {
     					soname := a.p.swigSoname(f)
     					sfiles[a.p] = append(sfiles[a.p], filepath.Join(sd, soname))
     				}
    +				usesCgo = true
     			}
     		}
     	}
    @@ -1416,25 +1433,40 @@ func (tools gccgcToolchain) ld(b *builder, p *Package, out string, allactions []
     		ldflags = append(ldflags, sfiles...)
     	}
     	ldflags = append(ldflags, cgoldflags...)
    +	if usesCgo && goos == "linux" {
    +		ldflags = append(ldflags, "-Wl,-E")
    +	}
     	return b.run(".", p.ImportPath, "gccgo", "-o", out, buildGccgoflags, ofiles, "-Wl,-(", ldflags, "-Wl,)")
     }
    

    usesCgo フラグを導入し、cgo または swig が使用され、かつLinuxの場合にリンカに -Wl,-E を追加。

  5. gccgcToolchain.cc (Cコンパイラ) での GOPKGPATH 定義 (L1435-1444):

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -1435,8 +1444,11 @@ func (tools gccgcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
     func (gccgcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
     	inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
     	cfile = mkAbs(p.Dir, cfile)
    +	defs := []string{"-DGOOS_" + goos, "-DGOARCH_" + goarch}
    +	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
    +		defs = append(defs, `-DGOPKGPATH="`+pkgpath+`"`)\n+	}
     	return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
    -		"-I", objdir, "-I", inc, "-o", ofile,
    -		"-DGOOS_"+goos, "-DGOARCH_"+goarch, "-c", cfile)
    +		"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
     }
    

    .c ファイルコンパイル時に GOPKGPATH マクロを定義。

  6. gccgoPrefix の削除と gccgoPkgpath, gccgoCleanPkgpath の追加 (L1446-1466):

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -1446,14 +1455,23 @@ func (gccgcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
     	return b.run(p.Dir, p.ImportPath, "gcc", "-Wall", "-g",
     		"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
     }
     
    -func gccgoPrefix(p *Package) string {
    -	switch {
    -	case p.build.IsCommand() && !p.forceLibrary:
    +func gccgoPkgpath(p *Package) string {
    +	if p.build.IsCommand() && !p.forceLibrary {
     		return ""
    -	case p.fake:
    -		return "fake_" + p.ImportPath
     	}
    -	return "go_" + p.ImportPath
    +	return p.ImportPath
    +}
    +
    +func gccgoCleanPkgpath(p *Package) string {
    +	clean := func(r rune) rune {
    +		switch {
    +		case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
    +			'0' <= r && r <= '9':
    +			return r
    +		}
    +		return '_'
    +	}
    +	return strings.Map(clean, gccgoPkgpath(p))
     }
     
     // libgcc returns the filename for libgcc, as determined by invoking gcc with
    

    gccgoPrefix 関数を削除し、gccgoPkgpathgccgoCleanPkgpath を新しく定義。

  7. builder.cgo でのフラグ変更とオブジェクト拡張子設定 (L1563-1570):

    --- a/src/cmd/go/build.go
    +++ b/src/cmd/go/build.go
    @@ -1563,8 +1595,8 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\
     
     	if _, ok := buildToolchain.(gccgcToolchain); ok {
     		cgoflags = append(cgoflags, "-gccgo")
    -		if prefix := gccgoPrefix(p); prefix != "" {
    -			cgoflags = append(cgoflags, "-gccgoprefix="+gccgoPrefix(p))
    +		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
    +			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
     		}
     		objExt = "o"
     	}
    

    -gccgoprefix-gccgopkgpath に変更し、objExt"o" に設定。

コアとなるコードの解説

オブジェクトファイル拡張子の統一

    objExt := archChar
    if _, ok := buildToolchain.(gccgcToolchain); ok {
        objExt = "o"
    }
    // ...
    out := file[:len(file)-len(".c")] + "." + objExt
    // ...
    out := file[:len(file)-len(".s")] + "." + objExt

この変更は、cmd/gogccgo ツールチェーンを使用しているかどうかを buildToolchain.(gccgcToolchain) で確認し、もし gccgo であれば、C (.c) およびアセンブリ (.s) ファイルから生成されるオブジェクトファイルの拡張子を標準的な .o に設定します。Goの標準コンパイラ (gc) はアーキテクチャ固有の拡張子(例: .5, .6, .8)を使用しますが、gccgo はGCCの慣習に従うため、この統一は互換性にとって重要です。

gccgcToolchain.gc (Goコンパイラ) のフラグ変更

    if pkgpath := gccgoPkgpath(p); pkgpath != "" {
        gcargs = append(gcargs, "-fgo-pkgpath="+pkgpath)
    }
    if p.localPrefix != "" {
        gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
    }

gccgo コンパイラを呼び出す際に渡す引数 (gcargs) が変更されました。

  • gccgoPkgpath(p) は、パッケージのインポートパスを返します。これが空でなければ、-fgo-pkgpath= フラグが追加されます。これは、gccgo がGoのパッケージパスを正しく認識し、内部的なシンボル名や依存関係の解決に利用できるようにするためです。以前の -fgo-prefix よりも、その意図が明確になりました。
  • p.localPrefix は、Goモジュールにおける相対的なインポートパスのプレフィックスを示す可能性があります。これが存在する場合、-fgo-relative-import-path= フラグが追加され、gccgo が相対インポートを適切に処理できるようになります。

gccgcToolchain.asm および gccgcToolchain.cc での GOPKGPATH 定義

    defs := []string{"-DGOOS_" + goos, "-DGOARCH_" + goarch}
    if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
        defs = append(defs, `-DGOPKGPATH="`+pkgpath+`"`)
    }
    return b.run(p.Dir, p.ImportPath, "gccgo", /* ... */, defs, sfile) // for .s files
    // ...
    return b.run(p.Dir, p.ImportPath, "gcc", /* ... */, defs, "-c", cfile) // for .c files

アセンブリ (.s) およびC (.c) ファイルをコンパイルする際、gccgoCleanPkgpath(p) でサニタイズされたGoのパッケージパスが、プリプロセッサマクロ GOPKGPATH として定義されます。例えば、パッケージパスが "github.com/foo/bar" であれば、GOPKGPATH"github_com_foo_bar" のような値になります。これにより、Cやアセンブリのソースコード内で #ifdef GOPKGPATHGOPKGPATH の値を利用して、Goのパッケージ情報に基づいた処理を行うことが可能になります。これは、GoとC/アセンブリの間のより深い連携を可能にします。

gccgcToolchain.ld (リンカ) での cgo 検出と -E フラグ追加

    usesCgo := false
    // ...
    if len(a.p.CgoFiles) > 0 {
        usesCgo = true
    }
    // ...
    if a.p.usesSwig() {
        // ...
        usesCgo = true
    }
    // ...
    if usesCgo && goos == "linux" {
        ldflags = append(ldflags, "-Wl,-E")
    }

このセクションでは、ビルド対象のパッケージが cgo ファイル (a.p.CgoFiles) を含んでいるか、または swig を使用しているか (a.p.usesSwig()) を usesCgo フラグで追跡します。 もし cgo または swig が使用されており、かつオペレーティングシステムがLinuxである場合、リンカに -Wl,-E フラグが追加されます。このフラグは、Linuxの動的リンカに対して、実行可能ファイルがロードされる際に環境変数 LD_PRELOADDT_RPATH/DT_RUNPATH で指定されたパスを検索対象に含めるように指示します。これは、cgo を使用してGoプログラムがCの共有ライブラリに依存する場合に、実行時のシンボル解決を確実に行うために非常に重要です。

gccgoPkgpath および gccgoCleanPkgpath 関数の導入

func gccgoPkgpath(p *Package) string {
    if p.build.IsCommand() && !p.forceLibrary {
        return ""
    }
    return p.ImportPath
}

func gccgoCleanPkgpath(p *Package) string {
    clean := func(r rune) rune {
        switch {
        case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
            '0' <= r && r <= '9':
            return r
        }
        return '_'
    }
    return strings.Map(clean, gccgoPkgpath(p))
}
  • gccgoPkgpath は、与えられたGoパッケージ p のインポートパスを返します。ただし、それがコマンドであり、かつ強制的にライブラリとして扱われていない場合は空文字列を返します。これは、実行可能ファイル自体には特定のパッケージパスが不要であるという gccgo のセマンティクスに合わせたものです。
  • gccgoCleanPkgpath は、gccgoPkgpath から得られた文字列を受け取り、それを「クリーン」にします。具体的には、英数字以外のすべての文字をアンダースコア (_) に置換します。この関数は、パッケージパスをCプリプロセッサマクロ (-D フラグで渡される値) の一部として使用する際に必要です。Cプリプロセッサマクロの名前や値には、特定の文字セットしか使用できないため、このサニタイズ処理が不可欠です。

builder.cgo でのフラグ変更とオブジェクト拡張子設定

    if _, ok := buildToolchain.(gccgcToolchain); ok {
        cgoflags = append(cgoflags, "-gccgo")
        if pkgpath := gccgoPkgpath(p); pkgpath != "" {
            cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
        }
        objExt = "o"
    }

cgo ツールを呼び出す際にも、gccgo ツールチェーンが使用されている場合は、-gccgo フラグが追加されます。また、gccgoPkgpath から得られたパッケージパスが空でなければ、-gccgopkgpath= フラグが追加されます。これは、cgogccgo と連携してGoとCの間のバインディングを生成する際に、正しいパッケージパス情報を利用できるようにするためです。さらに、cgo が生成するオブジェクトファイルの拡張子も .o に設定されます。

これらの変更は、cmd/gogccgo を利用する際のビルドプロセス全体にわたる整合性を高め、より堅牢で標準的なGoプログラムのビルドを可能にしています。

関連リンク

参考にした情報源リンク