MRuby.each_target do active_gems_txt = "#{build_dir}/mrbgems/active_gems.txt" if enable_gems? # set up all gems gems.each(&:setup) gems.check self # loader all gems self.libmruby_objs << objfile("#{build_dir}/mrbgems/gem_init") file objfile("#{build_dir}/mrbgems/gem_init") => ["#{build_dir}/mrbgems/gem_init.c", "#{build_dir}/LEGAL"] file "#{build_dir}/mrbgems/gem_init.c" => [active_gems_txt, MRUBY_CONFIG, __FILE__] do |t| mkdir_p "#{build_dir}/mrbgems" open(t.name, 'w') do |f| gem_func_gems = gems.select { |g| g.generate_functions } gem_func_decls = '' gem_funcs = '' gem_func_gems.each do |g| init = "GENERATED_TMP_mrb_#{g.funcname}_gem_init" final = "GENERATED_TMP_mrb_#{g.funcname}_gem_final" gem_func_decls << "void #{init}(mrb_state*);\n" \ "void #{final}(mrb_state*);\n" gem_funcs << " { #{init}, #{final} },\n" end f.puts %Q[/*] f.puts %Q[ * This file contains a list of all] f.puts %Q[ * initializing methods which are] f.puts %Q[ * necessary to bootstrap all gems.] f.puts %Q[ *] f.puts %Q[ * This file was generated by mruby/#{__FILE__.relative_path_from(MRUBY_ROOT)}.] f.puts %Q[ *] f.puts %Q[ * IMPORTANT:] f.puts %Q[ * This file was generated!] f.puts %Q[ * All manual changes will get lost.] f.puts %Q[ */] f.puts %Q[] f.puts %Q[#include ] f.puts %Q[#include ] f.puts %Q[#include ] f.puts %Q[] unless gem_funcs.empty? f.write gem_func_decls f.puts %Q[] f.puts %Q[static const struct {] f.puts %Q[ void (*init)(mrb_state*);] f.puts %Q[ void (*final)(mrb_state*);] f.puts %Q[} gem_funcs[] = {] f.write gem_funcs f.puts %Q[};] f.puts %Q[] f.puts %Q[#define NUM_GEMS ((int)(sizeof(gem_funcs) / sizeof(gem_funcs[0])))] f.puts %Q[] f.puts %Q[struct final_mrbgems {] f.puts %Q[ int i;] f.puts %Q[ int ai;] f.puts %Q[};] f.puts %Q[] f.puts %Q[static mrb_value] f.puts %Q[final_mrbgems_body(mrb_state *mrb, void *ud) {] f.puts %Q[ struct final_mrbgems *p = (struct final_mrbgems*)ud;] f.puts %Q[ for (; p->i >= 0; p->i--) {] f.puts %Q[ gem_funcs[p->i].final(mrb);] f.puts %Q[ mrb_gc_arena_restore(mrb, p->ai);] f.puts %Q[ }] f.puts %Q[ return mrb_nil_value();] f.puts %Q[}] f.puts %Q[] f.puts %Q[static void] f.puts %Q[mrb_final_mrbgems(mrb_state *mrb) {] f.puts %Q[ struct final_mrbgems a = { NUM_GEMS - 1, mrb_gc_arena_save(mrb) };] f.puts %Q[ for (; a.i >= 0; a.i--) {] f.puts %Q[ mrb_protect_error(mrb, final_mrbgems_body, &a, NULL);] f.puts %Q[ mrb_gc_arena_restore(mrb, a.ai);] f.puts %Q[ }] f.puts %Q[}] f.puts %Q[] end f.puts %Q[void] f.puts %Q[mrb_init_mrbgems(mrb_state *mrb) {] unless gem_funcs.empty? f.puts %Q[ int ai = mrb_gc_arena_save(mrb);] f.puts %Q[ for (int i = 0; i < NUM_GEMS; i++) {] f.puts %Q[ gem_funcs[i].init(mrb);] f.puts %Q[ mrb_gc_arena_restore(mrb, ai);] f.puts %Q[ mrb_vm_ci_env_clear(mrb, mrb->c->cibase);] f.puts %Q[ if (mrb->exc) {] f.puts %Q[ mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));] f.puts %Q[ }] f.puts %Q[ }] f.puts %Q[ mrb_state_atexit(mrb, mrb_final_mrbgems);] end f.puts %Q[}] end end end file active_gems_txt => :generate_active_gems_txt desc "generate the active gems text files" task :generate_active_gems_txt do |t| def t.timestamp; Time.at(0) end active_gems = gems.sort_by(&:name).inject(""){|s, g| s << "#{g.name}\n"} if !File.exist?(active_gems_txt) || File.read(active_gems_txt) != active_gems mkdir_p File.dirname(active_gems_txt) File.write(active_gems_txt, active_gems) end end # legal documents file "#{build_dir}/LEGAL" => [MRUBY_CONFIG, __FILE__] do |t| mkdir_p File.dirname t.name open(t.name, 'w+') do |f| f.puts <