构建 Ruby

依赖项

  1. 安装构建 CRuby 解释器的先决条件依赖项

    • C 编译器

    对于 RubyGems,您还需要

    如果要从 git 存储库构建,还需要

    • autoconf - 2.67 或更高版本

    • gperf - 3.1 或更高版本

      • 通常不需要;仅当您使用 gperf 编辑某些源文件时才需要

    • ruby - 3.0 或更高版本

      • 我们可以将此版本升级到最新的 Ubuntu LTS 的系统 ruby 版本。

  2. 安装可选的、推荐的依赖项

    • libffi(用于构建 fiddle)

    • gmp(如果您希望加速 Bignum 操作)

    • rustc - 1.58.0 或更高版本,如果您希望构建 YJIT

    如果要链接安装到非操作系统默认位置的库(例如,在 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

快速入门指南

  1. 下载 ruby 源代码

    选择以下选项之一。

    1. 从 tarball 构建

      下载 Ruby 页面下载最新的 tarball 并解压。例如,Ruby 3.0.2

      tar -xzf ruby-3.0.2.tar.gz
      cd ruby-3.0.2
    2. 从 git 存储库构建

      检出 CRuby 源代码

      git clone https://github.com/ruby/ruby.git
      cd ruby

      运行 GNU Autoconf 脚本(它会生成 configure 脚本)

      ./autogen.sh
  2. 在存储库目录中创建一个 build 目录

    mkdir build && cd build

    虽然没有必要在这样的专用目录中构建,但这样做是一个好习惯。

  3. 我们最终会将新的 Ruby 安装在 ~/.rubies/ruby-master 中,因此我们将创建该目录

    mkdir ~/.rubies
  4. 运行 configure 脚本(它会生成 Makefile

    ../configure --prefix="${HOME}/.rubies/ruby-master"
    • 同时,-C(或 --config-cache)可以减少下次配置的时间。

  5. 构建 Ruby

    make
    
  6. 运行测试 以确认您的构建成功。

  7. 将新编译的 Ruby 安装到 ~/.rubies/ruby-master

    make install
    
    • 如果您需要使用 sudo 运行 make install 并希望避免生成具有不同权限的文档,可以使用 make SUDO=sudo install

  8. 然后您可以尝试新的 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 目标

编译以进行调试

您应该配置 Ruby 时不进行优化,并使用其他可能干扰调试的标志

./configure --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"

使用 Address Sanitizer 构建

使用 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_SCALESYNTAX_SUGEST_TIMEOUT 变量是必需的,以确保测试不会在实际上只是速度较慢时因为超时而虚假地失败。

RUBY_TEST_TIMEOUT_SCALE=5 SYNTAX_SUGGEST_TIMEOUT=600 make check

但是,请注意以下警告!

如何衡量 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 或更高版本。