[インデックス 1528] ファイルの概要
このコミットは、Go言語のリンカである6lの挙動に関する重要な変更を導入しています。具体的には、アーカイブ(ライブラリ)からinit関数だけのためにオブジェクトをリンクしないように修正することで、Goライブラリの振る舞いをC言語のライブラリにより近づけることを目的としています。これにより、リンカの効率性が向上し、不要なコードのリンクが避けられます。
コミット
commit a3c4faf83f1849198b5431aa050793124a2fc91d
Author: Russ Cox <rsc@golang.org>
Date: Tue Jan 20 15:36:43 2009 -0800
6l: do not link in objects from an archive just for init functions.
(makes go libraries behave more like c libraries.)
R=r
DELTA=85 (67 added, 12 deleted, 6 changed)
OCL=23133
CL=23139
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a3c4faf83f1849198b5431aa050793124a2fc91d
元コミット内容
6l: init関数だけのためにアーカイブからオブジェクトをリンクしないようにする。(Goライブラリの振る舞いをCライブラリにより近づける。)
変更の背景
この変更の背景には、Go言語のリンカ6lが、ライブラリ(アーカイブファイル、.a)に含まれるinit関数を処理する方法に関する課題がありました。従来の挙動では、たとえそのライブラリ内の他の関数が参照されていなくても、init関数が存在するだけで、リンカがライブラリ全体、または関連するオブジェクトファイルをリンクしてしまう可能性がありました。これは、最終的なバイナリサイズを不必要に大きくし、リンク時間を増加させる原因となります。
C言語のリンカでは、通常、ライブラリからシンボルを解決する際に、実際に参照されているシンボルを含むオブジェクトファイルのみをリンクします。init関数のような特殊な関数であっても、それが明示的に参照されていない限り、その関数を含むオブジェクトファイル全体がリンクされることはありません。このコミットは、Goのリンカも同様の「必要なものだけをリンクする」という原則に従うように修正し、GoライブラリがCライブラリと同様の効率的なリンク挙動を示すようにすることを目的としています。
特に、Goのinit関数はパッケージの初期化に用いられ、プログラムの起動時に自動的に実行されます。しかし、その存在がリンカに不要な依存関係を強制することは、モジュール性やバイナリサイズ最適化の観点から望ましくありませんでした。この変更により、init関数が「オプションの関数」として扱われ、その関数を含むオブジェクトファイルが、他のシンボルによって参照されない限り、リンクの対象から外れるようになります。
前提知識の解説
1. Go言語のinit関数
Go言語には、各パッケージが持つことができる特別な関数initがあります。
func init()というシグネチャを持ち、引数も戻り値もありません。- 各パッケージは複数の
init関数を持つことができます。 init関数は、パッケージがインポートされた際に、main関数が実行される前に自動的に実行されます。- 主に、パッケージレベルの変数の初期化、外部リソースへの接続、設定の読み込みなど、プログラムの実行開始前に一度だけ行われるべき処理に使用されます。
init関数の実行順序は、インポートの依存関係に基づいて決定されます。
2. 6lリンカ
6lは、Go言語のツールチェインの一部であるリンカです。Goのソースコードはコンパイラ(例: 6g for x86-64)によってオブジェクトファイルにコンパイルされ、その後6lによって実行可能ファイルにリンクされます。
6lは、Goプログラムに必要なすべてのオブジェクトファイル(コンパイルされたGoコード、標準ライブラリ、サードパーティライブラリなど)を結合し、実行可能なバイナリを生成します。- リンカの主な役割は、シンボル解決(未解決の参照を定義に結びつけること)と、最終的な実行可能ファイルのレイアウトを決定することです。
3. アーカイブファイル(.a)とライブラリのリンク
- アーカイブファイル(
.a): 複数のオブジェクトファイル(.o)を一つにまとめたファイルです。Unix系のシステムでは静的ライブラリとしてよく使われます。リンカは、アーカイブファイルの中から、プログラムが参照しているシンボルを定義しているオブジェクトファイルだけを抽出してリンクします。 - 静的リンク: プログラムのコンパイル時に、必要なライブラリのコードが実行可能ファイルに直接組み込まれる方式です。これにより、実行可能ファイルは自己完結型となり、実行時に外部ライブラリを必要としません。
- シンボル解決: リンカが、プログラム内で使用されている関数や変数の名前(シンボル)を、それらが定義されている実際のメモリ上のアドレスに結びつけるプロセスです。
4. C言語のリンカの挙動
C言語のリンカ(例: ld)は、静的ライブラリ(.a)をリンクする際に、非常に効率的な「必要なものだけをリンクする」戦略を採用しています。
- プログラムがライブラリ内の特定の関数や変数を使用している場合のみ、その関数や変数を含むオブジェクトファイルがアーカイブから抽出され、最終的な実行可能ファイルにリンクされます。
- ライブラリ内の他のオブジェクトファイルや、参照されていない関数は、バイナリサイズを肥大化させないためにリンクされません。
技術的詳細
このコミットは、6lリンカがinit関数を特別に扱うためのメカニズムを導入しています。
-
isinitfunc関数の導入:src/cmd/6l/go.cにisinitfunc(Sym *s)関数が追加されました。- この関数は、シンボル名にGoの内部的な
init関数のマーカー(·Init·または·init·)が含まれているかどうかをチェックします。Goのコンパイラは、init関数に対してこのような特殊なシンボル名を生成します。 - これにより、リンカは特定のシンボルが
init関数であるかどうかを識別できるようになります。
-
SOPTシンボルタイプの導入:src/cmd/6l/l.hに新しいシンボルタイプSOPTが追加されました。SOPTは「Optional Symbol(オプションのシンボル)」を意味し、init関数など、アーカイブから明示的に参照されなくてもリンクされるべきではない関数に割り当てられます。src/cmd/6l/obj.cのシンボル処理ロジックが変更され、isinitfuncが真を返すシンボルに対してSOPTタイプが設定されるようになりました。これにより、リンカはこれらの関数を「オプション」としてマークし、特別な処理を適用します。
-
ignoreoptfuncs関数の導入と利用:src/cmd/6l/go.cにignoreoptfuncs()関数が追加されました。- この関数は、リンカが生成したプログラム命令(
Prog)を走査し、SOPTタイプのシンボルへの呼び出し(ACALL命令)を見つけます。 - もし
SOPTシンボルへの呼び出しが見つかった場合、その呼び出し命令をANOP(No Operation)命令に変換し、fromとtoのアドレス指定を無効にします。これは、SOPTとしてマークされた関数が最終的にリンクされなかった場合に、その関数への呼び出しが実行時に問題を引き起こさないようにするための措置です。 src/cmd/6l/obj.cのmain関数内で、definetypestrings()やdefinetypesigs()の前にignoreoptfuncs()が呼び出されるようになりました。これにより、リンク処理の早い段階でオプション関数の呼び出しが処理されます。
-
newtext関数の導入とコードの整理:src/cmd/6l/pass.cにnewtext(Prog *p, Sym *s)関数が追加されました。- この関数は、テキストセクション(コード)に新しいプログラム命令を追加するロジックをカプセル化します。
- 以前は
src/cmd/6l/obj.cのATEXTケース内に直接記述されていた、シンボルタイプの設定、プログラムカウンタの更新、命令リストへの追加などの処理がnewtext関数にまとめられました。これにより、コードの重複が減り、可読性と保守性が向上しました。 ATEXT命令の処理において、シンボルがSTEXT(通常のテキストシンボル)またはSXREF(外部参照シンボル)であるかどうかのチェックに加えて、SOPTであるかどうかのチェックも追加されました。これにより、SOPTとしてマークされたinit関数が、再定義として誤って扱われることを防ぎます。
これらの変更により、6lリンカはinit関数を「オプション」として認識し、その関数が他のコードから明示的に参照されていない限り、その関数を含むオブジェクトファイルをアーカイブからリンクしないように動作します。これにより、Goの静的ライブラリのリンク挙動がC言語のそれにより近くなり、最終的なバイナリサイズが最適化されます。
コアとなるコードの変更箇所
src/cmd/6l/go.c
isinitfunc関数の追加: シンボル名がinit関数パターンに一致するかを判定。ignoreoptfuncs関数の追加:SOPTタイプのシンボルへの呼び出しをANOPに変換。
src/cmd/6l/l.h
Sym構造体にtextフィールド(Prog*型)を追加。enumにSOPTシンボルタイプを追加。ignoreoptfuncs、deadcode、newtext、isinitfunc関数のプロトタイプ宣言を追加。
src/cmd/6l/obj.c
main関数内でignoreoptfuncs()を呼び出すように変更。ANAME処理において、isinitfunc(s)が真の場合にシンボルタイプをSOPTに設定するロジックを追加。ATEXT処理において、シンボルがSOPTタイプでないことを再定義チェックの条件に追加。ATEXT処理のコード生成部分をnewtext(p, s)呼び出しに置き換え。
src/cmd/6l/pass.c
newtext関数の追加: テキストセクションに新しいプログラム命令を追加する共通ロジックをカプセル化。patch関数内のdiagメッセージをより詳細にするために、p->to.sym->nameを追加。
コアとなるコードの解説
isinitfunc (src/cmd/6l/go.c)
int
isinitfunc(Sym *s)
{
char *p;
p = utfrune(s->name, 0xb7); // 0xb7 = '·'
if(p == nil)
return 0;
if(memcmp(p, "·Init·", 8) == 0 || memcmp(p, "·init·", 8) == 0)
return 1;
return 0;
}
この関数は、Goのinit関数がコンパイラによって生成される際に付与される特殊なシンボル名(·Init·または·init·)を検出します。0xb7はUTF-8で·(中点)を表します。シンボル名にこの中点が含まれ、その後にInit·またはinit·が続く場合、そのシンボルはinit関数であると判断されます。
ignoreoptfuncs (src/cmd/6l/go.c)
void
ignoreoptfuncs(void)
{
Prog *p;
// nop out calls to optional functions
// that were not pulled in from libraries.
for(p=firstp; p != P; p=p->link) {
if(p->to.sym != S && p->to.sym->type == SOPT) {
if(p->as != ACALL)
diag("bad use of optional function: %P", p);
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
}
}
この関数は、リンカが生成した命令列(Progリスト)を走査します。もし命令のターゲットシンボル(p->to.sym)がSOPTタイプ(オプションの関数、つまりinit関数)であり、かつその命令が関数呼び出し(ACALL)である場合、その呼び出し命令をANOP(何もしない命令)に変換します。これにより、もしinit関数が最終的にリンクされなかったとしても、その関数への呼び出しが実行時にクラッシュを引き起こすことを防ぎます。
SOPTシンボルタイプの割り当て (src/cmd/6l/obj.c)
if((v == D_EXTERN || v == D_STATIC) && s->type == 0) {
s->type = SXREF;
if(isinitfunc(s))
s->type = SOPT; // optional function; don't pull in an object file just for s.
}
オブジェクトファイルを読み込む際、外部参照(D_EXTERN)または静的(D_STATIC)シンボルで、まだタイプが設定されていないもの(s->type == 0)に対して、まずSXREF(外部参照)タイプを設定します。その上で、もしそのシンボルがisinitfuncによってinit関数であると識別された場合、そのタイプをSOPTに上書きします。これにより、リンカは後続の処理でこのシンボルを「オプション」として特別に扱うようになります。
newtext (src/cmd/6l/pass.c)
Prog*
newtext(Prog *p, Sym *s)
{
if(p == P) {
p = prg();
p->as = ATEXT;
p->from.sym = s;
}
s->type = STEXT;
s->text = p;
s->value = pc;
lastp->link = p;
lastp = p;
p->pc = pc++;
if(textp == P)
textp = p;
else
etextp->pcond = p;
etextp = p;
return p;
}
この関数は、新しいテキストセクション(コード)の命令(Prog)を作成または初期化し、それをリンカの命令リストに追加する共通のロジックを提供します。シンボルsのタイプをSTEXT(テキストセクションのシンボル)に設定し、そのテキスト命令へのポインタをs->textに格納します。また、プログラムカウンタpcを更新し、命令をリンカの内部リストに適切に連結します。これにより、obj.c内の重複するコードが削減され、コードの構造が改善されました。
関連リンク
- Go言語の
init関数に関する公式ドキュメントやチュートリアル - Go言語のリンカ(
cmd/link)のソースコード - 静的ライブラリと動的ライブラリのリンクに関する一般的な情報
参考にした情報源リンク
- Go言語の初期のリンカの挙動に関する議論(GoのメーリングリストやIssueトラッカーなど、当時の情報源)
- C言語のリンカの挙動に関する一般的な情報(例:
man ld、リンカの仕組みに関する書籍やオンラインリソース) - Go言語のソースコード(特に
src/cmd/6lディレクトリ)
[インデックス 1528] ファイルの概要
このコミットは、Go言語のリンカである6lの挙動に関する重要な変更を導入しています。具体的には、アーカイブ(ライブラリ)からinit関数だけのためにオブジェクトをリンクしないように修正することで、Goライブラリの振る舞いをC言語のライブラリにより近づけることを目的としています。これにより、リンカの効率性が向上し、不要なコードのリンクが避けられます。
コミット
commit a3c4faf83f1849198b5431aa050793124a2fc91d
Author: Russ Cox <rsc@golang.org>
Date: Tue Jan 20 15:36:43 2009 -0800
6l: do not link in objects from an archive just for init functions.
(makes go libraries behave more like c libraries.)
R=r
DELTA=85 (67 added, 12 deleted, 6 changed)
OCL=23133
CL=23139
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/a3c4faf83f1849198b5431aa050793124a2fc91d
元コミット内容
6l: init関数だけのためにアーカイブからオブジェクトをリンクしないようにする。(Goライブラリの振る舞いをCライブラリにより近づける。)
変更の背景
この変更の背景には、Go言語のリンカ6lが、ライブラリ(アーカイブファイル、.a)に含まれるinit関数を処理する方法に関する課題がありました。従来の挙動では、たとえそのライブラリ内の他の関数が参照されていなくても、init関数が存在するだけで、リンカがライブラリ全体、または関連するオブジェクトファイルをリンクしてしまう可能性がありました。これは、最終的なバイナリサイズを不必要に大きくし、リンク時間を増加させる原因となります。
C言語のリンカでは、通常、ライブラリからシンボルを解決する際に、実際に参照されているシンボルを含むオブジェクトファイルのみをリンクします。init関数のような特殊な関数であっても、それが明示的に参照されていない限り、その関数を含むオブジェクトファイル全体がリンクされることはありません。このコミットは、Goのリンカも同様の「必要なものだけをリンクする」という原則に従うように修正し、GoライブラリがCライブラリと同様の効率的なリンク挙動を示すようにすることを目的としています。
特に、Goのinit関数はパッケージの初期化に用いられ、プログラムの起動時に自動的に実行されます。しかし、その存在がリンカに不要な依存関係を強制することは、モジュール性やバイナリサイズ最適化の観点から望ましくありませんでした。この変更により、init関数が「オプションの関数」として扱われ、その関数を含むオブジェクトファイルが、他のシンボルによって参照されない限り、リンクの対象から外れるようになります。
前提知識の解説
1. Go言語のinit関数
Go言語には、各パッケージが持つことができる特別な関数initがあります。
func init()というシグネチャを持ち、引数も戻り値もありません。- 各パッケージは複数の
init関数を持つことができます。 init関数は、パッケージがインポートされた際に、main関数が実行される前に自動的に実行されます。- 主に、パッケージレベルの変数の初期化、外部リソースへの接続、設定の読み込みなど、プログラムの実行開始前に一度だけ行われるべき処理に使用されます。
init関数の実行順序は、インポートの依存関係に基づいて決定されます。
2. 6lリンカ
6lは、Go言語のツールチェインの一部であるリンカです。Goのソースコードはコンパイラ(例: 6g for x86-64)によってオブジェクトファイルにコンパイルされ、その後6lによって実行可能ファイルにリンクされます。
6lは、Goプログラムに必要なすべてのオブジェクトファイル(コンパイルされたGoコード、標準ライブラリ、サードパーティライブラリなど)を結合し、実行可能なバイナリを生成します。- リンカの主な役割は、シンボル解決(未解決の参照を定義に結びつけること)と、最終的な実行可能ファイルのレイアウトを決定することです。
3. アーカイブファイル(.a)とライブラリのリンク
- アーカイブファイル(
.a): 複数のオブジェクトファイル(.o)を一つにまとめたファイルです。Unix系のシステムでは静的ライブラリとしてよく使われます。リンカは、アーカイブファイルの中から、プログラムが参照しているシンボルを定義しているオブジェクトファイルだけを抽出してリンクします。 - 静的リンク: プログラムのコンパイル時に、必要なライブラリのコードが実行可能ファイルに直接組み込まれる方式です。これにより、実行可能ファイルは自己完結型となり、実行時に外部ライブラリを必要としません。
- シンボル解決: リンカが、プログラム内で使用されている関数や変数の名前(シンボル)を、それらが定義されている実際のメモリ上のアドレスに結びつけるプロセスです。
4. C言語のリンカの挙動
C言語のリンカ(例: ld)は、静的ライブラリ(.a)をリンクする際に、非常に効率的な「必要なものだけをリンクする」戦略を採用しています。
- プログラムがライブラリ内の特定の関数や変数を使用している場合のみ、その関数や変数を含むオブジェクトファイルがアーカイブから抽出され、最終的な実行可能ファイルにリンクされます。
- ライブラリ内の他のオブジェクトファイルや、参照されていない関数は、バイナリサイズを肥大化させないためにリンクされません。
技術的詳細
このコミットは、6lリンカがinit関数を特別に扱うためのメカニズムを導入しています。
-
isinitfunc関数の導入:src/cmd/6l/go.cにisinitfunc(Sym *s)関数が追加されました。- この関数は、シンボル名にGoの内部的な
init関数のマーカー(·Init·または·init·)が含まれているかどうかをチェックします。Goのコンパイラは、init関数に対してこのような特殊なシンボル名を生成します。 - これにより、リンカは特定のシンボルが
init関数であるかどうかを識別できるようになります。
-
SOPTシンボルタイプの導入:src/cmd/6l/l.hに新しいシンボルタイプSOPTが追加されました。SOPTは「Optional Symbol(オプションのシンボル)」を意味し、init関数など、アーカイブから明示的に参照されなくてもリンクされるべきではない関数に割り当てられます。src/cmd/6l/obj.cのシンボル処理ロジックが変更され、isinitfuncが真を返すシンボルに対してSOPTタイプが設定されるようになりました。これにより、リンカはこれらの関数を「オプション」としてマークし、特別な処理を適用します。
-
ignoreoptfuncs関数の導入と利用:src/cmd/6l/go.cにignoreoptfuncs()関数が追加されました。- この関数は、リンカが生成したプログラム命令(
Prog)を走査し、SOPTタイプのシンボルへの呼び出し(ACALL命令)を見つけます。 - もし
SOPTシンボルへの呼び出しが見つかった場合、その呼び出し命令をANOP(No Operation)命令に変換し、fromとtoのアドレス指定を無効にします。これは、SOPTとしてマークされた関数が最終的にリンクされなかった場合に、その関数への呼び出しが実行時に問題を引き起こさないようにするための措置です。 src/cmd/6l/obj.cのmain関数内で、definetypestrings()やdefinetypesigs()の前にignoreoptfuncs()が呼び出されるようになりました。これにより、リンク処理の早い段階でオプション関数の呼び出しが処理されます。
-
newtext関数の導入とコードの整理:src/cmd/6l/pass.cにnewtext(Prog *p, Sym *s)関数が追加されました。- この関数は、テキストセクション(コード)に新しいプログラム命令を追加するロジックをカプセル化します。
- 以前は
src/cmd/6l/obj.cのATEXTケース内に直接記述されていた、シンボルタイプの設定、プログラムカウンタの更新、命令リストへの追加などの処理がnewtext関数にまとめられました。これにより、コードの重複が減り、可読性と保守性が向上しました。 ATEXT命令の処理において、シンボルがSTEXT(通常のテキストシンボル)またはSXREF(外部参照シンボル)であるかどうかのチェックに加えて、SOPTであるかどうかのチェックも追加されました。これにより、SOPTとしてマークされたinit関数が、再定義として誤って扱われることを防ぎます。
これらの変更により、6lリンカはinit関数を「オプション」として認識し、その関数が他のコードから明示的に参照されていない限り、その関数を含むオブジェクトファイルをアーカイブからリンクしないように動作します。これにより、Goの静的ライブラリのリンク挙動がC言語のそれにより近くなり、最終的なバイナリサイズが最適化されます。
コアとなるコードの変更箇所
src/cmd/6l/go.c
isinitfunc関数の追加: シンボル名がinit関数パターンに一致するかを判定。ignoreoptfuncs関数の追加:SOPTタイプのシンボルへの呼び出しをANOPに変換。
src/cmd/6l/l.h
Sym構造体にtextフィールド(Prog*型)を追加。enumにSOPTシンボルタイプを追加。ignoreoptfuncs、deadcode、newtext、isinitfunc関数のプロトタイプ宣言を追加。
src/cmd/6l/obj.c
main関数内でignoreoptfuncs()を呼び出すように変更。ANAME処理において、isinitfunc(s)が真の場合にシンボルタイプをSOPTに設定するロジックを追加。ATEXT処理において、シンボルがSOPTタイプでないことを再定義チェックの条件に追加。ATEXT処理のコード生成部分をnewtext(p, s)呼び出しに置き換え。
src/cmd/6l/pass.c
newtext関数の追加: テキストセクションに新しいプログラム命令を追加する共通ロジックをカプセル化。patch関数内のdiagメッセージをより詳細にするために、p->to.sym->nameを追加。
コアとなるコードの解説
isinitfunc (src/cmd/6l/go.c)
int
isinitfunc(Sym *s)
{
char *p;
p = utfrune(s->name, 0xb7); // 0xb7 = '·'
if(p == nil)
return 0;
if(memcmp(p, "·Init·", 8) == 0 || memcmp(p, "·init·", 8) == 0)
return 1;
return 0;
}
この関数は、Goのinit関数がコンパイラによって生成される際に付与される特殊なシンボル名(·Init·または·init·)を検出します。0xb7はUTF-8で·(中点)を表します。シンボル名にこの中点が含まれ、その後にInit·またはinit·が続く場合、そのシンボルはinit関数であると判断されます。
ignoreoptfuncs (src/cmd/6l/go.c)
void
ignoreoptfuncs(void)
{
Prog *p;
// nop out calls to optional functions
// that were not pulled in from libraries.
for(p=firstp; p != P; p=p->link) {
if(p->to.sym != S && p->to.sym->type == SOPT) {
if(p->as != ACALL)
diag("bad use of optional function: %P", p);
p->as = ANOP;
p->from.type = D_NONE;
p->to.type = D_NONE;
}
}
}
この関数は、リンカが生成した命令列(Progリスト)を走査します。もし命令のターゲットシンボル(p->to.sym)がSOPTタイプ(オプションの関数、つまりinit関数)であり、かつその命令が関数呼び出し(ACALL)である場合、その呼び出し命令をANOP(何もしない命令)に変換します。これにより、もしinit関数が最終的にリンクされなかったとしても、その関数への呼び出しが実行時にクラッシュを引き起こすことを防ぎます。
SOPTシンボルタイプの割り当て (src/cmd/6l/obj.c)
if((v == D_EXTERN || v == D_STATIC) && s->type == 0) {
s->type = SXREF;
if(isinitfunc(s))
s->type = SOPT; // optional function; don't pull in an object file just for s.
}
オブジェクトファイルを読み込む際、外部参照(D_EXTERN)または静的(D_STATIC)シンボルで、まだタイプが設定されていないもの(s->type == 0)に対して、まずSXREF(外部参照)タイプを設定します。その上で、もしそのシンボルがisinitfuncによってinit関数であると識別された場合、そのタイプをSOPTに上書きします。これにより、リンカは後続の処理でこのシンボルを「オプション」として特別に扱うようになります。
newtext (src/cmd/6l/pass.c)
Prog*
newtext(Prog *p, Sym *s)
{
if(p == P) {
p = prg();
p->as = ATEXT;
p->from.sym = s;
}
s->type = STEXT;
s->text = p;
s->value = pc;
lastp->link = p;
lastp = p;
p->pc = pc++;
if(textp == P)
textp = p;
else
etextp->pcond = p;
etextp = p;
return p;
}
この関数は、新しいテキストセクション(コード)の命令(Prog)を作成または初期化し、それをリンカの命令リストに追加する共通のロジックを提供します。シンボルsのタイプをSTEXT(テキストセクションのシンボル)に設定し、そのテキスト命令へのポインタをs->textに格納します。また、プログラムカウンタpcを更新し、命令をリンカの内部リストに適切に連結します。これにより、obj.c内の重複するコードが削減され、コードの構造が改善されました。
関連リンク
- Go言語の
init関数に関する公式ドキュメントやチュートリアル - Go言語のリンカ(
cmd/link)のソースコード - 静的ライブラリと動的ライブラリのリンクに関する一般的な情報
参考にした情報源リンク
- Go言語の初期のリンカの挙動に関する議論(GoのメーリングリストやIssueトラッカーなど、当時の情報源)
- C言語のリンカの挙動に関する一般的な情報(例:
man ld、リンカの仕組みに関する書籍やオンラインリソース) - Go言語のソースコード(特に
src/cmd/6lディレクトリ) - Web search results for "Go language init function behavior linker" (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGF5s_llFIEBGh_tgOYB0UfzSd5w-BietxoO4MmaBPT7sfnhoy1juWi3GW1sbvGbO-UHYLVVxY6thUB0DUeD6F6IOgr-vE8H5QA_UddDqi2E5ALpqkpGSYocPDG00W-7VNnZj1yUB3JE07C2aknQ1Rg_kNz2p8ooWCfJqAaNYCZodzQYjYbCeO3s_DnySOYHcV_eZF8jw2VbVSoK6IDn_C_pGRqCP5b)
- medium.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEZ8ypfj7x23_3jYIKDpQ-2zAkfPxFCrVCC1BRx0334OqO-hlB6qODRFBGZsQw78X_-a6IQ_APcvNBpnd9PDaCqk3_wG0jZpQsM3fkqzXLndjcMY9V-javjHEQsLYIkFcwpEGvtyarVr-gTz6Vh2o6DX_Q7d5cB7v3jf__-tkvGmzKTb8WGg__BQLLtvPZLmxNwCN9Qvcdzll33-no3hTc=)
- tutorialedge.net (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFOqhV3poGBvLJS3uTUM15ZvyAFOs2o2BXAX7Rdq4bWlKUlyj6584s1Uq8B9Fk-tbF2z6UGFfGSGKudTGNQDcz2pWxLheE6JSLgb7KI55moztV3u-ccspUgEKlsKgguwHwt7q7k0oQMVcoChNstQ9IQ)
- digitalocean.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE7v2sDXfiMlCuce-Mi-cV1EmTE-RxyYTjzI_yXMPuAJdCF1g5H00I9zmQB4UjQt5m2R_3H-MWZDgs05qdvzOSTxFYNdUg6CoBz4QbzeEfooyGkSx27ejJufCK2cLqu-_e-qx43qgqch4QOtl4zWsrQ40GcjwS2FAzsmWq8rLVTe2oO8WY=)
- github.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHE7OhcM0We6qUMY5ia4zeYOW5gxNwTLVjwjIET_7bBy8ekdc_951NfGWMhihCGRIEYq9RMRV6Z_bmkugMiGNGVkYthEovrnTzJs6qLr99Ungx_UVemXrlssC2Bm-QJxFDfmhFS)