プログラミング
Redプログラミング言語: 静的リンクのサポート
Red Programming Language: Static linking support (red-lang.org)
要約
Redプログラミング言語は、C言語で書かれたライブラリの静的リンクをサポートし、すべての依存関係を内部にパッケージ化した単一の実行可能ファイルを配布できるようになりました。この機能は、外部ライブラリをプログラムに組み込み、配布の簡素化を可能にします。開発プロセスでは、エージェント(AI)の支援を受けながら、COFF、ELF、Mach-Oという3つのネイティブオブジェクト形式に対応し、選択的なアーカイブ読み込みやCOMDAT/弱シンボル折りたたみなどの高度な機能を実現しています。
全文翻訳
ページ
ホーム
について
始める
ダウンロード
ドキュメント
貢献
ロードマップ
プライバシーポリシー
2026年6月29日
静的リンクのサポート
「海がいつか穏やかになるという希望から解放されなければならない。私たちは強い風の中で航海することを学ばなければならない。」
-アリストテレス・オナシス
コーディングエージェントの革命が世界を席巻しており、私たちはその真っ只中にいます。皆さんの多くと同様に、私たちもエージェントの驚くべき(そして不満の募る)機能を試し、Redと新しい世界における私たちのビジョンの役割について考察しました。結論は(驚くほど)明確です。Redは依然として非常に重要であり、エージェントとの連携を改善することで、さらにその重要性を増すでしょう。その間、いくつかの機能強化をご紹介します。まず、C言語で書かれたライブラリの静的リンクをサポートするためにツールチェーンを拡張し、すべての依存関係を内部にパックした単一の実行可能ファイルを配布できるようになりました。この作業は、フロンティアモデルとローカルハーネス(Claude CodeとCodex)の多大な支援を受けて行われました。これは小さな追加機能だと思われるかもしれませんが、静的リンカーは各プラットフォームのオブジェクト形式を読み込み、必要な部分だけを取り込み、重複したセクションを折りたたみ、システムシンボルを解決し、手作業で再配置をパッチ適用する必要があるため、かなりの数のメカニズムを構築する必要がありました。その報酬は、誰もが望む結果です。つまり、他に何もインストールする必要のない、単一の自己完結型バイナリです。
簡単な例
プログラムの隣に圧縮ライブラリを出荷することなく、データを圧縮してみましょう。具体的には、よく知られているzlibおよびdeflate APIを実装する小さなMITライセンスのライブラリであるminizを使用します。これは、単一の`miniz.c` / `miniz.h`ペアとして配布されており、コンパイルとリンクに特に便利です。
最初のステップは、minizを静的ライブラリにコンパイルすることです。考慮すべき点は2つだけです。Red/Systemは現在32ビットコードを生成するため、オブジェクトも32ビットである必要があります。また、コンパイラの余分な機能(C++例外テーブルとスタックカナリア)をいくつかオフにすると、オブジェクトが不要なランタイムヘルパーを参照しなくなります。
Windowsでは、MSVCで:
cl /c /MT /GS- /EHs-c- /GR- miniz.c lib /out:miniz.lib miniz.obj
次に、必要な2つの関数をマップします。インポートされた名前に拡張子がなく、単に`miniz`であることに注意してください:
Red/System [
Title: "miniz round-trip]
#import [
"miniz" cdecl [
compress: "mz_compress" [
dst [byte-ptr!] dst-len [int-ptr!] src [byte-ptr!] src-len [integer!] return: [integer!]
]
uncompress: "mz_uncompress" [
dst [byte-ptr!] dst-len [int-ptr!] src [byte-ptr!] src-len [integer!] return: [integer!]
]
]
]
この拡張子のない名前が興味深い点です。ツールチェーンが自動的に解決し、単一のコマンドラインスイッチで解決方法を決定します。デフォルトでは、`miniz`はプラットフォームの共有ライブラリ(Windowsでは`miniz.dll`、Linuxでは`libminiz.so`)に解決されるため、プログラムはRed/Systemが常にそうであったように動的にリンクされます:
red -r demo.reds ; "miniz"はminiz.dllに解決され、動的にリンクされます
次に、静的を示す`-s`(または長い方の`--static`)を追加すると、同じ`miniz`は代わりに、先ほど構築した静的ライブラリに解決されます:
red -r -s demo.reds ; "miniz"はminiz.libに解決され、静的にリンクされます
今回は`mz_compress`と`mz_uncompress`が実行可能ファイル自体の一部になります。隣に出荷する`miniz.dll`はなく、設定する`PATH`も、作成するインストーラーもなく、コピーしてどこでも実行できる単一の自己完結型バイナリ(ここでは50KB未満)だけです。同じソースファイルに、1つの追加フラグです。
必要に応じて明示的に指定する
拡張子のない名前は便利ですが、自分で拡張子を明示的に指定することも常に可能です。その場合、ツールチェーンはその指定を正確に尊重し、`-s`はその特定のインポートには影響しません。これは、1つのプログラムが両方の種類のリンクを混在させる場合に便利です。つまり、常に動的にしたいシステムライブラリと、常に組み込みたいヘルパーライブラリを組み合わせる場合です。たとえば:
#import["user32.dll" stdcall [...]] ; 常に動的
#import["miniz.lib" cdecl [...]] ; 常に静的 (Windows)
#import["libminiz.a" cdecl [...]] ; 常に静的 (Linux / macOS)
このように、拡張子のない名前と`-s`を使用してプログラム全体を一度に切り替えることも、明示的な拡張子でライブラリごとの制御を行うこともできます。既存のコードで、すでに`.dll` / `.so` / `.dylib`と明示的に指定しているものは、変更なしで動作し続けます。したがって、これらのツールチェーンへの追加機能は、現在のコードベースとの後方互換性があります。
サポートされるターゲット
静的リンクは、Redの主要なすべてのネイティブターゲットで動作します。
Windows (x86) — COFFオブジェクトとライブラリ (`.obj` / `.lib`)
Linux (x86) — ELFオブジェクトとアーカイブ (`.o` / `.a`)
Linux ARM、Raspberry Piを含む — ARMとThumb-2コードの両方のELF ARM
macOS (Intel) — Mach-Oオブジェクトとアーカイブ
クロスコンパイルは通常通り機能するため、`-t RPi -s`は自己完結型のARMバイナリをデスクトップ上で直接ビルドし、Piにコピーして実行する準備が整います。
実際のケース: CherryTracker
ツールチェーンの静的リンク機能をテストしてデモするための実際のケースが必要で、その結果、非常に満足のいく完全に動作するツールを構築し、リリースすることにしました: CherryTracker。コーディングエージェント機能の最近の進歩により、Redで長年コーディングしたいと思っていたサウンドトラッカースタイルのmodプレイヤーを、サイドプロジェクトとして生成することができました!目指していた洗練されたバージョンを得るには、エージェントとの間で多くの(数十回もの)反復が必要でした。それでも、コードの品質とスタイルを改善するために何度も手を入れる必要がありました。理想ほど短く洗練されているわけではありませんが、エージェントが生成したものとしては十分です。ソースコードはGithubで公開されています。WindowsおよびLinux用の事前構築済みバイナリが利用可能です(ウェブサイトまたはリポジトリを参照)。Windowsバイナリには、私の個人コード署名証明書で署名されています。ModArchiveから入手したさまざまな形式の多数のmodもリポジトリから入手できます。CherryTrackerはRedで記述されており、DrawベースのUIを使用し、Red/Systemレイヤーで高速データ処理とバックエンドライブラリとのインターフェースを行っています。
libxmp: さまざまなmodソング形式のデコードに使用されます。
SDL3: オーディオレイヤーを提供するために使用されます。
これらのライブラリの32ビット静的バージョンは、両方のターゲットOSのlibsフォルダーに提供されています。インポートコードは拡張子のないオプションを使用しています。
#import["libs/libxmp" cdecl [...]]
#import["libs/SDL3" cdecl [...]]
私のローカルリポジトリには、これらの外部ライブラリの共有ライブラリバージョンも配置しています。Redツールチェーンの開発コンパイルモード(`-c`)とこれらの共有ライブラリを使用すると、エージェントと私は新しいバージョンを非常に迅速に再コンパイルしてテスト(libRedRTを使用)し、リリースバージョンでは`-r -s`コンパイルオプションを使用して静的リンクに切り替えることができます。このアプローチは、このアプリケーション(余暇で数週間にわたって)全体での作業中に、非常にシンプルで効率的であることが証明されました。試してみて、特に80年代/90年代にmodを再生していた方なら、Redがコーディングエージェントと組み合わせたときに何ができるかをご覧ください!
舞台裏を見る
これは実際の静的リンカーであり、「バイトを連結する」トリックではありません。共通のインターフェースを介してCOFF、ELF、Mach-Oの3つのネイティブオブジェクト形式を読み込み、静的リンクを実際に機能させる部分を処理します。
➤ 選択的アーカイブ読み込み: アーカイブは何百ものオブジェクトファイルを含むことができます。リンカーは、すでに何かを参照しているシンボルを解決するメンバーだけを取り込み、その依存関係チェーンを最後までたどります。大きな`.lib`に対してリンクしても、大きな実行可能ファイルにはなりません。
➤ COMDATおよび弱シンボル折りたたみ: C++(および現代のCでは`inline`を介して)は、同じテンプレートインスタンス化、インライン関数、またはvtableをすべての翻訳単位で発行し、リンカーが1つのコピーを保持し、残りを破棄することを期待しています。リンカーはこれらのグループを追跡し、重複を、それらを指していた再配置とともに折りたたみます。
➤ フォーマットごとの完全な再配置サポート: 扱いにくいものも含まれます。Piに必要なARM Thumb-2分割即値とBL/BLXインターワーキング、および最適化されたスイッチテーブルが生成するMach-Oの散布型セクション差分再配置などです。