diff --git a/Rakefile b/Rakefile index 4422f9688..5d8ba4945 100644 --- a/Rakefile +++ b/Rakefile @@ -17,6 +17,11 @@ require "mruby/build" MRUBY_CONFIG = MRuby::Build.mruby_config_path load MRUBY_CONFIG +# set up all gems +MRuby.each_target do + gems.setup(self) if enable_gems? +end + # load basic rules MRuby.each_target do |build| build.define_rules diff --git a/doc/guides/mrbgems.md b/doc/guides/mrbgems.md index 5c63ffb71..d7104821e 100644 --- a/doc/guides/mrbgems.md +++ b/doc/guides/mrbgems.md @@ -310,6 +310,28 @@ For example: when B depends on C and A depends on B, A will get include paths ex Exported `include_paths` are automatically appended to GEM local `include_paths` by rake. You can use `spec.export_include_paths` accessor if you want more complex build. +### Settings for GEM build commands/tasks + +When the block argument passed to `MRuby::Gem::Specification.new` is executed, +the GEM build commands/tasks for the `MRuby::Build` instance may not yet be finalized. +In most cases, modifying the GEM build commands/tasks within the block passed to +`MRuby::Gem::Specification.new` is not a problem. + +However, you may need to perform GEM build commands/tasks after the GEM build +commands/tasks for the `MRuby::Build` instance have been finalized. +In such cases, you can achieve this by passing a block argument to +`MRuby::Gem::Specification#build_settings` within the block passed to +`MRuby::Gem::Specification.new`. + +```ruby +spec.build_settings do + spec.cc.flags << "-any_flags" +end +``` + +**NOTE**: Using the `build_settings` method will cause GEM's all build command settings +directly written in the block passed to `MRuby::Gem::Specification.new` to be ignored. + ## C Extension mruby can be extended with C. This is possible by using the C API to diff --git a/lib/mruby/gem.rb b/lib/mruby/gem.rb index 619621e7b..1e9a3d919 100644 --- a/lib/mruby/gem.rb +++ b/lib/mruby/gem.rb @@ -53,10 +53,8 @@ module MRuby return if defined?(@bins) # return if already set up MRuby::Gem.current = self - MRuby::Build::COMMANDS.each do |command| - instance_variable_set("@#{command}", @build.send(command).clone) - end - @linker.run_attrs.each(&:clear) + reset_commands # for backward compatibility, reset the commands from the beginning. + @build_settings = nil @rbfiles = Dir.glob("#{@dir}/mrblib/**/*.rb").sort @objs = srcs_to_objs("src") @@ -192,6 +190,19 @@ module MRuby end end + def build_settings(&blk) + @build_settings = blk + end + + def setup_build + if @build_settings + # by this point, build.cc or other commands may have been modified. + # therefore, reset the commands again before calling build_settings. + reset_commands + @build_settings.call(self) + end + end + def define_gem_init_builder file "#{build_dir}/gem_init.c" => [build.mrbcfile, __FILE__] + [rbfiles].flatten do |t| mkdir_p build_dir @@ -303,6 +314,13 @@ module MRuby self end + + private def reset_commands + MRuby::Build::COMMANDS.each do |command| + instance_variable_set("@#{command}", @build.send(command).clone) + end + @linker.run_attrs.each(&:clear) + end end # Specification class Version @@ -401,7 +419,21 @@ module MRuby end end - def generate_gem_table build + def setup(build) + gemset = nil + begin + gemset_prev = gemset + self.each(&:setup) + gemset = self.setup_dependencies(build).keys.sort + end until gemset == gemset_prev + end + + def setup_build + each(&:setup_build) + self + end + + def setup_dependencies(build) gem_table = each_with_object({}) { |spec, h| h[spec.name] = spec } default_gems = {} @@ -424,6 +456,12 @@ module MRuby end end + gem_table + end + + def generate_gem_table(build) + gem_table = setup_dependencies(build) + each do |g| g.dependencies.each do |dep| name = dep[:gem] diff --git a/mrbgems/mruby-compiler/mrbgem.rake b/mrbgems/mruby-compiler/mrbgem.rake index c5e1bd539..bd83c8bc4 100644 --- a/mrbgems/mruby-compiler/mrbgem.rake +++ b/mrbgems/mruby-compiler/mrbgem.rake @@ -3,15 +3,17 @@ MRuby::Gem::Specification.new 'mruby-compiler' do |spec| spec.author = 'mruby developers' spec.summary = 'mruby compiler library' - objs = %w[codegen y.tab].map do |name| - src = "#{dir}/core/#{name}.c" - if build.cxx_exception_enabled? - build.compile_as_cxx(src) - else - objfile(src.pathmap("#{build_dir}/core/%n")) + spec.build_settings do + objs = %w[codegen y.tab].map do |name| + src = "#{dir}/core/#{name}.c" + if build.cxx_exception_enabled? + build.compile_as_cxx(src) + else + objfile(src.pathmap("#{build_dir}/core/%n")) + end end + build.libmruby_core_objs << objs end - build.libmruby_core_objs << objs end dir = __dir__ diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index 272d476e6..55a49c61d 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -2,8 +2,7 @@ MRuby.each_target do active_gems_txt = "#{build_dir}/mrbgems/active_gems.txt" if enable_gems? - # set up all gems - gems.each(&:setup) + gems.setup_build gems.check self # loader all gems