Auto-linkingまとめ
Auto-linkingとは
Auto-linkingとは、コンパイラが出力したオブジェクトファイルからリンク対象のライブラリを自動的に決定する仕組みです。
通常、ユーザはリンカのコマンドライン引数に -lm
のようにリンクするライブラリを指定しますが、Auto-linkingをサポートするコンパイラとリンカを使う場合、以下のようなC言語の #pragma
コメントを記述することで、リンカオプションを指定をせずに、リンカにライブラリを伝えることができます。
#include <math.h> #include <stdio.h> #pragma comment(lib, "m") int main(void) { printf("PI = %f\n", atan(1) * 4); return 0; }
コンパイルの様子
# -lmの指定無しでリンクが成功する $ clang main.c -fuse-ld=lld $ ./a.out PI = 3.141593
リンカオプションを指定する必要が無くなることで、ユーザの負担が減るだけでなく、ビルドシステム中のオプション伝播が単純化されます。嬉しいですね。
この記事ではオブジェクトファイル形式ごとのAuto-linkingの実装状況と、LLVMにおけるサポートについて解説します。
(完全に理解したがしばらくして忘れて調べ直す、を何回かやったのでいい加減文字に起こすことにした)
オブジェクトファイル形式ごとの仕組み
上で紹介した #pragma comment(lib, "...")
はIBMコンパイラ、MSVC、Clangが提供しているディレクティブです。(他にもサポートしてるコンパイラはあるかも)
MSVCはCOFF、ClangはELF、Mach-O、COFF向けにこの機能を実装しています。
COFF
MSVCが出力するオブジェクトファイル形式COFFには、リンカオプションを格納する.drectve
セクションがあります。このセクションはオブジェクトファイルのみでサポートされており、通常のセクションとは異なり、最終的な実行可能ファイルには含まれません。
コンパイラは #pragma comment(lib, "...")
からリンカオプションを生成し、オブジェクトファイルの.drectve
セクションに埋め込むことで、link.exeコマンドにリンクするライブラリを伝えています。
PE Format - Win32 apps | Microsoft Docs: The .drectve Section (Object Only)
ELF
ELFにはCOFFのような仕様として定義されたリンカオプション用セクションはありません。
その代わりに、LLVMがClangとlldの間のコンベンションとして特殊なセクションを定義しています。
そのため、Clangで#pragma comment(lib, "...")
をコンパイルしたとしても、goldやGNU ldでリンクする場合オプションが伝わりません。
LLVMの実際の実装については後述します。
Mach-O
Mach-Oオブジェクトファイルには、ヘッダの後ろにLoad Command呼ばれる構造体列が配置されており、セクションやセグメントなどのレイアウト、動作に必要なOSバージョンなど、リンカやプログラムローダに伝える情報が格納されています。このLoad Commandの一つに、 LC_LINKER_OPTION
があり、その名の通りリンカオプションをリンカに伝えてくれます。
このあたりの情報は明確なドキュメントを見つけられておらず、実装を追って分かったことなので、Mach-Oの規約として定義されているものなのかは分かりません。(もしドキュメントの在り処をご存じの方がいれば教えて下さい)
リンカ(ld64)側の実装はこのあたりにあります。 macho_relocatable_file.cpp
LLVMにおけるAuto-linking
さて、LLVMにはAuto-linkingを実現するための機能が歴史的経緯により2つあります。どちらもLLVM IR上のモジュールメタデータとして表現されており、コンパイラがLLVM IRを生成する際に指定します。
1つ目は、llvm.linker.options
です。
このメタデータは、COFFでは.drectve
、Mach-OではLC_LINKER_OPTION
に降下します。
一応ELFでも SHT_LLVM_LINKER_OPTIONS
という特別なセクションにリンカオプションが埋め込まれるようにコード生成されますが、なんと肝心のlld側が対応していません。
他のオブジェクトファイルの形式と違い、任意のリンカオプションを受け付けるのではなく、オプションのセマンティクスを明示的にしたKey-Valueペアで表現するため、
コンパイラフロントエンドがELF向けに特別な処理を入れる必要があります。
SwiftのWindowsポートで有名なcompnerdさんが2018年に提案して、ClangフロントエンドとLLVMバックエンドの実装をしましたが、その後アップデートが無いようです。
- LLVM Language Reference Manual: Automatic Linker Flags Named Metadata
- [llvm-dev] Linker Option support for ELF
2つ目は llvm.dependent-libraries
です。
llvm.linker.options
のELFサポートが難航している状態に対して、SonyのPlay Station向けツールチェイン開発者の方が新しく導入したメタデータです。
これは、ELFのみをサポートしており、 リンクするライブラリ名の配列を受け付け、オブジェクトファイルのSHT_LLVM_DEPENDENT_LIBRARIES
というセクションに埋め込みます。
こちらはClang、LLVMバックエンド、リンカの実装が完了しています。現在のClangは#pragma comment(lib, "...")
をELFの場合のみ、llvm.linker.options
を使う実装になっています。
まとめ
大変