※当サイトの記事には、広告・プロモーションが含まれます。

LinuxにおけるRubyのgemが何かとややこしい。Bundler、Gemfile、gemspec、Rakefileとは?

gigazine.net

Linuxの生みの親であるリーナス・トーバルズ氏が、2024年9月20日にReal Time Linuxとして知られる「PREEMPT_RT」を正式にLinuxカーネルへと組み込みました。

一定時間以内の応答を保証する「Real Time Linux」が正式にカーネルに組み込まれる - GIGAZINE

Real Time Linuxは産業用制御システム、医療機器、航空宇宙機器など「時刻」に敏感なシステムにLinuxを使用する際に、一定時間以内にイベントに応答することを保証する仕組み。PREEMPT_RTはカーネルを変更してリアルタイム性をLinuxに組み込むパッチセットで、2005年に誕生しました。

一定時間以内の応答を保証する「Real Time Linux」が正式にカーネルに組み込まれる - GIGAZINE

トーバルズ氏は2006年に「Linuxでレーザーを制御するなんて正気じゃない」と述べつつ、「でも、Linuxで産業用溶接レーザーを制御したいならPREEMPT_RTを使うことに何の問題もない」と自らのスタンスを表明。PREEMPT_RTはLinuxカーネルの一部ではありませんでしたが、長年にわたりさまざまな分野で使用されてきました。

一定時間以内の応答を保証する「Real Time Linux」が正式にカーネルに組み込まれる - GIGAZINE

そのため、正式にLinuxカーネルにPREEMPT_RTが組み込まれても即座に何かが変化するわけではありませんが、公式にカーネルに組み込まれたことでPREEMPT_RTを使用するシステムの依存関係が減り、保守がより容易になるとのこと。

一定時間以内の応答を保証する「Real Time Linux」が正式にカーネルに組み込まれる - GIGAZINE

⇧ ソフトウェア開発者としては、「Real Time Linux」に依存する機能を開発する上での環境構築が容易になるのであれば、嬉しいことですが。

「degrade(退化させる)」乃至は、「regression(退化、後戻り)」が起きておらず、性能面、セキュリティ面も影響がないのであれば、Linuxカーネルに組み込まれたのは、良いことのように思われますな。

Rubyのgemとは

Rubyの公式のドキュメントによると、

www.ruby-lang.org

⇧とあり、「gem」という用語は

  1. Rubyのライブラリの形式
  2. Rubyのライブラリを操作するコマンド

の2つの意味を持つらしいですと。

Wikipediaによると、

RubyGemsは、Ruby言語用のパッケージ管理システムであり、Rubyのプログラムと("gem" と呼ばれる)ライブラリの配布用標準フォーマットを提供している。gemを容易に管理でき、gemを配布するサーバの機能も持つ。Rubyバージョン1.9以降では標準ライブラリの一部となっている。

RubyGems - Wikipedia

⇧ とあり、RubyGemsとのやり取りをする際に「gem」コマンドを使っていると。

blog.rubygems.org

■旧い構成

■新しい構成

⇧ となってるらしい。

基本的には、RubyGemsというシステムが管理、公開しているGemライブラリをダウンロードしてきて利用する感じになるってことかね?

Bundler、Gemfile、gemspec、Rakefileとかって何なの?

で、Rubyのプロジェクトで目にするのが、

といった用語なんだけど、こ奴らは一体何者なのか?

「Bundler」はというと、

github.com

Bundler: a gem to bundle gems

Bundler makes sure Ruby applications run the same code on every machine.

https://github.com/rubygems/rubygems/tree/master/bundler

It does this by managing the gems that the application depends on. Given a list of gems, it can automatically download and install those gems, as well as any other gems needed by the gems that are listed. 

https://github.com/rubygems/rubygems/tree/master/bundler

Before installing gems, it checks the versions of every gem to make sure that they are compatible, and can all be loaded at the same time. 

https://github.com/rubygems/rubygems/tree/master/bundler

