diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb index e6298d71f..dfe944d35 100644 --- a/lib/mruby/build.rb +++ b/lib/mruby/build.rb @@ -1,6 +1,7 @@ require "mruby/core_ext" require "mruby/build/load_gems" require "mruby/build/command" +autoload :Find, "find" module MRuby autoload :Gem, "mruby/gem" @@ -487,6 +488,20 @@ EOS @internal end + def each_header_files(&block) + return to_enum(__method__) unless block + + basedir = File.join(MRUBY_ROOT, "include") + Find.find(basedir) do |d| + next unless File.file? d + yield d + end + + @gems.each { |g| g.each_header_files(&block) } + + self + end + protected attr_writer :presym diff --git a/lib/mruby/core_ext.rb b/lib/mruby/core_ext.rb index 1ad528c26..ac2737643 100644 --- a/lib/mruby/core_ext.rb +++ b/lib/mruby/core_ext.rb @@ -22,6 +22,27 @@ class String def remove_leading_parents Pathname.new(".#{Pathname.new("/#{self}").cleanpath}").cleanpath.to_s end + + def replace_prefix_by(dirmap) + [self].replace_prefix_by(dirmap)[0] + end +end + +class Array + # Replace the prefix of each string that is a file path that contains in its own array. + # + # dirmap is a hash whose elements are `{ "path/to/old-prefix" => "path/to/new-prefix", ... }`. + # If it does not match any element of dirmap, the file path is not replaced. + def replace_prefix_by(dirmap) + dirmap = dirmap.map { |older, newer| [File.join(older, "/"), File.join(newer, "/")] } + dirmap.sort! + dirmap.reverse! + self.flatten.map do |e| + map = dirmap.find { |older, newer| e.start_with?(older) } + e = e.sub(map[0], map[1]) if map + e + end + end end def install_D(src, dst) diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 64c6f3dee..4cbe4e696 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -292,6 +292,19 @@ module MRuby end end.all? end + + def each_header_files(&block) + return to_enum(__method__) unless block + + self.export_include_paths.flatten.uniq.compact.each do |dir| + Find.find(dir) do |d| + next unless File.file? d + yield d + end + end + + self + end end # Specification class Version diff --git a/tasks/libmruby.rake b/tasks/libmruby.rake index 1fb3cbc31..3f357c921 100644 --- a/tasks/libmruby.rake +++ b/tasks/libmruby.rake @@ -8,9 +8,33 @@ MRuby.each_target do next unless libmruby_enabled? file libmruby_static => libmruby_objs.flatten do |t| + Rake::Task["expose_header_files"].invoke archiver.run t.name, t.prerequisites end + task "expose_header_files" do |t| + # Since header files may be generated dynamically and it is hard to know all of them, + # the task is executed depending on when libmruby.a is generated. + + gemsbasedir = File.join(build_dir, "include/mruby/gems") + dirmap = { + MRUBY_ROOT => build_dir + } + gems.each { |g| + dirmap[g.dir] = File.join(gemsbasedir, g.name) + dirmap[g.build_dir] = File.join(gemsbasedir, g.name) + } + + dirs = each_header_files.to_a + dirs.uniq! + dirs.replace_prefix_by(dirmap).zip(dirs).each do |dest, src| + if File.mtime(src).to_i > (File.mtime(dest).to_i rescue 0) + mkpath File.dirname(dest) + cp src, dest + end + end + end + file "#{build_dir}/lib/libmruby.flags.mak" => [__FILE__, libmruby_static] do |t| mkdir_p File.dirname t.name open(t.name, 'w') do |f|