Skip to content

Instantly share code, notes, and snippets.

@godfat
Created December 30, 2009 17:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save godfat/548caf0d63f647c0fbe2 to your computer and use it in GitHub Desktop.
Save godfat/548caf0d63f647c0fbe2 to your computer and use it in GitHub Desktop.
def compile_object(path, output)
base = File.basename(path, '.rb')
output ||= File.join(File.dirname(path), base + '.o')
# Generate init function (must be unique).
uuid = `uuidgen`.strip.gsub('-', '')
init_func = "MREP_#{uuid}"
tmp_objs = []
@archs.each do |arch|
# Compile the file into LLVM bitcode.
bc = gen_tmpfile(base + arch, 'bc')
execute("arch -#{arch} #{@macruby} --emit-llvm \"#{bc}\" #{init_func} \"#{path}\"")
# Compile the bitcode as assembly.
asm = gen_tmpfile(base + arch, 's')
execute("#{@llc} -f \"#{bc}\" -o=\"#{asm}\" -march=#{llc_arch(arch)} -relocation-model=pic -enable-eh")
# Compile the assembly.
tmp_obj = gen_tmpfile(base + arch, 'o')
execute("#{@gcc} -c -arch #{arch} \"#{asm}\" -o \"#{tmp_obj}\"")
tmp_objs << tmp_obj
end
# Link the architecture objects.
cli_tmp_objs = tmp_objs.map do |obj|
'"' + obj + '"'
end
execute("#{@lipo} -create #{cli_tmp_objs.join(' ')} -output \"#{output}\"")
[output, init_func]
end
def compile_executable(objs_data, output)
output ||= 'a.out'
raise if objs_data.empty?
die "first object file must be a Ruby source file or object" if objs_data[0][1] == nil
# Generate main file.
main_txt = <<EOS
extern "C" {
void ruby_sysinit(int *, char ***);
void ruby_init(void);
void ruby_init_loadpath(void);
void ruby_script(const char *);
void ruby_set_argv(int, char **);
void rb_vm_init_compiler(void);
void rb_vm_aot_feature_provide(const char *, void *);
void *rb_vm_top_self(void);
void rb_vm_print_current_exception(void);
void rb_exit(int);
EOS
objs_data.each do |obj, init_func|
next if init_func == nil
main_txt << "void *#{init_func}(void *, void *);\n"
end
main_txt << <<EOS
}
int main(int argc, char **argv)
{
const char *progname = argv[0];
ruby_sysinit(&argc, &argv);
if (argc > 0) {
argc--;
argv++;
}
ruby_init();
ruby_init_loadpath();
ruby_set_argv(argc, argv);
rb_vm_init_compiler();
ruby_script(progname);
try {
EOS
objs_data[1..-1].each do |obj, init_func|
next if init_func == nil
main_txt << "rb_vm_aot_feature_provide(\"#{feature_name(obj)}\", (void *)#{init_func});\n"
end
main_txt << <<EOS
void *self = rb_vm_top_self();
#{objs_data[0][1]}(self, 0);
}
catch (...) {
rb_vm_print_current_exception();
rb_exit(1);
}
rb_exit(0);
}
EOS
# Prepare objects.
objs = []
objs_data.each { |o, _| objs << o }
# Compile main file.
main = gen_tmpfile('main', 'mm')
File.open(main, 'w') { |io| io.write(main_txt) }
main_o = gen_tmpfile('main', 'o')
execute("#{@gcxx} \"#{main}\" -c #{arch_flags} -o \"#{main_o}\" -fobjc-gc")
objs.unshift(main_o)
# Link all objects into executable.
linkf = @static ?
"-L#{RbConfig::CONFIG['libdir']} #{RbConfig::CONFIG['LIBRUBYARG_STATIC_REALLY']}" :
"-framework MacRuby -lobjc"
line = "#{@gcxx} -o \"#{output}\" #{arch_flags} #{linkf} "
objs.each { |o| line << " \"#{o}\"" }
execute(line)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment