lib/rscons/environment.rb in rscons-1.6.1 vs lib/rscons/environment.rb in rscons-1.7.0

- old
+ new

@@ -5,11 +5,11 @@ module Rscons # The Environment class is the main programmatic interface to Rscons. It # contains a collection of construction variables, options, builders, and # rules for building targets. class Environment - # @return [Hash] Set of \{"builder_name" => builder_object} pairs. + # @return [Hash] Set of !{"builder_name" => builder_object} pairs. attr_reader :builders # :command, :short, or :off attr_accessor :echo @@ -40,11 +40,11 @@ @varset = VarSet.new @targets = {} @user_deps = {} @builders = {} @build_dirs = [] - @build_hooks = [] + @build_hooks = {pre: [], post: []} unless options[:exclude_builders] DEFAULT_BUILDERS.each do |builder_class_name| builder_class = Builders.const_get(builder_class_name) builder_class or raise "Could not find builder class #{builder_class_name}" add_builder(builder_class.new) @@ -101,13 +101,16 @@ @build_dirs.each do |src_dir, obj_dir| env.build_dir(src_dir, obj_dir) end end if clone.include?(:build_hooks) - @build_hooks.each do |build_hook_block| + @build_hooks[:pre].each do |build_hook_block| env.add_build_hook(&build_hook_block) end + @build_hooks[:post].each do |build_hook_block| + env.add_post_build_hook(&build_hook_block) + end end if block_given? yield env env.process @@ -130,10 +133,16 @@ end end # Add a build hook to the Environment. # + # Build hooks are Ruby blocks which are invoked immediately before a + # build operation takes place. Build hooks have an opportunity to modify + # the construction variables in use for the build operation based on the + # builder in use, target file name, or sources. Build hooks can also + # register new build targets. + # # @yield [build_op] # Invoke the given block with the current build operation. # @yieldparam build_op [Hash] # Hash with keys: # - :builder - The builder object in use. @@ -142,23 +151,49 @@ # - :vars - Set of construction variable values in use. # - :env - The Environment invoking the builder. # # @return [void] def add_build_hook(&block) - @build_hooks << block + @build_hooks[:pre] << block end + # Add a post build hook to the Environment. + # + # Post-build hooks are Ruby blocks which are invoked immediately after a + # build operation takes place. Post-build hooks are only invoked if the + # build operation succeeded. Post-build hooks can register new build + # targets. + # + # @since 1.7.0 + # + # @yield [build_op] + # Invoke the given block with the current build operation. + # @yieldparam build_op [Hash] + # Hash with keys: + # - :builder - The builder object in use. + # - :target - Target file name. + # - :sources - List of source file(s). + # - :vars - Set of construction variable values in use. + # - :env - The Environment invoking the builder. + # + # @return [void] + def add_post_build_hook(&block) + @build_hooks[:post] << block + end + # Specify a build directory for this Environment. # # Source files from src_dir will produce object files under obj_dir. # - # @param src_dir [String] Path to the source directory. + # @param src_dir [String, Regexp] Path to the source directory. # @param obj_dir [String] Path to the object directory. # # @return [void] def build_dir(src_dir, obj_dir) - src_dir = src_dir.gsub('\\', '/') if src_dir.is_a?(String) + if src_dir.is_a?(String) + src_dir = src_dir.gsub("\\", "/").sub(%r{/*$}, "") + end @build_dirs << [src_dir, obj_dir] end # Return the file name to be built from +source_fname+ with suffix # +suffix+. @@ -214,35 +249,37 @@ # When a block is passed to Environment.new, this method is automatically # called after the block returns. # # @return [void] def process - unless @targets.empty? - expand_paths! + expand_paths! + while @targets.size > 0 + targets = @targets + @targets = {} cache = Cache.instance cache.clear_checksum_cache! targets_processed = {} process_target = proc do |target| targets_processed[target] ||= begin - @targets[target][:sources].each do |src| - if @targets.include?(src) and not targets_processed.include?(src) + targets[target][:sources].each do |src| + if targets.include?(src) and not targets_processed.include?(src) process_target.call(src) end end - result = run_builder(@targets[target][:builder], + result = run_builder(targets[target][:builder], target, - @targets[target][:sources], + targets[target][:sources], cache, - @targets[target][:vars] || {}) + targets[target][:vars] || {}) unless result raise BuildError.new("Failed to build #{target}") end result end end begin - @targets.each do |target, target_params| + targets.each do |target, target_params| process_target.call(target) end ensure cache.write end @@ -408,20 +445,25 @@ # @param vars [Hash] Extra variables to pass to the builder. # # @return [String,false] Return value from the {Builder}'s +run+ method. def run_builder(builder, target, sources, cache, vars) vars = @varset.merge(vars) - @build_hooks.each do |build_hook_block| - build_operation = { - builder: builder, - target: target, - sources: sources, - vars: vars, - env: self, - } - build_hook_block.call(build_operation) + call_build_hooks = lambda do |sec| + @build_hooks[sec].each do |build_hook_block| + build_operation = { + builder: builder, + target: target, + sources: sources, + vars: vars, + env: self, + } + build_hook_block.call(build_operation) + end end - builder.run(target, sources, cache, self, vars) + call_build_hooks[:pre] + rv = builder.run(target, sources, cache, self, vars) + call_build_hooks[:post] if rv + rv end # Expand a path to be relative to the Environment's build root. # # Paths beginning with "^/" are expanded by replacing "^" with the