[インデックス 18499] ファイルの概要
このコミットは、Go言語のツールチェイン、特にcmd/go
とgo/build
パッケージに、Objective-Cのソースファイル(.m
ファイル)のサポートを追加するものです。これにより、GoプログラムからObjective-Cコードを呼び出す際に、よりシームレスな統合が可能になります。
コミット
commit 7861cd6082993becfedeaab75567eaba0c9a03f8
Author: Carlos Castillo <cookieo9@gmail.com>
Date: Thu Feb 13 10:11:44 2014 -0800
cmd/go, go/build: support .m files
go/build is changed to list the .m files in a package, and match them for build constraints, adding them to a new field: Package.MFiles.
The go tool is changed to support building .m files and linking in the results during CGO and SWIG builds. This means packages that create a C interface to calls Objective-C code from go are now go-gettable without producing and distributing .syso files. This change is analogous to the one in Go 1.2 made to support C++ built code.
This change doesn't support .mm files (Objective C++).
Also added support for these MFiles to go list's -json mode.
Fixes #6536.
LGTM=iant
R=golang-codereviews, iant
CC=golang-codereviews
https://golang.org/cl/60590044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7861cd6082993becfedeaab75567eaba0c9a03f8
元コミット内容
cmd/go, go/build: support .m files
go/build
パッケージが変更され、パッケージ内の.m
ファイルをリストアップし、ビルド制約に合致するものを新しいフィールドPackage.MFiles
に追加するようになりました。
go
ツールが変更され、CGOおよびSWIGビルド中に.m
ファイルをビルドし、その結果をリンクするようになりました。これにより、GoからObjective-Cコードを呼び出すCインターフェースを作成するパッケージが、.syso
ファイルを生成・配布することなくgo-gettable
になります。この変更は、Go 1.2でC++ビルドコードをサポートするために行われた変更と類似しています。
この変更は.mm
ファイル(Objective-C++)をサポートしていません。
また、go list
の-json
モードにこれらのMFiles
のサポートが追加されました。
Fixes #6536
.
変更の背景
Go言語は、C言語との相互運用性を提供するためにCGOというメカニズムを持っています。これにより、GoコードからC関数を呼び出したり、CコードからGo関数を呼び出したりすることが可能です。しかし、Objective-CコードをGoプロジェクトに統合する場合、これまでは.syso
ファイル(事前にコンパイルされたオブジェクトファイル)を手動で管理する必要がありました。これは、特にクロスプラットフォーム開発や依存関係の管理において、開発者に負担をかけるものでした。
このコミットの主な目的は、GoツールチェインがObjective-Cソースファイル(.m
)を直接認識し、CGOおよびSWIGのビルドプロセスに組み込むことで、この統合プロセスを簡素化することです。これにより、GoパッケージがObjective-Cコードを含む場合でも、go get
コマンドで簡単に取得・ビルドできるようになり、開発体験が向上します。コミットメッセージにあるFixes #6536
は、この機能追加の必要性を示唆するIssueへの対応です。
Go 1.2でC++ファイルのサポートが追加されたのと同様に、Objective-Cも同様の統合パスを持つことで、Goエコシステムにおける外部言語との連携がより一貫性のあるものになります。
前提知識の解説
- Objective-C (.mファイル): AppleのmacOSおよびiOS開発で主に用いられるオブジェクト指向プログラミング言語です。C言語のスーパーセットであり、Smalltalkスタイルのメッセージング機能が追加されています。
.m
拡張子はObjective-Cのソースファイルを示します。 - CGO: Go言語がC言語のコードと相互運用するためのメカニズムです。Goプログラム内でCの関数を呼び出したり、Cのデータ構造を使用したりすることを可能にします。CGOを使用すると、Goのビルドプロセス中にCコンパイラ(通常はGCCやClang)が呼び出され、Cコードがコンパイル・リンクされます。
- SWIG (Simplified Wrapper and Interface Generator): C/C++/Objective-Cなどの言語で書かれたライブラリを、Python, Java, Go, Rubyなどの様々なスクリプト言語から呼び出すためのインターフェースコードを自動生成するツールです。SWIGを使用することで、手動でラッパーコードを書く手間を省き、異なる言語間の連携を容易にします。
go get
: Go言語のパッケージ管理コマンドの一つで、リモートリポジトリからGoパッケージをダウンロードし、ビルドしてインストールするために使用されます。go get
が機能するためには、依存するすべてのソースファイルがGoツールチェインによって適切に処理できる必要があります。.syso
ファイル: システム固有のオブジェクトファイル(System Object File)の略で、Goのビルドプロセスで外部のC/C++コードなどを事前にコンパイルして生成されるバイナリファイルです。CGOやSWIGを使用する際に、Goツールチェインが直接コンパイルできない外部コードをリンクするために使用されることがあります。このコミットの目的の一つは、Objective-Cコードのために.syso
ファイルを不要にすることです。- ビルド制約 (Build Constraints): Goのソースファイルに記述される特別なコメント行(例:
// +build darwin,amd64
)で、特定のOS、アーキテクチャ、またはカスタムタグが有効な場合にのみそのファイルをビルドに含めるようにGoツールチェインに指示します。これにより、プラットフォーム固有のコードを管理できます。
技術的詳細
このコミットは、GoツールチェインがObjective-Cソースファイル(.m
)を認識し、ビルドプロセスに統合するための複数の変更を含んでいます。
-
go/build
パッケージの拡張:go/build.Package
構造体に新しいフィールドMFiles
が追加されました。これは、パッケージ内のObjective-Cソースファイル(.m
)のリストを保持します。go/build
パッケージ内のファイルスキャンロジック(readDir
関数など)が更新され、.m
拡張子を持つファイルをMFiles
として識別し、適切に分類するようになりました。これにより、GoツールチェインはObjective-CファイルをGoパッケージの一部として認識できるようになります。- ビルド制約の評価ロジックも更新され、
.m
ファイルに対してもビルド制約が適用されるようになりました。
-
cmd/go
ツールの変更:- ビルドプロセスの統合:
src/cmd/go/build.go
内のbuilder
構造体のcgo
およびswig
メソッドが変更され、Objective-Cファイル(mfiles
)を引数として受け取るようになりました。これにより、CGOおよびSWIGのコンパイル・リンクプロセス中に.m
ファイルが適切に処理されます。 - コンパイルとリンク:
cgo
関数内で、Objective-Cファイルが存在する場合、-lobjc
リンカフラグが自動的に追加されるようになりました。これは、Objective-Cランタイムライブラリへのリンクを保証するために必要です。.m
ファイルは、b.gcc
関数(GoツールチェインがC/C++/アセンブリファイルをコンパイルするために使用する内部関数)を通じてコンパイルされ、生成されたオブジェクトファイルがリンクプロセスに含まれるようになります。
- エラーハンドリング: CGOまたはSWIGを使用せずにObjective-Cファイルを含むパッケージをビルドしようとした場合、Goツールはエラーを返すようになりました。これは、Objective-CコードのコンパイルとリンクにはCGOまたはSWIGのサポートが不可欠であるためです。
go list -json
の更新:src/cmd/go/list.go
およびsrc/cmd/go/pkg.go
が更新され、go list -json
コマンドの出力にMFiles
フィールドが含まれるようになりました。これにより、プログラムからパッケージのObjective-Cファイル情報を取得できるようになります。- ドキュメントの更新:
doc/go1.3.txt
とsrc/cmd/go/doc.go
が更新され、Go 1.3のリリースノートとgo build
コマンドのドキュメントに.m
ファイルのサポートが明記されました。
- ビルドプロセスの統合:
この変更は、Go 1.2でC++ファイル(.cc
, .cpp
, .cxx
)のサポートが追加されたのと同様のアプローチを取っています。これにより、GoはC/C++だけでなく、Objective-Cとの相互運用性も向上させ、より幅広いシステムプログラミングのユースケースに対応できるようになります。ただし、Objective-C++(.mm
ファイル)はサポートされていません。これは、Objective-C++のコンパイルとリンクがObjective-Cよりも複雑であり、Goツールチェインにさらに多くの変更が必要となるためと考えられます。
コアとなるコードの変更箇所
このコミットにおける主要なコード変更は以下のファイルに集中しています。
-
src/pkg/go/build/build.go
:Package
構造体にMFiles []string
フィールドが追加されました。readDir
関数内で、ファイル拡張子が.m
の場合にp.MFiles
に追加するロジックが追加されました。matchFile
関数で、.m
拡張子がビルド対象ファイルとして認識されるようになりました。
-
src/cmd/go/build.go
:builder.build
関数内で、CGOまたはSWIGを使用しないObjective-Cファイルが存在する場合のエラーチェックが追加されました。builder.cgo
およびbuilder.swig
関数のシグネチャが変更され、mfiles []string
引数が追加されました。builder.cgo
関数内で、mfiles
が存在する場合に-lobjc
リンカフラグがcgoLDFLAGS
に追加されるようになりました。builder.cgo
およびbuilder.swig
関数内で、mfiles
内の各.m
ファイルをb.gcc
でコンパイルし、生成されたオブジェクトファイルをリンク対象に追加するロジックが追加されました。gcToolchain.gc
関数で、textFiles
の計算にlen(p.MFiles)
が追加されました。gccgoToolchain.ld
関数で、objc
フラグが追加され、len(a.p.MFiles) > 0
の場合にobjc
がtrue
になり、-lobjc
リンカフラグが追加されるようになりました。
-
src/cmd/go/pkg.go
:Package
構造体にMFiles []string
フィールドが追加されました。copyBuild
,load
,isStale
などの関数で、MFiles
フィールドのコピーや参照が適切に行われるように変更されました。
-
src/cmd/go/list.go
:go list -json
の出力構造にMFiles
フィールドが追加されました。
-
src/cmd/go/doc.go
:go build
コマンドのドキュメントが更新され、.m
ファイルがCコンパイラに渡されることが明記されました。
-
doc/go1.3.txt
:- Go 1.3のリリースノートに
.m
ファイルサポートに関する項目が追加されました。
- Go 1.3のリリースノートに
コアとなるコードの解説
src/pkg/go/build/build.go
type Package struct {
// ... 既存のフィールド ...
MFiles []string // .m (Objective-C) source files
// ... 既存のフィールド ...
}
// readDir function (抜粋)
// ...
case ".m":
p.MFiles = append(p.MFiles, name)
continue
// ...
// matchFile function (抜粋)
// ...
switch ext {
case ".go", ".c", ".cc", ".cxx", ".cpp", ".m", ".s", ".h", ".hh", ".hpp", ".hxx", ".S", ".swig", ".swigcxx":
// tentatively okay - read to make sure
// ...
go/build
パッケージは、Goのビルドシステムの中核をなすもので、ソースファイルの発見と分類を担当します。この変更では、Package
構造体にMFiles
という新しいスライスが追加され、Objective-Cソースファイルの名前を保持するようになりました。readDir
関数はディレクトリ内のファイルをスキャンし、.m
拡張子を持つファイルをMFiles
リストに自動的に追加します。matchFile
関数は、ビルドに含めるべきファイルの種類を決定する際に、.m
ファイルを「暫定的にOK」なファイルとして認識するように更新されました。これにより、GoツールチェインはObjective-CファイルをGoパッケージの一部として正式に扱うことができるようになります。
src/cmd/go/build.go
// func (b *builder) build(a *action) (err error) (抜粋)
// ...
// Same as above for Objective-C files
if len(a.p.MFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
return fmt.Errorf("can't build package %s because it contains Objective-C files (%s) but it's not using cgo nor SWIG",
a.p.ImportPath, strings.Join(a.p.MFiles, ","))
}
// ...
// func (b *builder) cgo(p *Package, cgoExe, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) (抜粋)
// ...
// If we are compiling Objective-C code, then we need to link against libobjc
if len(mfiles) > 0 {
cgoLDFLAGS = append(cgoLDFLAGS, "-lobjc")
}
// ...
for _, file := range mfiles {
// Append .o to the file, just in case the pkg has file.c and file.m
ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
if err := b.gcc(p, ofile, cflags, file); err != nil {
return nil, nil, err
}
linkobj = append(linkobj, ofile)
outObj = append(outObj, ofile)
}
// ...
// func (b *builder) swig(p *Package, obj string, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) (抜粋)
// ...
for _, file := range mfiles {
// Append .o to the file, just in case the pkg has file.c and file.cpp
ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o"
if err := b.gcc(p, ofile, nil, file); err != nil {
return nil, nil, err
}
extraObj = append(extraObj, ofile)
}
// ...
cmd/go
はGoのビルドコマンドの実装です。build
関数では、Objective-Cファイルが存在するにもかかわらずCGOもSWIGも使用されていない場合にエラーを返すチェックが追加されました。これは、Objective-Cコードをコンパイル・リンクするにはこれらの外部ツールが必要であるためです。
最も重要な変更はcgo
関数とswig
関数にあります。これらの関数は、CGOおよびSWIGのビルドプロセスを管理します。
cgo
関数では、mfiles
(Objective-Cファイルのリスト)が空でない場合、リンカフラグに-lobjc
が追加されます。これは、Objective-Cランタイムライブラリをリンクするために不可欠です。cgo
とswig
の両関数で、mfiles
リスト内の各Objective-Cファイルがb.gcc
関数(GoツールチェインがC/C++/アセンブリファイルをコンパイルするために使用する内部関数)によってコンパイルされます。コンパイルされたオブジェクトファイル(.o
)は、最終的なバイナリにリンクされるlinkobj
またはextraObj
リストに追加されます。
これらの変更により、GoツールチェインはObjective-CファイルをGoのビルドプロセスにシームレスに統合し、CGOまたはSWIGを介してGoコードとObjective-Cコード間の相互運用性を実現します。
関連リンク
- Go言語公式ドキュメント: https://go.dev/doc/
- CGOに関する公式ドキュメント: https://go.dev/blog/cgo
- SWIG公式ウェブサイト: http://www.swig.org/
- Go Issue #6536: cmd/go: support .m files (Objective-C) - https://github.com/golang/go/issues/6536
参考にした情報源リンク
- Go言語のソースコード (特に
src/cmd/go
とsrc/pkg/go/build
ディレクトリ) - Go言語のコミット履歴
- Objective-Cの基本概念
- CGOの利用方法に関する一般的な情報
- SWIGの利用方法に関する一般的な情報