[macruby-changes] [2016] MacRuby/branches/experimental/bin/rubyc

source_changes at macosforge.org source_changes at macosforge.org
Sat Jul 11 02:36:55 PDT 2009


Revision: 2016
          http://trac.macosforge.org/projects/ruby/changeset/2016
Author:   lsansonetti at apple.com
Date:     2009-07-11 02:36:55 -0700 (Sat, 11 Jul 2009)
Log Message:
-----------
added macrubyc command line tool, an interface to the AOT compiler

Added Paths:
-----------
    MacRuby/branches/experimental/bin/rubyc

Added: MacRuby/branches/experimental/bin/rubyc
===================================================================
--- MacRuby/branches/experimental/bin/rubyc	                        (rev 0)
+++ MacRuby/branches/experimental/bin/rubyc	2009-07-11 09:36:55 UTC (rev 2016)
@@ -0,0 +1,197 @@
+#!/usr/bin/ruby
+# MacRuby AOT Compiler.
+#
+# This file is covered by the Ruby license.
+#
+# Copyright (C) 2009, Apple Inc
+
+require 'optparse'
+require 'rbconfig'
+
+class Compiler
+  NAME = File.basename(__FILE__)
+  VERSION = '0.1'
+
+  def initialize(argv)
+    # Parse arguments.
+    OptionParser.new do |opts|
+      opts.banner = "Usage: #{NAME} [options] file..."
+      opts.on('-c', 'Compile and assemble, but do not link') { @dont_link = true }
+      opts.on('-o <file>', 'Place the output into <file>') { |output| @output = output }
+      opts.on('-v', '--version', 'Display the version') { show_version }
+      opts.on('-V', '--verbose', 'Print every command line executed') { @verbose = true }
+      opts.on('-h', '--help', 'Display this information') { die opts }
+      begin
+        opts.parse!(argv)
+      rescue OptionParser::InvalidOption => e
+        die e, opts
+      end
+      die opts if argv.empty?
+      @files = argv
+    end
+
+    # Locate necessary programs.
+    @macruby = locate('macruby')
+    @llc = locate('llc')    
+    @gcc = locate('gcc')
+    @gcxx = locate('g++')
+    @nm = locate('nm')
+
+    # Misc.
+    @tmpdir = (ENV['TMPDIR'] or raise 'no TMPDIR?')
+    @tmpfiles = []
+  end
+
+  def run
+    if @dont_link
+      if @files.size > 1 and @output
+        die "cannot specify -o with -c and multiple input files"
+      end
+      @files.each do |file|
+        if File.extname(file) != '.rb'
+          die "given input file `#{file}' must be a Ruby source file (.rb)"
+        end
+        compile_object(file, @output)
+      end
+    else
+      objs = @files.map do |file|
+        case File.extname(file)
+          when '.rb'
+            compile_object(file, nil)
+          when '.o'
+            die "given input file `#{file} must exist" unless File.exist?(File)
+            file
+          else
+            die "given input file `#{file}' must be either a Ruby source file (.rb) or a Mach-O object file (.o)"
+        end
+      end
+      compile_executable(objs, @output)
+    end
+  end
+
+  def cleanup
+    @tmpfiles.each { |x| File.delete(x) }
+  end
+
+  private
+
+  def compile_object(path, output)
+    base = File.basename(path, '.rb') 
+    output ||= File.join(File.dirname(path), base + '.o')
+
+    # Compile the file into LLVM bitcode.
+    bc = gen_tmpfile(base, 'bc')
+    execute("#{@macruby} --emit-llvm \"#{bc}\" \"#{path}\"")
+
+    # Compile the bitcode as assembly.
+    asm = gen_tmpfile(base, 's')
+    execute("#{@llc} -f #{bc} -o=#{asm}")
+
+    # Finally compile the assembly.
+    execute("#{@gcc} -c -arch x86_64 #{asm} -o #{output}")
+
+    output
+  end
+
+  def compile_executable(objs, output)
+    output ||= 'a.out'
+
+    # Guess which objects were originally MacRuby source files and memorize their init function.
+    init_funcs = []
+    objs.each do |file|
+      ary = execute("#{@nm} #{file}").scan(/^\d+\sT\s(_MREP_.*)$/)
+      unless ary.empty?
+        init_funcs << ary[0][0][1..-1] # drop _ prefix
+      end
+    end
+
+    # Generate main file.
+    main_txt = <<EOS
+extern "C" {
+    void ruby_sysinit(int *, char ***);
+    void ruby_init(void);
+    void ruby_set_argv(int, char **);
+    void rb_vm_init_compiler(void);
+    void *rb_vm_top_self(void);
+    void rb_vm_print_current_exception(void);
+    void rb_exit(int);
+EOS
+    init_funcs.each { |x| main_txt << "void *#{x}(void *, void *);\n" }
+    main_txt << <<EOS
+}
+
+int main(int argc, char **argv)
+{
+    ruby_sysinit(&argc, &argv);
+    if (argc > 0) {
+	argc--;
+        argv++;
+    }
+    ruby_init();
+    ruby_set_argv(argc, argv);
+    rb_vm_init_compiler();
+    try {
+        void *self = rb_vm_top_self();
+EOS
+    init_funcs.each { |x| main_txt << "#{x}(self, 0);\n" }
+    main_txt << <<EOS
+    }
+    catch (...) {
+	rb_vm_print_current_exception();
+	rb_exit(1);
+    }
+    rb_exit(0);
+}
+EOS
+
+    # Compile main file.
+    main = gen_tmpfile('main', 'cpp')
+    File.open(main, 'w') { |io| io.write(main_txt) }
+    main_o = gen_tmpfile('main', 'o')
+    execute("#{@gcxx} #{main} -c -arch x86_64 -o #{main_o}")
+    objs.unshift(main_o)
+
+    # Link all objects into executable.
+    line = "#{@gcxx} -o #{output} -L#{RbConfig::CONFIG['libdir']} -lmacruby-static -arch x86_64 -framework Foundation -lobjc -lauto -I/usr/include/libxml2 -lxml2 "
+    line << execute("llvm-config --ldflags --libs core jit nativecodegen interpreter bitwriter").gsub(/\n/, '')
+    objs.each { |o| line << " #{o}" }
+    execute(line)
+  end
+
+  def execute(line)
+    $stderr.puts line if @verbose
+    ret = `#{line}`
+    die "Error when executing `#{line}'" unless $?.success?
+    ret
+  end
+
+  def locate(progname)
+    path = `which #{progname}`.strip
+    die "Can't locate program `#{progname}'" if path.empty?
+    path
+  end
+
+  def gen_tmpfile(base, ext)
+    file = File.join(@tmpdir, "#{base}.#{ext}")
+    @tmpfiles << file
+    file
+  end
+
+  def die(*args)
+    $stderr.puts args
+    exit 1
+  end
+
+  def show_version
+    puts "MacRuby version #{MACRUBY_VERSION}"
+    puts "#{NAME} version #{VERSION}"
+    exit 1
+  end
+end
+
+app = Compiler.new(ARGV)
+begin
+  app.run
+ensure
+  app.cleanup
+end
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20090711/05e2f0e3/attachment.html>


More information about the macruby-changes mailing list