Подтвердить что ты не робот

Как скомпилировать Ruby?

Есть ли инструмент, который может позволить мне скомпилировать Ruby-код, чтобы он работал несколько быстрее?

Например, я слышал, что есть инструмент для Python, называемый "pyc", который позволяет нам скомпилировать код, чтобы он выполнялся в 10 раз быстрее.

4b9b3361

Ответ 1

Простой ответ заключается в том, что вы не можете, по крайней мере, с 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 вы можете использовать компилятор "Ahead Of Time" через, я полагаю, jrubyc.

Это не стандартный способ делать что-то, и вам, как правило, лучше, просто позволяя вашей реализации Ruby обрабатывать ее так, как она хочет. По крайней мере, Rubinius будет кэшировать байтовый код после первой компиляции, обновляя его так, как ему нужно.

Ответ 2

В начале 2013 года невозможно перевести Ruby в исходный код C/С++, а затем скомпилировать его.

Однако я слышал, что Мац (Yukihiro Matsumoto) говорит, что исследователь создает этот инструмент в Японии. Проект должен быть основан правительством Японии.

В противном случае вы можете использовать JRuby и скомпилировать его в байт-коде Java, или вы можете использовать Rubinius. Rubinius автоматически компилируется в байтовом коде (JIT-компилятор) для Rubinius VM. Можно преобразовать Rubinius в байт-код в LLVM IR, а LLVM может генерировать машинный код.

Ответ 3

Проверьте Unholy git repo

Ответ 4

Из 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.readbin('/home/john/bytecode')
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary byte_code

instruction_from_byte_code.eval
# => :shiva

Примечание. Этот ответ проверяется только в МРТ. Он может работать или не работать в других реализациях Ruby

Ответ 5

Я знаю, что это старый вопрос, но я нашел очень интересный проект, который может дать ответ на ваш вопрос: http://crystal-lang.org/

Он в основном компилирует Ruby в собственный машинный код. Это не совсем верно, потому что Crystal - это не совсем Ruby, и вам, возможно, придется внести некоторые изменения в ваш код. Есть также библиотеки, которые не поддерживаются (пока), но для меня все выглядит очень многообещающе.

Ответ 6

Следующий "самодостаточный" тестовый пример ruby основан на примерах из этой темы, из комментария/ответа пользователя по имени illusionist.

#!/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/info/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

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