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

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

このコミットは、Go言語のビルドシステムにおけるgo/buildパッケージの変更に関するものです。具体的には、#cgoディレクティブ内で使用されるフラグにおいて、コロン(:)文字が許可されるように修正されました。これにより、Windows環境でcgoを使用する際に、C:/fooのようなドライブレターを含むパスを-I(インクルードパス)フラグとして正しく指定できるようになりました。

コミット

commit fb036824df95f5d127064b3897e3e74fb9691b29
Author: Russ Cox <rsc@golang.org>
Date:   Thu Jan 12 11:05:54 2012 -0800

    go/build: allow colon in #cgo flags
    
    This makes it possible to say -I c:/foo on Windows.
    
    Fixes #2683 comment #3.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/5540043

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

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

元コミット内容

go/buildパッケージにおいて、#cgoディレクティブのフラグにコロンを許可する変更。これにより、Windows環境で-I c:/fooのようなパス指定が可能になる。Issue 2683のコメント3を修正。

変更の背景

Go言語のcgo機能は、GoプログラムからC言語のコードを呼び出すための重要なメカニズムです。#cgoディレクティブは、Cコンパイラやリンカに渡す追加のフラグ(例: インクルードパス、ライブラリパス)を指定するために使用されます。

このコミットが行われる前は、go/buildパッケージ内のsafeBytesという変数が、#cgoフラグとして許可される文字のセットを定義していました。このセットにはコロン(:)が含まれていませんでした。

Windowsオペレーティングシステムでは、ファイルパスにドライブレター(例: C:D:)が含まれることが一般的です。例えば、特定のヘッダーファイルがC:\Program Files\MyLib\includeにある場合、Cコンパイラには-I C:\Program Files\MyLib\includeのようなフラグを渡す必要があります。しかし、safeBytesにコロンが含まれていなかったため、#cgo CFLAGS: -I C:/path/to/includeのように指定しようとすると、go/buildパッケージがこれを不正な文字として認識し、ビルドエラーが発生していました。

この制限は、特にWindows環境でcgoを利用して外部Cライブラリと連携する開発者にとって大きな障壁となっていました。このコミットは、この問題を解決し、Windows環境でのcgoの使い勝手を向上させることを目的としています。

前提知識の解説

  • go/buildパッケージ: Go言語の標準ライブラリの一部で、Goのソースコードを解析し、パッケージの依存関係を解決し、ビルドに必要な情報を収集する役割を担います。go buildコマンドの基盤となるパッケージの一つです。
  • cgo: Go言語の機能の一つで、GoプログラムからC言語の関数を呼び出したり、C言語のコードをGoプログラムに組み込んだりするためのメカニズムです。C言語のライブラリを利用する際に不可欠です。
  • #cgoディレクティブ: cgoを使用するGoソースファイル内に記述される特殊なコメント行です。Cコンパイラやリンカに渡すフラグ(例: CFLAGSLDFLAGS)や、GoとCの間で共有される型定義などを指定します。
    • 例: #cgo CFLAGS: -I/usr/local/include は、Cコンパイラに/usr/local/includeをインクルードパスとして追加するよう指示します。
  • -I フラグ (Cコンパイラ): C/C++コンパイラ(GCC, Clangなど)において、インクルードファイルの検索パスを追加するために使用されるオプションです。例えば、-I/path/to/headersと指定すると、コンパイラは/path/to/headersディレクトリ内もヘッダーファイルを検索するようになります。
  • Windowsのファイルパス形式: Windowsでは、ファイルパスは通常、ドライブレター(例: C:)から始まり、ディレクトリの区切り文字としてバックスラッシュ(\)またはスラッシュ(/)が使用されます。例えば、C:\Users\User\DocumentsC:/Users/User/Documentsのように記述されます。

技術的詳細

go/buildパッケージは、Goのソースファイルを解析する際に、#cgoディレクティブを特別に処理します。この処理の一環として、#cgoフラグとして指定された文字列が、特定の安全な文字セットのみで構成されているかを検証するロジックが存在しました。これは、不正な文字がコマンドライン引数としてシェルに渡されることによるセキュリティリスクや、予期せぬ動作を防ぐための措置と考えられます。

具体的には、src/pkg/go/build/dir.goファイル内にsafeBytesというバイトスライスが定義されており、これが許可される文字のホワイトリストとして機能していました。そして、safeNameという関数が、与えられた文字列がこのsafeBytesに含まれる文字のみで構成されているかをチェックしていました。

変更前は、safeBytesには以下の文字が含まれていました。 +-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz

このリストにはコロン(:)が含まれていなかったため、Windowsのドライブレターを含むパス(例: C:/path/to/include)が#cgo CFLAGS: -I C:/path/to/includeのように指定されると、safeName関数がコロンを不正な文字と判断し、ビルドプロセスがエラーとなっていました。

このコミットでは、safeBytesにコロン文字を追加することで、この問題を解決しています。これにより、safeName関数がコロンを含む文字列も「安全」と判断するようになり、Windowsパスの指定が可能になりました。

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

変更はsrc/pkg/go/build/dir.goファイルの一箇所のみです。

--- a/src/pkg/go/build/dir.go
+++ b/src/pkg/go/build/dir.go
@@ -476,7 +476,7 @@ func (ctxt *Context) saveCgo(filename string, di *DirInfo, cg *ast.CommentGroup)\
 	return nil
 }
 
-var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
+var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:")
 
 func safeName(s string) bool {
 	if s == "" {

コアとなるコードの解説

変更された行は、safeBytesというグローバル変数(バイトスライス)の定義です。

  • 変更前: var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz") このバイトスライスは、#cgoディレクティブのフラグとして許可される文字の集合を定義しています。この文字列には、英数字、一部の記号(+, -, ., ,, /, =)、アンダースコアが含まれていますが、コロン(:)は含まれていませんでした。

  • 変更後: var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz:") 変更点として、文字列の末尾にコロン(:)が追加されました。これにより、safeBytesがコロンを許可する文字として認識するようになります。

このsafeBytes変数は、safeNameという関数によって利用されます。safeName関数は、#cgoフラグとして渡された文字列の各バイトがsafeBytesに含まれているかをチェックします。もし含まれていない文字があれば、その文字列は「安全でない」と判断され、エラーとなります。

コロンがsafeBytesに追加されたことで、safeName関数はC:/path/to/includeのような文字列に含まれるコロンを正当な文字として扱い、#cgoフラグの検証が成功するようになります。これにより、Windows環境でのcgoの利用がスムーズになりました。

関連リンク

  • Go Issue 2683: https://github.com/golang/go/issues/2683 このコミットが修正した具体的な問題に関する議論が記載されています。特にコメント3がこの変更の直接的なトリガーとなっています。
  • Go Code Review 5540043: https://golang.org/cl/5540043 この変更がGoのコードレビューシステム(Gerrit)でどのようにレビューされたかを確認できます。

参考にした情報源リンク

  • Go言語公式ドキュメント - cgo: https://pkg.go.dev/cmd/cgo cgoの基本的な使い方や#cgoディレクティブに関する詳細な情報が記載されています。
  • Go言語公式ドキュメント - go/buildパッケージ: https://pkg.go.dev/go/build go/buildパッケージのAPIドキュメントです。
  • Windowsのファイルパス: 一般的なWindowsのファイルパスの構造に関する情報源(例: Microsoft Learnのドキュメントなど)。
  • Cコンパイラの-Iオプション: GCCやClangなどのCコンパイラのドキュメントで、-Iオプションの使われ方に関する情報。