构建 Ruby¶ ↑
依赖项¶ ↑
-
安装构建 CRuby 解释器的先决条件依赖项
-
C 编译器
对于 RubyGems,您还需要
如果您想从 git 存储库构建,您还需要
-
-
安装可选的、推荐的依赖项
如果要链接安装到非 OS 默认位置的库(例如,macOS 上的 Homebrew),请将 `--with-opt-dir`(或 gmp 的 `--with-gmp-dir`)选项传递给 `configure`。
configure --with-opt-dir=$(brew --prefix gmp):$(brew --prefix jemalloc)
至于仅特定扩展名而不是 Ruby 所需的库(openssl、readline、libyaml、zlib),您可以将 `--with-EXTLIB-dir` 选项添加到命令行或 `CONFIGURE_ARGS` 环境变量中。命令行选项将嵌入到 `rbconfig.rb` 中,而后者环境变量不会嵌入,仅在构建扩展库时使用。
export CONFIGURE_ARGS="" for ext in openssl readline libyaml zlib; do CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-$ext-dir=$(brew --prefix $ext)" done
快速入门指南¶ ↑
-
下载 ruby 源代码
选择以下选项之一。
-
从 tarball 构建
从 Download Ruby 页面下载最新的 tarball 并解压缩它。例如,Ruby 3.0.2
tar -xzf ruby-3.0.2.tar.gz cd ruby-3.0.2
-
从 git 存储库构建
检出 CRuby 源代码
git clone https://github.com/ruby/ruby.git cd ruby
运行 GNU Autoconf 脚本(它会生成 `configure` 脚本)
./autogen.sh
-
-
在存储库目录内创建一个 `build` 目录
mkdir build && cd build
虽然不一定需要在这样的专用目录中构建,但这样做是一个好习惯。
-
我们最终会将新的 Ruby 安装到 `~/.rubies/ruby-master` 中,因此我们将创建该目录
mkdir ~/.rubies
-
运行 `configure` 脚本(它会生成 `Makefile`)
../configure --prefix="${HOME}/.rubies/ruby-master"
-
此外,`-C`(或 `--config-cache`)将减少下次配置的时间。
-
-
构建 Ruby
make
-
运行测试以确认您的构建成功。
-
将新编译的 Ruby 安装到 `~/.rubies/ruby-master` 中
make install
-
如果您需要使用 `sudo` 运行 `make install` 并希望避免使用不同权限生成文档,则可以使用 `make SUDO=sudo install`。
-
-
然后,您可以尝试您的新 Ruby,例如
~/.rubies/ruby-master/bin/ruby -e "puts 'Hello, World!'"
最后,您的存储库将如下所示
ruby ├── autogen.sh # Pre-existing Autoconf script, used in step 1 ├── configure # Generated in step 1, which generates the `Makefile` in step 4 ├── build # Created in step 2 and populated in step 4 │ ├── GNUmakefile # Generated by `../configure` │ ├── Makefile # Generated by `../configure` │ ├── object.o # Compiled object file, built my `make` │ └── ... other compiled `.o` object files │ │ # Other interesting files: ├── include │ └── ruby.h # The main public header ├── internal │ ├── object.h │ └── ... other header files used by the `.c` files in the repo root. ├── lib │ └── # Default gems, like `bundler`, `erb`, `set`, `yaml`, etc. ├── spec │ └── # A mirror of the Ruby specification from github.com/ruby/spec ├── test │ ├── ruby │ └── ... ├── object.c └── ... other `.c` files
无法解释的构建错误¶ ↑
如果您遇到无法解释的构建错误,请在保存所有工作后,尝试在源根目录中运行 `git clean -xfd` 以删除所有 git 忽略的本地文件。如果您正在使用已更新多次的源目录,则可能存在先前版本中的临时构建工件,这会导致构建失败。
在 Windows 上构建¶ ↑
有关在 Windows 上构建的文档可以在 单独的文件中找到。
更多细节¶ ↑
如果您有兴趣继续开发 Ruby,以下是有关 Ruby 构建的更多详细信息,以提供帮助。
并行运行 make 脚本¶ ↑
在 GNU make1 和 BSD make 实现中,要并行运行特定的 make 脚本,请传递标志 `-j<进程数>`。例如,要在 8 个进程上运行测试,请使用
make test-all -j8
我们还可以设置 `MAKEFLAGS` 以并行运行*所有* `make` 命令。
拥有正确的 `--jobs` 标志将确保在构建软件项目时利用所有处理器。为了有效地执行此操作,您可以在 shell 配置/配置文件中设置 `MAKEFLAGS`
# On macOS with Fish shell: export MAKEFLAGS="--jobs "(sysctl -n hw.ncpu) # On macOS with Bash/ZSH shell: export MAKEFLAGS="--jobs $(sysctl -n hw.ncpu)" # On Linux with Fish shell: export MAKEFLAGS="--jobs "(nproc) # On Linux with Bash/ZSH shell: export MAKEFLAGS="--jobs $(nproc)"
Miniruby 与 Ruby¶ ↑
Miniruby 是一个没有外部依赖项且缺少某些功能的 Ruby 版本。它在 Ruby 开发中很有用,因为它允许更快的构建时间。Miniruby 在 Ruby 之前构建。构建 Ruby 需要一个功能正常的 Miniruby。要构建 Miniruby
make miniruby
调试¶ ↑
您可以使用 lldb 或 gdb 进行调试。在调试之前,您需要创建一个 `test.rb`,其中包含您想要运行的 Ruby 脚本。您可以使用以下 make 目标
-
`make run`:使用 Miniruby 运行 `test.rb`
-
`make lldb`:在 lldb 中使用 Miniruby 运行 `test.rb`
-
`make gdb`:在 gdb 中使用 Miniruby 运行 `test.rb`
-
`make runruby`:使用 Ruby 运行 `test.rb`
-
`make lldb-ruby`:在 lldb 中使用 Ruby 运行 `test.rb`
-
`make gdb-ruby`:在 gdb 中使用 Ruby 运行 `test.rb`
编译以进行调试¶ ↑
您应该配置 Ruby,使其不进行优化以及其他可能会干扰调试的标志
./configure --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
使用地址消毒器构建¶ ↑
使用地址消毒器 (ASAN) 是检测内存问题的好方法。它可以检测 Ruby 本身以及使用 ASAN 编译并加载到使用 ASAN 编译的 Ruby 中的任何 C 扩展中的内存安全问题。
./autogen.sh mkdir build && cd build ../configure CC=clang-18 cflags="-fsanitize=address -fno-omit-frame-pointer -DUSE_MN_THREADS=0" # and any other options you might like make
如果 ASAN 检测到内存安全问题,则编译后的 Ruby 现在将自动崩溃并显示报告和回溯。要在 ASAN 下运行 Ruby 的测试套件,请发出以下命令。请注意,这会花费很长时间(在我的笔记本电脑上超过两个小时);`RUBY_TEST_TIMEOUT_SCALE` 和 `SYNTAX_SUGEST_TIMEOUT` 变量是必需的,以确保测试不会因超时而虚假地失败,而实际上它们只是速度很慢。
RUBY_TEST_TIMEOUT_SCALE=5 SYNTAX_SUGGEST_TIMEOUT=600 make check
但是,请注意以下注意事项!
-
ASAN 将无法在任何当前发布的 Ruby 版本上正常工作;必要支持目前仅存在于 Ruby 的 master 分支上(并且整个测试套件仅在提交 修订版 9d0a5148 时通过)。
-
由于 Bug #20243,Clang 为线程局部变量生成的代码不适用于 M:N 线程。因此,现在需要在构建时禁用 M:N 线程支持(使用 `-DUSE_MN_THREADS=0` 配置参数)。
-
ASAN 仅在使用 Clang 18 或更高版本时才有效 - 它需要与多线程 `fork` 相关的 llvm/llvm-project#75290。
-
ASAN 迄今为止仅在 Linux 上的 Clang 上进行了测试。它可能适用于其他编译器或其他平台,也可能不适用 - 如果您在使用此类配置时遇到问题,请在 Ruby 问题跟踪系统上提交问题(或者,报告它们实际上正常工作!)
-
特别是,虽然我还没有尝试过,但我有理由相信 ASAN 暂时*无法*在 macOS 上正常工作 - 多线程 fork 问题的修复实际上已在 macOS 上还原(请参阅 llvm/llvm-project#75659)。如果这对您来说是一个问题,请在 Ruby 问题跟踪系统上打开一个问题。
如何测量 C 和 Ruby 代码的覆盖率¶ ↑
您需要能够使用 gcc (gcov) 和 lcov 可视化工具。
./autogen.sh ./configure --enable-gcov make make update-coverage rm -f test-coverage.dat make test-all COVERAGE=true make lcov open lcov-out/index.html
如果您只需要 C 代码覆盖率,您可以从上述过程中移除 COVERAGE=true
。您也可以直接使用 gcov
命令来获取每个文件的覆盖率。
如果您只需要 Ruby 代码覆盖率,您可以移除 --enable-gcov
。请注意,test-coverage.dat
会累积所有 make test-all
的运行结果。如果您只想测量一次测试运行,请务必删除该文件。
您可以在这里查看 CI 的覆盖率结果:rubyci.org/coverage
1 注意:GNU make 3 缺少一些用于并行执行的功能,我们建议升级到 GNU make 4 或更高版本。