After the gems have been installed, Bundler can help you update some or all of them when new versions become available. 

https://github.com/rubygems/rubygems/tree/master/bundler

Finally, it records the exact versions that have been installed, so that others can install the exact same gems.

https://github.com/rubygems/rubygems/tree/master/bundler

Rubyのアプリケーションが動作する際の、環境依存を無くしてくれると謳っている。

何だろう、Javaで言うところの「Java 仮想マシンJVMJava Virtual Machine)」のような役割を実現しているということになるんだろうか?

Write once, run anywhereWORA「一度〔プログラムを〕書けば、どこでも実行できる」[要出典])または Write once, run everywhere (WORE) とは、Javaプログラムオペレーティングシステム (OS) などのプラットフォームに依存しないという意味の、サン・マイクロシステムズJavaスローガンである。

Write once, run anywhere - Wikipedia

概要

Javaで記述されたソフトウェアは多くのシステムの上で開発・コンパイルでき、同一のバイトコードを得ることができる。そのバイトコードJava仮想マシン(JVM)を持つ全てのシステムで動作する。Microsoft WindowsMac OSLinuxSolarisFreeBSDAIXNetWareHP-UXOS/2などで動く。

Write once, run anywhere - Wikipedia

⇧ とあるように、Javaにおいては、環境依存の無い動作を実現してるのが「Java 仮想マシンJVMJava Virtual Machine)」らしいですと。

勿論、完全に実現できているわけでは無いので、「ファイルシステム」に依存したソースコードなどは(「.sh」を実行する処理などは、Linux環境でしか動作しないなど)、一部の環境でしか動かない。

話が脱線しましたが、「Bundler」は「RubyGems」の一部かと思いきや、

github.com

⇧ 上記のページを見た感じでは、明確に区別されてるように思えますと。

続いて、「Gemfile」はというと、

bundler.io

Gemfile

Gemfile - A format for describing gem dependencies for Ruby programs

Bundler: gemfile

⇧「Bundler」の機能を実現する一部ということになる感じなんですかね?

「gemspec」「Rakefile」なども、「Bundler」の機能を実現する一部ってことになるんかな?

このあたり、発祥が不明なので、よく分からんですな...

とりあえず、「Bundler」に関連する登場人物たちということになるんですかね?

まとめると、

  • Bundler

「Bundler」特有の用語ってことになるんですかね?

Gemのインストール方法は2種類あるということ?

で、

guides.rubygems.org

The gem command allows you to interact with RubyGems.

https://guides.rubygems.org/rubygems-basics/

⇧ 上記サイト様にありますように、RubyGemsとのやり取りは、唯一、

  • gem command

のみでありますと。

なので、「Bundler」も内部的に、gem command を利用していると思われますが、Gemをインストールする方法としては、

  1. gem command直接実行する
  2. Bundlerを利用する

の2つの方法が用意されているという認識で良いのかしら?

Ruby界隈の事情が全く分からんので何とも言えませんが...

LinuxにおけるRubyプロジェクトのGemどう管理すれば?

で、最近、

  • Bundlerのインストールだと動かない
  • gem installだと動く

という事象に遭遇して、途方に暮れてましたと。

そりゃ、「Bundler」でGemを管理して動かせるなら動かしたいよ...

皆様のご推察の通り、

github.com

⇧「Oxidized」でございます。

そもそも、公式のドキュメントでも、「Bundler」を使っていないんよね...

Ruby」が適当過ぎるのか、「Oxidized」が適当過ぎるのか、それが問題だ、と言いたくなってしまうぐらい、カオスな状況ですと。

頼むから、環境構築で不毛な時間を浪費させないで欲しい...

RubyがGemを参照する仕組みが知りたいんだが...

そもそも、RubyがGemを参照する仕組みが把握できていないという...

ChatGPTに聞いた感じでは、

  1. GEM_HOME
  2. GEM_PATH

の2つの「環境変数」が、Gemを参照する上で関係してくるらしい。

