如何编译Ruby?

问题描述 投票:0回答:8

有没有一个工具可以让我编译 Ruby 代码,使其运行得更快一些?

例如,我听说Python有一个名为“pyc”的工具,可以让我们编译代码,使其运行速度提高10倍。

ruby compilation
8个回答
27
投票

简单的答案是你不能,至少对于 MRI 1.8(标准)来说是这样。这是因为 1.8 通过遍历抽象语法树来工作。 Python、Ruby 1.9、JRuby 和 Rubinius 使用字节码,这允许编译为中间表示(字节码)。 从 MRI Ruby 2.3 开始,做到这一点变得很容易,请参阅下面的answer

使用 Rubinius,您可以执行本文中描述的操作:http://rubini.us/2011/03/17/running-ruby-with-no-ruby/

在 JRuby 中,我相信,您可以通过 jrubyc 使用“Ahead Of Time”编译器。

这并不是真正的标准处理方式,通常最好让 Ruby 实现按照自己的意愿处理它。 Rubinius 至少会在第一次编译后缓存字节代码,并根据需要进行更新。


12
投票

ruby 2.3.0
可以轻松地将源代码编译为 Ruby-VM 可以理解的字节码。

byte_code = RubyVM::InstructionSequence.compile_file '/home/john/somefile.rb'

File.binwrite '/home/john/bytecode', byte_code.to_binary

以及在命令行中

$ cat bytecode 

YARB�
IUsx86_64-linux*.*1

+1�!AA*1
!qy��������yyQ� E/home/john/somefile.rbE<main>E <class:A>EshivaEhelloEAEputsEcore#define_methodu����� 5M

文件内容

class A
  def shiva
    puts 'hello'
  end
end

目的是什么?

Ruby 需要时间将源代码编译为字节码,因此您可以将字节码直接加载到 ruby 中并执行。没有语法检查和编译的开销。它比正常过程快得多。

如何加载字节码?

bytecode = File.binread('/home/john/bytecode')
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary bytecode

instruction_from_byte_code.eval
# => :shiva

注意:此答案仅在 MRI 中进行测试。它可能在其他 Ruby 实现中起作用,也可能不起作用


8
投票

我知道这是一个老问题,但我发现了一个非常有趣的项目,可以为您的问题提供答案:http://crystal-lang.org/

它基本上将 Ruby 编译为本机机器代码。这并不完全正确,因为 Crystal 并不完全是 Ruby,您可能需要对代码进行一些修改。还有一些库(尚未)不受支持,但对我来说,这一切看起来都非常有前途。


7
投票

2013年初还没有办法将Ruby翻译成C/C++源码然后编译。

不过,我听Matz(松本幸弘)说,日本的一位研究人员正在创造这个工具。该项目应该由日本政府发起。

否则,您可以使用 JRuby 并将其编译为 Java 字节码,或者您可以使用 Rubinius。 Rubinius 自动为 Rubinius VM 编译字节码(JIT 编译器)。可以将字节码形式的 Rubinius 转换为 LLVM IR,并且 LLVM 可以生成机器代码。


4
投票

检查Unholy git 仓库


0
投票

以下“独立”Ruby 测试用例基于该线程中的示例,来自名为 magicist 的用户的评论/答案。

#!/usr/bin/env ruby
#==========================================================================
# This file is in public domain.
# The code of this file is based on the code fragments at the
# 2018_12_09 version of the:
#
#     https://stackoverflow.com/questions/5902334/how-to-compile-ruby
#
# This file has been tested with the ruby version
#
#     ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
#
#-----start--of--the--boilerplate------------------------------------------

s_fp_home=ENV["HOME"].to_s
s_fp_tmp=s_fp_home+"/tmp" # using /tmp can be a security risk
s_fp_demofolder=s_fp_tmp+"/ruby_bytecode_usage_demo_01"

def create_folder_if_needed(s_fp_in)
   if !Dir.exists? s_fp_in
      Dir.mkdir(s_fp_in)
      if !Dir.exists? s_fp_in
         raise(Exception.new("\n\n Folder creation failed.\n"+
         "GUID=='d6e409cb-e072-4441-9421-22630190c2e7'\n"))
      end # if
   end # if
end # create_folder_if_needed
create_folder_if_needed(s_fp_tmp)
create_folder_if_needed(s_fp_demofolder)

s_rand=""
7.times{s_rand<<("_"+rand(100).to_s)}

s_fp_bytecode=s_fp_demofolder+"/awesome_bytecode"+s_rand
s_fp_src=s_fp_demofolder+"/x"+s_rand+".rb"

if File.exists? s_fp_src
   raise(Exception.new("\n\n This file should not exist yet.\n"+
   " s_fp_src=="+s_fp_src+"\n"+
   "GUID=='43ab3d45-1324-47af-9441-22630190c2e7'\n"))
end # if
IO.write(s_fp_src,"puts('');puts('Greetings from bytecode!');puts('')")
if !File.exists? s_fp_src
   raise(Exception.new("\n\n The file \n"+s_fp_src+"\n is missing.\n"+
   "GUID=='4aeb5e54-efe0-4111-a851-22630190c2e7'\n"))
end # if


#-----start--of--the--core--of--the--demo----------------------------------

bytecode_out = RubyVM::InstructionSequence.compile_file(s_fp_src)
IO.binwrite(s_fp_bytecode, bytecode_out.to_binary)

bytecode_in = IO.binread(s_fp_bytecode)
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary(bytecode_in)
instruction_from_byte_code.eval

#==========================================================================

0
投票

尝试使用 ruby-packer,它可以从 Ruby 和 Ruby on Rails 应用程序创建可执行文件


0
投票

我假设您正在运行 CRuby。

您可以在运行 Ruby 时尝试使用

--jit
标志,看看是否可以获得任何速度。否则,我认为您还不能将 Ruby 脚本编译为本机代码。仅通过
RubyVM
模块进行字节码,但我认为您不会从中获得任何好处。

Crystal-lang 或 GraalVM 可以作为您的替代方案(进行一些可能的更改)以获得更高的性能。

© www.soinside.com 2019 - 2024. All rights reserved.