Linux上でmacOSのソフトウェアを動かすプロジェクト
「Linux」上で「macOS」のソフトウェアを動作させるための変換レイヤーを開発しているプロジェクトがあります。そのプロジェクトの名称は「Darling」(ダーリン)です。
「macOS on Linux」といったところでしょうか。
DarwinとLinux
「Darling」は、「Darwin」と「Linux」を組み合わせた表現です。「Darwin」は「Apple」により開発されているオープンソースのOSであり、「macOS」など「Apple」が開発しているOSを支えるコアコンポーネントでもあります。
AppleのEULAには抵触しない
「Darling」のソースコードには、「Apple」の「EULA(ソフトウェア利用許諾契約)」に抵触するコードは含まれていません。そのためユーザーが「Apple」の「EULA」の影響を受けるソフトウェアを「Darling」上で実行しない限り、「Apple」の「EULA」に抵触することはありません。
変換レイヤー
「Darling」は「Linux」上で動作する変換レイヤーです。「macOS」のバイナリーをそのまま「Linux」上で実行できるように、「Darling」は「Linux」のライブラリーやツールキットと連携し、「macOS」のバイナリーが必要とする機能を提供します。
Darling今までと今後の展望
さて「Darling」の開発者が過去5年間を振り返り、また今後の展望について語っています。Darlingはここ5年間開発が行われているが、プロジェクトに対する質問を受け付けようと思う。
―数年間かけて何が起きたのか?成果は何か?いつ目標を達成できるのか?
Darlingの歴史
Darlingは最初、mach-o loader for linux(maloader)プロジェクトをベースとしていた。mach-o loader for linuxプロジェクトは今でもGitHubで見つけることができる。
当時を振り返ると、これは大きな失敗である。
まぁ失敗から学ぶという言い方もできるが。
当時私はmacOSの技術やアーキテクチャーに関する知識はほとんど無かった。
maloaderは、非常に単純なアプリケーションを動作させることができるかどうか技術的な可能性を実証するためだけに存在していたものであり、もっと複雑なソフトウェアを動作させる仕組みとしては不十分であった。
その後maloaderのやり方ではうまく行かないことが明らかになり、私はmaloaderのような高レベルAPIをそれに対応するLinuxの機能に変換する方法から、Appleのソースコードを直接ビルドする方法へと移行した。
つまり、libSystemからglibcへ直接橋渡しすることにしたのだ。
この方法は非常に基本的な"Hello world"アプリケーションを動作させるために多くの先行投資となる時間を必要としたが、この手法は正しい手法であった。
Darlingが悩まされてきた数々の互換性に関する問題が、この方法を採用した当初からすぐになくなったのだ。
そしてオリジナルのAppleのソースコードの一部分をビルドすれば、多くの作業を行うことなしにもっと多くの部分が簡単にビルドできるようになる。
Wineと同じ方針ではうまくいかない
この時点で私は、Wineを本プロジェクトのゴールの1つとして見ており、Wineが持つアイデアのいくつかを取り込みたいと考えていた。しかしそれは間違いであることが分かった。
とはいえ今回は前回の失敗と異なり、数カ月分の作業を無駄にすることにはならない。
Mach-Oへの移行
ご存知だと思うが、macOSなどApple製のOSは、アプリケーションや動的ライブラリーのバイナリーフォーマットにMach-Oを採用している。UnixライクなOSが採用しているELF形式とは対照的である。
masterブランチではELFでバイナリーを生成
今のところDarlingのmasterブランチでは、ELFファイルを生成するようになっている。これは生成されるmacOSライブラリーとフレームワークはすべてELF形式であるということを意味する。
そして様々な実行可能なファイル群がDarling内でmacOSライクな環境を構築する。
これはWineがやっていることと似たような手法である。
Wineのディレクトリー(/usr/lib/x86_64-linux-gnu/wine)内を見れば、多数の.dll.soファイルが見つかるだろう。
これらのファイルはWindowsライクな実行環境を構築するために使用され、あの残念な”winelib”ベースのアプリケーションの存在を可能にする。
実PE DLLの代わりにELFでライブラリー群を構築することはWineにとってなんら欠点を負うことのない合理的なことだろう。
私はこの手法の良し悪しを評価することはできない。
しかしDarlingにとってこの手法は数々の複雑さを持ち込むことになり、別の手法を採用する必要があった。
大きなハードル
Mach-Oへ移行するにあたり最も大きなハードルは、Mach-O特有の機能である。非常に効率的なELFと異なり、AppleはMach-Oに新機能を追加する前に熟考しない。
Mach-Oだけでなく多くの他の分野においてもそうだし、Appleのシステムコール一覧がその裏付けであり、Mach-Oも例外ではない。
Mach-O特有の機能は直接ELFが持つ機能に紐付けすることができない。
例えば2レベルの名前空間、シンボルの再エクスポート、特殊なセグメント、追加初期化パラメーター、FATバイナリーである。
シンボルのプレフィックスにアンダースコアを使用するなど他にも細かな違いがあり、これらの違いを処理するには困難を伴い、DarlingはAppleから取得したアセンブリファイルごとにパッチをあてる必要がある。
using-machos-experimentブランチ
これが今やDarlingがusing-machos-experimentブランチを持つ理由である。すべてのDarlingのコンポーネントはこのブランチを持っている。
このブランチから生成されるファイルはMach-Oでビルドされる。
ただしDarlingのブートストラップである小規模ないくつかの実行ファイルは例外である。
ClangコンパイラーのおかげでMach-Oでのビルドは容易になり、また、扱いやすくなったように思う。
多くのLinuxディストリビューションは、マルチターゲット機能を持ったClangを提供しており、macOS上でビルドしたのと同様にネイティブなMach-O形式のファイルを生成することができる。
唯一足りないのはリンカーだったが、Darlingのビルド過程でそれを追加するのは非常に簡単だった。
何を意味するのか
この方針の変更により、実際のmacOSの環境に近い環境をDarlingにもたらすことになる。macOSアプリケーションを実行している時、Darlingが生成した本物の.dylibファイルが/usr/libに存在している。
標準的なシステムで必要な.dylibファイルをメモリーへ読み込むソフトウェアや、それを利用するためにダイナミックリンカーに問い合わせるようなプラットフォーム間で互換性のない操作を行うソフトウェアは、homeで見つけられるだろう。
この開発ブランチにおいてすべてのコンポーネントはMach-O及びFATバイナリーでビルドされ、x86_64とi386アーキテクチャーのバイナリーを含む。
これらのビルドは1度にまとめて行われる。
シンボル衝突問題の終わり
これにより、macOSライブラリーとLinuxライブラリー間で発生する様々なシンボル名の衝突に終わりを告げることになる。この問題は、衝突を回避するためELFのシンボルバージョンを修正しても時々発生する問題であった。
シンボルの衝突がなくなるため、AppleオリジナルのダイナミックリンカーやObjective-Cランタイムが利用できるようになる。
まだ作業が完了していないもう一つの作業は、macOSとDarling間の互換性に関する違いを減らすことである。
加えて、EULAの問題から一旦離れれば、DarlingのライブラリーをmacOSオリジナルのライブラリーに置き換えても、動作する可能性をもたらす。
技術的に見れば、外の世界と相互作用するDarlingの機能に大きな影響を与えるものである。
32bitのmacOSアプリケーション
Mach-Oブランチでは現在、32bitのmacOSアプリケーションを動作させるために巧妙な手段を使用している。64bitのLinuxプロセス内に32bitのmacOSアプリケーションを読み込み、必要に応じて32bitモードに変換したり元に戻したりしている。
この仕組みには現実的な利点が殆ど無いとあなたは思うかもしれないし、おそらくその思いは正しいだろう。
だが確実に利点がある。
32bitのLinuxプロセスでは実現できないcommpageを正しいアドレスにマップするなどいくつか利点があるのだ。
コンテナー化
Darlingは現在プレフィックスを提供している。しかしもはやWineと同じ方法でプレフィックスを管理しない。
知っているかもしれないが、Wineを起動するとWineはプレフィックスを更新していますという迷惑なポップアップを表示する。
Darlingではこのようなポップアップはない。
オーバーレイ
Darlingは、デフォルトコンテンツを指すプレフィックスの上にユーザーのプレフィックを重ねあわせるため、overlayfsを使用している。特にMach-Oブランチにおいて、Darlingのファイル群はあちこちに横断的にファイルがばらまかれることはなく、すべてのファイルは<install-prefix>/libexec/darling以下に配置される。
オーバーレイの設定が完了すれば、Darlingはそのオーバーレイをルートファイルシステムとして扱い、そのオーバーレイへ切り替える。
そのオーバーレイは自身のマウント名前空間を持つ。
この名前空間及び他のLinux名前空間の利用は、DockerやLXCの動作手法に近い手法をDarlingにもたらす。
将来、個別のネットワーク名前空間の中に隔離されたDarlingプレフィックを存在できるようにオプションを提供しようと思う。
それはスタンドアローンのシステムのように動作させることができる。
将来の展望
Darlingはもはや独り舞台ではないのだ。二人の有能なエンジニア、Sergey氏とAndrew氏がプロジェクトに参加し、すでにすばらしい協力をしてくれている。
Darlingは現在Machの移植(Linux Kernelモジュールに実装)周りの改善やkqueueのサポートが必要である。
Machのサポート方法の選択
今後Machの移植に関する大きな議題は、Machサポートのために独自の実装を行っていくのか、それともXNUのオリジナルコードの移植を試してみるか、ということである。もし後者に取り組むとしたら、macOSのlaunchdやnotifyd、syslogdなど多くのデーモンを動かせるようになるだろう。
GUIアプリケーションをサポートするために
その一方でSergey氏は、GUIアプリケーションの実行に必要となるすべてのレイヤーを接続し、GUIアプリケーションの実験を行っている。またどのようにGUIアプリケーションの実行手法を進展させるのが良いか方法を把握しようとしている。
macOS環境により近づけるために
Andrew氏は、Darlingの環境をmacOS環境に近づける作業を行っている。例えばDarling内でPerlのビルドを行っている。
これは愚かな作業に聞こえるかもしれないが、macOSでPerlが実際に必要となる頻度、Perlが呼ばれる頻度を知れば、あなたは驚くことになるだろう。
そしてこの作業は愚かなことではない。
DarlingはLinuxで提供されているPerlを利用することはできないのだ。
基盤固め
これはエンドユーザーにとってあまり関心がないことかもしれないが、プロジェクトに将来性及び実行可能な継続性を持たせるために、すべてのプロジェクトは堅実な基盤か始めなければならない。これがGUIアプリケーションのサポートが長期目標になっている理由である。
しかしコンソールアプリケーションならDarling上での動作を見ることはできる。
コンソールアプリケーションは主な目標ではなく、目的を達成するための手段・一過程である。
ドキュメントとデバッグ
Darlingは現在ドキュメントが不十分な状態である。これは新しい協力者にとって初期学習を難しくするものである。
そこで私はDarlingのドキュメントプロジェクトを開始し、DarlingのアイデアやDarlingの技術的な解説を行う計画である。
同様に一般的なmacOS内部の働きも紹介する予定である。
後者は特に重要である。
macOSのスキルを持つ多くの開発者でさえも、例えばMachの移植がどのように動作するのかといった理解は曖昧である。
先ほど出てきたcommpageについてもあまり知られていないだろう。
ELFファイルだけでなくMach-Oファイルのシンボルやデバッグ情報の読み込みを可能にするgdb-darlingデバッガーを開発するための作業が、using-machos-experimentブランチで行われている。
これはMach-Oへの移行のために必須のものであり、コンパイルされたDarlingのコードの99%はMach-Oファイルの中に配置され、このデバッガーがなければデバッグは非常に複雑なものになる。