stackoverflowによると、

stackoverflow.com

⇧ とあり、Rubyが実行の際に参照するGemは、「環境変数」の「GEM_PATH」の値を元にしているらしいですと。

で、「環境変数」の「GEM_HOME」がGemがインストールされる場所らしく、ChatGPTに聞いた感じでは、

Linuxのユーザー: GEM_HOME = 1: 1

⇧ ということらしく、Linuxのユーザー毎に異なるらしい。

ネットの情報でよく見かける「bundle install --path vendor/bundle」については、

bundler.io

⇧ 非推奨となっているが、Gemをインストールする場所を指定しているらしいので、「環境変数」の「GEM_HOME」を無視してインストールしているということらしい。

で、「Bundler」の上記のドキュメントで「GEM_PATH」についての記載が無いところをみると、おそらく「bundle install --path vendor/bundle」を実行したとしても、Gemがインストールされるだけであって、「環境変数」の「GEM_PATH」に対してインストールされたGemを参照するパスは自動で追加されないっぽい。

だから、Ruby実行時に、Gemが参照できないよ、って怒られたってことなんですかね?

ちなみに、「bundle install --path」の非推奨については、

makietan.github.io

⇧ 上記サイト様が対応を記載してくれておりました。

Gemが複数箇所にインストールされている場合、どちらも「環境変数」の「GEM_PATH」にGemの参照先を設定している場合、どういう挙動になるのか?

ChatGPTに確認したところ、

⇧ 先に設定されている方が優先されるらしい。

環境変数」の「GEM_PATH」の確認については、

qiita.com

qiita.com

⇧ 上記サイト様によりますと、

  • gem environment
    → Bundlerに関連する情報を除く
  • bundle env
    → Bundlerに関連する情報

という感じで、「Bundler」で管理してるかどうかの区別は、差分で確認する感じになるんかね?

Linux環境なら「printenv」とかで「環境変数」の「GEM_PATH」の値の全量は確認できそうな気がしますが、内訳を確認するには、「gem environment」や「bundle env」が必要になると。

他にも、

  • LOAD_PATH
  • RUBYLIB
  • RUBYPATH

のあたりについて、役割や関係性が分からんのよね...

環境変数」の「RUBYLIB」、「RUBYPATH」については、

docs.ruby-lang.org

Rubyの公式のドキュメントに載っていた。

「LOAD_PATH」については、

docs.ruby-lang.org

Rubyの組み込みライブラリで用意されている変数らしい。

ChatGPTに確認したところ、

RubyプログラムでGemが読み込まれるフロー

  1. Rubyプログラム実行:
  2. GEM_PATHの確認:
    • Rubyは「環境変数」の「GEM_PATH」を読み込み、Gemを検索するためのパスを取得します。
  3. LOAD_PATHの設定:
    • Rubyは初期の「LOAD_PATH」に、標準ライブラリのパスや、「環境変数」の「GEM_PATH」に基づいてインストールされたGemのパスを追加します。
    • ここで、「環境変数」の「RUBYLIB」や「RUBYPATH」に指定されたパスも考慮されます。これらが「LOAD_PATH」に追加されることにより、Rubyが自動的にロードするライブラリのパスが確保されます。
  4. requireの解決:
    • プログラム内で require や require_relative を使用してGemを読み込むと、 Rubyは「LOAD_PATH」を順に検索し、指定されたファイルを見つけます。
  5. Gemのファイルが読み込まれる:
    • 最初に見つかったファイルが読み込まれ、そのGemの機能が利用可能になります。

という流れになるそうな。

Ruby、何かとややこしい...

結局のところ、Rubyのプログラムが実行されるために必要な情報が分かり辛いんよね...

gemに種類があるらしい

何やら、

zenn.dev

⇧ とのことで、gem自体に種類があるそうな。

Ruby、徒労感が半端ない...

毎度モヤモヤ感が半端ない…

今回はこのへんで。