构建 Ruby
依赖项
-
安装构建 CRuby 解释器所需的前提依赖项
-
C 编译器
对于 RubyGems,您还需要
如果您想从 git 仓库构建,您还需要
-
-
安装可选、推荐的依赖项
如果您想链接安装在 OS 默认位置以外的库(例如 gmp),通常在 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-mastermake 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
对于 VS Code 用户,您可以通过运行以下命令来设置基于编辑器的调试体验
cp -r misc/.vscode .vscode
这将为通过运行 test.rb 并使用 lldb 来调试 Ruby 本身添加启动配置。
注意:如果您在 ./build 文件夹下构建 Ruby,您需要相应地更新 .vscode/launch.json 中的 program 条目为:"${workspaceFolder}/build/ruby"
为调试编译
您可以使用 RUBY_DEBUG 宏编译 Ruby,以在某些功能上启用调试。一个例子是在 Ruby 中使用 RubyVM::Shape.of(object) 调试对象形状。
此外,Ruby 可以被编译以支持 RUBY_DEBUG 环境变量,以在某些功能上启用调试。一个例子是使用 RUBY_DEBUG=gc_stress 来调试 GC 相关问题。
还支持 RUBY_DEBUG_LOG 环境变量,通过 USE_RUBY_DEBUG_LOG 宏记录 VM 操作的大量信息。
您还应该在没有优化和其他可能干扰调试的标志的情况下配置 Ruby,通过更改优化标志来实现。
整合所有内容
./configure cppflags="-DRUBY_DEBUG=1 -DUSE_RUBY_DEBUG_LOG=1" --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
使用 Address Sanitizer 构建
使用地址消毒器 (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
但是,请注意以下注意事项!
-
由于 Bug #20243,Clang 为线程局部变量生成了代码,这与 M:N 线程不兼容。因此,目前有必要在构建时禁用 M:N 线程支持(使用
-DUSE_MN_THREADS=0configure 参数)。 -
ASAN 仅在使用 Clang 18 或更高版本时有效 - 它需要 llvm/llvm-project#75290,这与多线程
fork相关。 -
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 或更高版本。