[インデックス 15396] ファイルの概要
このコミットは、Go言語のツールチェインにおけるcgo
(C言語との相互運用機能)、cmd/dist
(Goのビルドシステム)、cmd/go
(Goコマンド)がclang
コンパイラと連携する際の複数の問題を修正することを目的としています。特に、clang
の診断メッセージの挙動、libgcc
のパス解決、DWARFデバッグ情報の生成、および特定の警告オプションに関する修正が含まれています。
コミット
commit eec961470fc38a253b46b4004f9acb72741e93d7
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Sat Feb 23 20:24:38 2013 +0800
cmd/cgo, cmd/dist, cmd/go: cgo with clang fixes
1. Workaround the smart clang diagnostics with -Qunused-arguments:
clang: error: argument unused during compilation: '-XXX'
2. if "clang -print-libgcc-file-name" returns non-absolute path, don't
provide that on linker command line.
3. Fix dwarf.PtrType.Size() in cmd/cgo as clang doesn't generate
DW_AT_byte_size for pointer types.
4. Workaround warnings for -Wno-unneeded-internal-declaration with
-Wno-unknown-warning-option.
5. Add -Wno-unused-function.
6. enable race detector test on darwin with clang
(at least Apple clang version 1.7 (tags/Apple/clang-77) works).
Requires CL 7354043.
Update #4829
This should fix most parts of the problem, but one glitch still remains.
DWARF generated by newer clang doesn't differentiate these
two function types:
void *malloc(size_t);
void *malloc(unsigned long int);
so you might need to do this to make make.bash pass:
sed -i -e 's/C.malloc(C.size_t/C.malloc(C.ulong/' pkg/os/user/lookup_unix.go
R=golang-dev, dave, iant, rsc
CC=golang-dev
https://golang.org/cl/7351044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/eec961470fc38a253b46b4004f9acb72741e93d7
元コミット内容
上記の「コミット」セクションに記載されている内容が元コミット内容です。
変更の背景
このコミットの主な背景は、Go言語のツールチェインがclang
コンパイラと連携する際に発生していた複数の互換性問題とバグを解決することです。特に、以下の点が挙げられます。
clang
の厳格な診断メッセージへの対応:clang
は、コンパイル時に使用されない引数に対して-Qunused-arguments
のようなオプションが指定されていても、それを未使用と判断してエラー(または警告)を出すことがあります。これは、Goのビルドシステムがclang
に渡す引数の一部が、特定のコンテキストでは実際に使用されない場合に問題となっていました。libgcc
パスの不正確な解決:clang -print-libgcc-file-name
コマンドが、libgcc
ライブラリの絶対パスではなく相対パスを返す場合があり、これがリンカのコマンドラインで正しく扱われない問題がありました。- DWARFデバッグ情報の欠落:
clang
がポインタ型に対してDW_AT_byte_size
属性を生成しないため、cmd/cgo
がDWARFデバッグ情報を処理する際に、ポインタのサイズを正しく認識できない問題がありました。これはデバッグ情報の正確性に影響を与えます。 - 警告オプションの互換性:
clang
のバージョンによっては、-Wno-unneeded-internal-declaration
のような警告抑制オプションが認識されず、それ自体が「不明な警告オプション」として警告される問題がありました。 - レース検出器のテストの制限:
darwin
(macOS)環境でclang
を使用している場合、Goのレース検出器のテストが実行できないという制限がありました。これは、clang
が特定の.syso
ファイルをリンクできないという誤解に基づいていた可能性があります。
これらの問題は、Goのユーザーがclang
を主要なCコンパイラとして使用する際に、ビルドエラーやデバッグ情報の不正確さ、テストの実行制限といった形で現れていました。コミットメッセージで言及されているUpdate #4829
は、これらの問題の包括的な解決を目指すものでした(ただし、Goの公式リポジトリで直接#4829
というIssueは見つかりませんでした。これは内部的なトラッキング番号か、別のプロジェクトのIssueを参照している可能性があります)。
前提知識の解説
このコミットを理解するためには、以下の技術的な概念について知っておく必要があります。
- Go言語の
cgo
:cgo
はGo言語の機能の一つで、GoプログラムからC言語のコードを呼び出したり、C言語のコードからGoの関数を呼び出したりするためのメカニズムを提供します。GoとCの間のデータ型の変換や、コンパイル・リンクのプロセスを管理します。 clang
: LLVMプロジェクトの一部であるC、C++、Objective-C、Objective-C++コンパイラです。GCC(GNU Compiler Collection)の代替として広く使用されており、高速なコンパイルと優れた診断機能が特徴です。- GCC (GNU Compiler Collection): GNUプロジェクトによって開発されている、様々なプログラミング言語に対応したコンパイラの集合体です。C、C++、Objective-C、Fortran、Ada、Goなどの言語をサポートしています。
- DWARF (Debugging With Attributed Record Formats): プログラムのデバッグ情報を格納するための標準的なフォーマットです。変数名、型情報、ソースコードの行番号、スタックフレーム情報などが含まれ、デバッガが実行中のプログラムの状態を解析するために使用します。
DW_AT_byte_size
: DWARFデバッグ情報における属性の一つで、特定のデータ型がメモリ上で占めるバイトサイズを示します。ポインタ型の場合、通常はシステムのポインタサイズ(例: 32ビットシステムでは4バイト、64ビットシステムでは8バイト)が格納されます。libgcc
: GCCランタイムライブラリのことで、GCCが生成するコードが依存する低レベルのヘルパー関数(例: 整数演算、浮動小数点演算、例外処理など)を提供します。C言語のプログラムがこれらの関数を直接呼び出すことは稀ですが、コンパイラが生成するコードが暗黙的に依存します。-Qunused-arguments
:clang
のコンパイラオプションの一つで、コマンドラインで指定された引数のうち、コンパイル中に使用されなかったものを警告またはエラーとして報告しないようにします。clang
はデフォルトで未使用の引数に対して厳格な診断を行うため、特定のビルドシステムではこのオプションが必要になることがあります。-Wno-unneeded-internal-declaration
:clang
の警告抑制オプションの一つで、内部的に宣言されたが使用されていない関数や変数に関する警告を抑制します。-Wno-unused-function
:clang
の警告抑制オプションの一つで、宣言されたが使用されていない関数に関する警告を抑制します。- レース検出器 (Race Detector): Go言語のツールチェインに組み込まれている機能で、並行処理におけるデータ競合(data race)を検出します。データ競合は、複数のゴルーチンが同時に同じメモリ位置にアクセスし、少なくとも1つのアクセスが書き込みであり、かつアクセスが同期されていない場合に発生するバグです。レース検出器は、実行時にこれらの競合を特定し、デバッグを支援します。
make.bash
: Go言語のソースコードをビルドするためのシェルスクリプトです。Goのツールチェイン全体をコンパイルするために使用されます。
技術的詳細
このコミットは、clang
との連携における複数の問題を、以下の6つの主要な変更点で解決しています。
-
-Qunused-arguments
によるclang
診断の回避:clang
は、コンパイル時に使用されないコマンドライン引数に対してエラーを出すことがあります。Goのビルドプロセスでは、特定の状況下でclang
に渡される引数が未使用と判断されることがありました。- このコミットでは、
src/cmd/cgo/gcc.go
のgccCmd()
関数とsrc/cmd/go/build.go
のgccCmd()
関数において、コンパイラがclang
である場合に-Qunused-arguments
オプションを明示的に追加しています。これにより、clang
が未使用の引数についてエラーや警告を出すのを抑制し、ビルドプロセスをスムーズに進めます。 - また、
src/cmd/dist/build.c
では、clang
の場合にのみ-Qunused-arguments
を追加するように変更されています。以前はclang
の場合に-g
、それ以外の場合に-ggdb
を追加していましたが、clang
の厳格な引数チェックを回避するためにこの変更が行われました。
-
clang -print-libgcc-file-name
の非絶対パス問題の対処:clang -print-libgcc-file-name
コマンドは、libgcc
ライブラリのパスを返しますが、これが絶対パスではない場合がありました。Goのリンカは絶対パスを期待するため、この問題はリンクエラーを引き起こす可能性がありました。src/cmd/go/build.go
のlibgcc()
関数において、clang
を使用しており、かつlibgcc
のパスが絶対パスでない場合に、そのパスをリンカに提供しないように修正されました。これにより、不正確なパスが原因で発生するリンクエラーを回避します。
-
cmd/cgo
におけるdwarf.PtrType.Size()
の修正:clang
は、ポインタ型に対してDWARFデバッグ情報の一部であるDW_AT_byte_size
属性を生成しないことがあります。これにより、cmd/cgo
がポインタのサイズを正しく取得できず、デバッグ情報が不正確になる問題がありました。src/cmd/cgo/gcc.go
のtypeConv
構造体のType()
メソッドにおいて、DWARFの型がポインタ型(dwarf.PtrType
)であり、かつByteSize
が-1
(未設定)の場合に、c.ptrSize
(システムのポインタサイズ)を明示的に設定するように修正されました。これにより、clang
がDW_AT_byte_size
を生成しない場合でも、ポインタのサイズが正しく設定され、デバッグ情報の正確性が保たれます。
-
-Wno-unneeded-internal-declaration
警告の回避:- 古いバージョンのApple
clang
(バージョン1.7など)では、-Wno-unneeded-internal-declaration
オプションが認識されず、「不明な警告オプション」として警告が出ることがありました。 src/cmd/cgo/gcc.go
のgccCmd()
関数において、コンパイラがclang
である場合に、-Wno-unknown-warning-option
オプションを-Wno-unneeded-internal-declaration
の前に追加するように変更されました。これにより、clang
が不明な警告オプションについて警告を出すのを抑制し、ビルド時のノイズを減らします。
- 古いバージョンのApple
-
-Wno-unused-function
の追加:cgo
が生成するCコードには、Goから呼び出されないがC側で定義されている関数が含まれることがあり、これがclang
によって「未使用の関数」として警告されることがありました。src/cmd/cgo/gcc.go
のgccCmd()
関数において、clang
を使用している場合に-Wno-unused-function
オプションを追加しました。これにより、これらの警告が抑制され、ビルドログがクリーンになります。
-
darwin
におけるレース検出器テストの有効化:- 以前は、
darwin
環境でclang
を使用している場合、レース検出器のテストが実行されないように制限されていました。これは、clang
が特定の.syso
ファイルをリンクできないという誤解に基づいていた可能性があります。 src/run.bash
スクリプトにおいて、レース検出器テストの実行条件から*gcc*
のチェックを削除し、darwin-darwin-amd64-1
(darwin
上のamd64
でcgo
が有効な場合)でもテストが実行されるように変更されました。これにより、darwin
環境でもレース検出器のテストが実行可能になり、より広範な環境での品質保証が可能になります。コミットメッセージには「Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn) works」とあり、特定のバージョンのclang
では問題なく動作することが確認されたため、この変更が可能になりました。
- 以前は、
このコミットは、Goツールチェインとclang
の間の互換性を大幅に向上させ、特にmacOSユーザーにとってのビルド体験を改善するものです。ただし、コミットメッセージの最後に記載されているように、新しいclang
が生成するDWARF情報においてvoid *malloc(size_t)
とvoid *malloc(unsigned long int)
のような関数型を区別できないという残存する問題も指摘されています。これは、pkg/os/user/lookup_unix.go
のC.malloc(C.size_t
をC.malloc(C.ulong
に置換することで回避できるとされています。
コアとなるコードの変更箇所
このコミットでは、以下の4つのファイルが変更されています。
src/cmd/cgo/gcc.go
:cgo
がCコンパイラ(特にclang
)を呼び出す際のオプション設定と、DWARFデバッグ情報の処理に関する修正。clang
に渡すオプションに-Wno-unknown-warning-option
,-Wno-unused-function
,-Qunused-arguments
を追加。- ポインタ型のDWARF情報に
DW_AT_byte_size
が欠落している場合の修正ロジックを追加。
src/cmd/dist/build.c
: Goのビルドシステムの一部で、Cコンパイラに渡すデフォルトの引数に関する修正。proto_gccargs
に-ggdb
を追加。clang
の場合にのみ-Qunused-arguments
を追加するロジックに変更。以前の-g
または-ggdb
の選択ロジックを削除。
src/cmd/go/build.go
:go
コマンドのビルドロジック、特にlibgcc
のパス解決とgccCmd
の引数生成に関する修正。libgcc()
関数で、clang
が非絶対パスを返す場合にlibgcc
パスを使用しないように修正。gccCmd()
関数で、clang
の場合に-Qunused-arguments
を常に含めるように修正。cgoLibGccFile
とcgoLibGccErr
の扱いを改善し、エラーハンドリングをより堅牢に。staticLibs
の構築ロジックを修正し、cgoLibGccFile
が空でない場合にのみ追加するように変更。
src/run.bash
: Goのテストスクリプトで、レース検出器テストの実行条件に関する修正。- レース検出器テストの実行条件から
*gcc*
のチェックを削除し、darwin
上のclang
でもテストが実行されるように変更。
- レース検出器テストの実行条件から
コアとなるコードの解説
src/cmd/cgo/gcc.go
@@ -783,7 +783,13 @@ func (p *Package) gccCmd() []string {
if strings.Contains(p.gccName(), "clang") {
c = append(c,
"-ferror-limit=0",
+ // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
+ // doesn't have -Wno-unneeded-internal-declaration, so we need yet another
+ // flag to disable the warning. Yes, really good diagnostics, clang.
+ "-Wno-unknown-warning-option",
"-Wno-unneeded-internal-declaration",
+ "-Wno-unused-function",
+ "-Qunused-arguments",
)
}
@@ -1049,6 +1055,12 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
return t
}
+ // clang won't generate DW_AT_byte_size for pointer types,
+ // so we have to fix it here.
+ if dt, ok := base(dtype).(*dwarf.PtrType); ok && dt.ByteSize == -1 {
+ dt.ByteSize = c.ptrSize
+ }
+
t := new(Type)
t.Size = dtype.Size()
t.Align = -1
gccCmd()
関数:clang
を使用している場合、コンパイラオプションに-Wno-unknown-warning-option
(不明な警告オプションに関する警告を抑制)、-Wno-unused-function
(未使用関数に関する警告を抑制)、-Qunused-arguments
(未使用のコマンドライン引数に関する警告を抑制)が追加されています。これは、clang
の厳格な診断機能がGoのビルドプロセスと競合するのを防ぐためです。Type()
メソッド: DWARFデバッグ情報を処理する際に、ポインタ型(dwarf.PtrType
)のByteSize
が-1
(未設定)である場合、c.ptrSize
(システムのポインタサイズ)を代入しています。これは、clang
がポインタ型に対してDW_AT_byte_size
属性を生成しない問題への対処です。
src/cmd/dist/build.c
@@ -409,6 +409,7 @@ static char *proto_gccargs[] = {
"-Wno-comment",
"-Werror",
"-fno-common",
+ "-ggdb",
"-pipe",
"-O2",
};
@@ -604,10 +605,10 @@ install(char *dir)
splitfields(&gccargs, bstr(&b));
for(i=0; i<nelem(proto_gccargs); i++)
vadd(&gccargs, proto_gccargs[i]);
-\t\tif(clang)
-\t\t\tvadd(&gccargs, "-g");
-\t\telse
-\t\t\tvadd(&gccargs, "-ggdb");
+\t\tif(clang) {
+\t\t\t// clang is too smart about unused command-line arguments
+\t\t\tvadd(&gccargs, "-Qunused-arguments");
+\t\t}
}
islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
proto_gccargs
: デフォルトのGCC引数リストに-ggdb
が追加されました。これはデバッグ情報の生成をより詳細にするためのオプションです。install()
関数:clang
を使用している場合に、以前は-g
または-ggdb
を選択していましたが、この変更によりclang
の場合にのみ-Qunused-arguments
を明示的に追加するように変更されました。これは、clang
が未使用の引数に対して厳格な診断を行うことを考慮したものです。
src/cmd/go/build.go
@@ -1609,6 +1609,8 @@ func gccgoCleanPkgpath(p *Package) string {
func (b *builder) libgcc(p *Package) (string, error) {
var buf bytes.Buffer
+ gccCmd := b.gccCmd(p.Dir)
+
prev := b.print
if buildN {
// In -n mode we temporarily swap out the builder's
@@ -1619,7 +1621,7 @@ func (b *builder) libgcc(p *Package) (string, error) {
return fmt.Fprint(&buf, a...)
}
}
- f, err := b.runOut(p.Dir, p.ImportPath, b.gccCmd(p.Dir), "-print-libgcc-file-name")
+ f, err := b.runOut(p.Dir, p.ImportPath, gccCmd, "-print-libgcc-file-name")
if err != nil {
return "", fmt.Errorf("gcc -print-libgcc-file-name: %v (%s)", err, f)
}
@@ -1629,6 +1631,13 @@ func (b *builder) libgcc(p *Package) (string, error) {
b.print(s)
return "$LIBGCC", nil
}
+
+ // clang might not be able to find libgcc, and in that case,
+ // it will simply return "libgcc.a", which is of no use to us.
+ if strings.Contains(gccCmd[0], "clang") && !filepath.IsAbs(string(f)) {
+ return "", nil
+ }
+
return strings.Trim(string(f), "\r\n"), nil
}
@@ -1662,19 +1671,21 @@ func (b *builder) gccCmd(objdir string) []string {
}\n\ta = append(a, b.gccArchArgs()...)\n \t// gcc-4.5 and beyond require explicit \"-pthread\" flag\n-\t// for multithreading with pthread library, but clang whines\n-\t// about unused arguments if we pass it.\n+\t// for multithreading with pthread library.\n \tif buildContext.CgoEnabled {\n \t\tswitch goos {\n \t\tcase \"windows\":\n \t\t\ta = append(a, \"-mthreads\")\n \t\tdefault:\n-\t\t\tif !strings.Contains(a[0], \"clang\") {\n-\t\t\t\ta = append(a, \"-pthread\")\n-\t\t\t}\n+\t\t\ta = append(a, \"-pthread\")\n \t\t}\n \t}\n \n+\t// clang is too smart about command-line arguments\n+\tif strings.Contains(a[0], \"clang\") {\n+\t\ta = append(a, \"-Qunused-arguments\")\n+\t}\n+\n \t// On OS X, some of the compilers behave as if -fno-common\n \t// is always set, and the Mach-O linker in 6l/8l assumes this.\n \t// See http://golang.org/issue/3253.\n@@ -1706,6 +1717,7 @@ var cgoRe = regexp.MustCompile(`[/\\\\:]`)\n \n var (\n \tcgoLibGccFile string\n+\tcgoLibGccErr error\n \tcgoLibGccFileOnce sync.Once\n )\n \n@@ -1800,21 +1812,19 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles []string) (outGo,\n \t}\n \n \tcgoLibGccFileOnce.Do(func() {\n-\t\tcgoLibGccFile, err = b.libgcc(p)\n+\t\tcgoLibGccFile, cgoLibGccErr = b.libgcc(p)\n \t})\n-\tif cgoLibGccFile == \"\" {\n-\t\tif err == nil {\n-\t\t\terr = errors.New(\"failed to get libgcc filename\")\n-\t\t}\n+\tif cgoLibGccFile == "" && cgoLibGccErr != nil {\n \t\treturn nil, nil, err\n \t}\n \n \tvar staticLibs []string\n \tif goos == \"windows\" {\n \t\t// libmingw32 and libmingwex might also use libgcc, so libgcc must come last\n-\t\tstaticLibs = []string{\"-lmingwex\", \"-lmingw32\", cgoLibGccFile}\n-\t} else {\n-\t\tstaticLibs = []string{cgoLibGccFile}\n+\t\tstaticLibs = []string{\"-lmingwex\", \"-lmingw32\"}\n+\t}\n+\tif cgoLibGccFile != "" {\n+\t\tstaticLibs = append(staticLibs, cgoLibGccFile)\n \t}\n \n \tfor _, cfile := range cfiles {\
libgcc()
関数:clang
がlibgcc
のパスとして非絶対パス(例: "libgcc.a")を返す場合、そのパスを無視するように変更されました。これは、clang
がlibgcc
を見つけられない場合にこのような挙動を示すため、不正確なパスをリンカに渡すのを防ぐためです。gccCmd()
関数:cgo
が有効な場合、-pthread
オプションが常にgccCmd
に追加されるようになりました。以前はclang
でない場合にのみ追加されていましたが、clang
が未使用引数について警告を出す問題が-Qunused-arguments
で解決されたため、常に含めることができるようになりました。また、clang
を使用している場合に-Qunused-arguments
が常にgccCmd
に追加されるようになりました。cgo()
関数:cgoLibGccFile
とcgoLibGccErr
という新しい変数が導入され、libgcc
のファイル名取得とそのエラーをより適切に管理するようになりました。libgcc
のファイル名が空で、かつエラーが発生している場合にのみエラーを返すようにロジックが変更されました。また、staticLibs
の構築ロジックが修正され、cgoLibGccFile
が空でない場合にのみstaticLibs
に追加されるようになりました。これにより、libgcc
が見つからない場合でも、他の静的ライブラリのリンクが妨げられないようになります。
src/run.bash
@@ -48,10 +48,8 @@ go test sync -short -timeout=120s -cpu=10
# Race detector only supported on Linux and OS X,
# and only on amd64, and only when cgo is enabled.
-# Also, clang can't seem to link the .syso files, so only
-# run if we're using gcc.
-case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED-${CC:-gcc}" in
-linux-linux-amd64-1-*gcc* | darwin-darwin-amd64-1-*gcc*)
+case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in
+linux-linux-amd64-1 | darwin-darwin-amd64-1)
echo
echo '# Testing race detector.'
go test -race -i flag
- レース検出器テストの実行条件が緩和されました。以前は
CC
環境変数が*gcc*
を含む場合にのみ実行されていましたが、この変更によりlinux-linux-amd64-1
またはdarwin-darwin-amd64-1
(それぞれLinuxまたはmacOS上のamd64アーキテクチャでcgoが有効な場合)であれば、コンパイラがclang
であってもレース検出器テストが実行されるようになりました。これは、clang
が.syso
ファイルをリンクできないという以前の懸念が解消されたためです。
関連リンク
- Go言語の公式ウェブサイト: https://golang.org/
- Go言語のIssueトラッカー: https://github.com/golang/go/issues
- このコミットが参照しているGoの変更リスト (CL): https://golang.org/cl/7351044
参考にした情報源リンク
- DWARF Debugging Information Format: https://dwarfstd.org/
- Clang Compiler User's Manual: https://clang.llvm.org/docs/UsersManual.html
- GCC documentation: https://gcc.gnu.org/onlinedocs/
- Go Race Detector: https://go.dev/doc/articles/race_detector
cgo
に関するGoのドキュメント: https://go.dev/blog/c-go-is-not-cgo (一般的な情報)clang
の-Qunused-arguments
オプションに関する情報 (例: Stack Overflowなど): https://stackoverflow.com/questions/tagged/clang+-Qunused-arguments (一般的な情報)libgcc
に関する情報 (例: GCCのドキュメントなど): https://gcc.gnu.org/onlinedocs/libgcc/ (一般的な情報)- Go Issue #4829 (コミットメッセージで参照されているが、Goの公式リポジトリでは直接見つからなかったため、一般的なIssueトラッキングの概念として参照): https://github.com/golang/go/issues/4829 (このIssueはGoの公式リポジトリには存在しないようです。コミットメッセージの記述は、内部的なトラッキング番号か、別のプロジェクトのIssueを参照している可能性があります。)