RVM 和 rbenv 是如何工作的?

Posted

技术标签:

【中文标题】RVM 和 rbenv 是如何工作的?【英文标题】:How do RVM and rbenv actually work? 【发布时间】:2012-03-12 18:05:32 【问题描述】:

我对 RVM 和 rbenv 的实际工作方式很感兴趣。

显然,它们在不同版本的 Ruby 和 gemset 之间进行交换,但这是如何实现的?我原以为他们只是在更新符号链接,但在深入研究代码后(我必须承认我对 Bash 的了解是肤浅的),他们似乎做了更多的事情。

【问题讨论】:

【参考方案1】:

所以总结一下上面的优秀答案,RVM 和 rbenv 之间的主要实际区别在于选择 Ruby 的版本。

rbenv:

rbenv 在路径的开头添加一个 shim,这是一个与 Ruby 同名的命令。当您在命令行中键入 ruby 时,将运行 shim(因为它也称为“ruby”并且在路径中排在第一位)。 shim 会查找环境变量或 .rbenv_version 文件来告诉它要委托给哪个版本的 Ruby。

RVM:

RVM 允许您通过调用 rvm use 直接设置 Ruby 版本。此外,它还覆盖了cd 系统命令。当您将cd 放入包含.rvmrc 文件的文件夹时,将执行.rvmrc 文件中的代码。这可用于设置 Ruby 版本,或您喜欢的任何其他版本。

其他区别:

当然还有其他区别。 RVM 具有开箱即用的 gemset,而 rbenv 只需要更多的 hacking(但不多)。两者都是问题的功能解决方案。

【讨论】:

【参考方案2】:

主要区别似乎是when and how ruby is switched。 Ruby 已切换:

手动(使用 rvm)或在更改目录期间自动用于 RVM 每次执行 ruby​​ 命令时自动用于 rbenv

RVM 依赖于修改后的cd 命令和rvm use 手动选择Ruby。 rbenv 使用所有基本 ruby​​ 命令的包装器或“垫片”作为选择 ruby​​ 的默认机制。 RVM 也为 gem、rake、ruby 等基本命令行工具创建包装器。例如,它们在 CronJobs 中使用(参见 http://rvm.io/integration/cron/),但它们不是切换 Ruby 版本的默认机制。

因此,这两种方法都通过覆盖命令和使用包装器来“自动”选择正确的 Ruby 版本。 rvm 覆盖像 cd 这样的 shell 命令。 rbenv 覆盖所有基本的 ruby​​ 命令,例如 ruby​​、irb、rake 和 gem。

【讨论】:

【参考方案3】:
rvm system
env > before
rvm jruby # or whatever
env > after
diff after before

给你大约:

< GEM_HOME=$HOME/.gem/ruby/1.9.1
---
> GEM_HOME=$HOME/.rvm/gems/jruby-1.6.6
< GEM_PATH=$HOME/.gem/ruby/1.9.1
---
> GEM_PATH=$HOME/.rvm/gems/jruby-1.6.6:$HOME/.rvm/gems/jruby-1.6.6@global
*bunch of rvm_*
> MY_RUBY_HOME=$HOME/.rvm/rubies/jruby-1.6.6
> RUBY_VERSION=jruby-1.6.6
> IRBRC=$HOME/.rvm/rubies/jruby-1.6.6/.irbrc

并且它预先设置:

$HOME/.rvm/gems/jruby-1.6.6/bin:$HOME/.rvm/gems/jruby-1.6.6@global/bin

$PATH

【讨论】:

【参考方案4】:

我写了一篇深度文章:http://niczsoft.com/2011/11/what-you-should-know-about-rbenv-and-rvm/

基本区别在于shell环境改变的地方:

RVM:当您更改 Ruby 时,它已更改。 rbenv:当您运行 Ruby/gem 可执行文件时,它发生了变化。

另外,关于 RVM 的事情是,它涵盖的范围远远超过仅仅管理 Ruby,它比任何其他工具都多得多(除了 RVM 和 rbenv 之外,还有其他工具:https://twitter.com/#!/mpapis/status/171714447910502401)

不要忘记您在 Freenode 服务器上的“#rvm”频道中获得的即时支持。

【讨论】:

谢谢,两个社区的人都参与进来真是太好了。【参考方案5】:

简短说明:rbenv 通过挂钩到您环境的PATH 来工作。概念很简单,但魔鬼在细节中;下面是完整的独家新闻。

首先,rbenv 为您安装的所有 Ruby 版本中的所有命令(rubyirbrakegem 等)创建 shims。这个过程称为重新散列。每次安装新版本的 Ruby 或安装提供命令的 gem 时,运行 rbenv rehash 以确保所有新命令都已填充。

这些垫片位于一个目录中(默认为~/.rbenv/shims)。要使用 rbenv,您只需将 shims 目录添加到 PATH 的前面:

export PATH="$HOME/.rbenv/shims:$PATH"

然后,无论何时您从命令行运行ruby,或运行shebang 读取#!/usr/bin/env ruby 的脚本,您的操作系统都会首先找到~/.rbenv/shims/ruby 并运行它而不是您可能拥有的任何其他ruby 可执行文件已安装。

每个 shim 都是一个小型 Bash 脚本,依次运行 rbenv exec。因此,在您的路径中使用 rbenv,irb 等效于 rbenv exec irbruby -e "puts 42" 等效于 rbenv exec ruby -e "puts 42"

rbenv exec 命令确定您要使用的 Ruby 版本,然后针对该版本运行相应的命令。方法如下:

    如果设置了RBENV_VERSION 环境变量,则其值将确定要使用的Ruby 版本。 如果当前工作目录有.rbenv-version文件,则其内容用于设置RBENV_VERSION环境变量。 如果当前目录中没有.rbenv-version 文件,rbenv 会在每个父目录中搜索.rbenv-version 文件,直到它到达文件系统的根目录。如果找到,则其内容用于设置RBENV_VERSION 环境变量。 如果RBENV_VERSION 仍未设置,rbenv 会尝试使用~/.rbenv/version 文件的内容来设置它。 如果没有在任何地方指定版本,rbenv 会假定您要使用“系统”Ruby,即如果 rbenv 不在您的路径中,将运行任何版本。

(您可以使用rbenv local 命令设置项目特定的Ruby 版本,该命令会在当前目录中创建.rbenv-version 文件。同样,rbenv global 命令修改~/.rbenv/version 文件。)

使用RBENV_VERSION 环境变量,rbenv 将~/.rbenv/versions/$RBENV_VERSION/bin 添加到PATH 的前面,然后执行传递给rbenv exec 的命令和参数。瞧!

要彻底了解幕后究竟发生了什么,请尝试设置 RBENV_DEBUG=1 并运行 Ruby 命令。 rbenv 运行的每个 Bash 命令都将写入您的终端。


现在,rbenv 只关心切换版本,但蓬勃发展的插件生态系统将帮助您完成从installing Ruby 到setting up your environment、managing "gemsets" 甚至automating bundle exec 的所有工作。

我不太确定 IRC 支持与切换 Ruby 版本有什么关系,而 rbenv 被设计为简单易懂,不需要支持。但是,如果您需要帮助,只需单击几下即可获得问题跟踪器和 Twitter。

披露:我是 rbenv、ruby-build 和 rbenv-vars 的作者。

【讨论】:

感谢您抽出宝贵时间给出如此出色的答案。 哇,感谢您提供如此通俗易懂的解释。天生的老师。 嘿,Sam,因为这个答案已经有两年了,你想更新一下吗?从那时起,rbenv 肯定发生了一些变化。 不。我见过的最好的黑客描述。我认为唯一需要更改的更新是指向 rbenv-gemset 的链接(该链接仍会将您带到那里。这只是重定向的另一个额外步骤)。

以上是关于RVM 和 rbenv 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

rbenv、rvm 和 chruby 有啥区别? [关闭]

为 Ruby on Rails 6 创建弹性 beanstalk 环境时遇到问题(rvm、rbenv、.ruby-version 问题)

markdown 从RVM切换到rbenv

使用rbenv 进行ruby 多版本的管理

如何从我的系统中删除 RVM(Ruby 版本管理器)

Rubygems、Bundler 和 RVM 混淆