diff --git a/lib/rscons/builders/library.rb b/lib/rscons/builders/library.rb index 4545325..328764b 100644 --- a/lib/rscons/builders/library.rb +++ b/lib/rscons/builders/library.rb @@ -2,6 +2,7 @@ module Rscons module Builders # A default Rscons builder that produces a static library archive. class Library < Builder + # Return default construction variables for the builder. # # @param env [Environment] The Environment using the builder. @@ -16,28 +17,36 @@ module Rscons } end + # Set up a build operation using this builder. + # + # @param options [Hash] Builder setup options. + # + # @return [Object] + # Any object that the builder author wishes to be saved and passed back + # in to the {#run} method. + def setup(options) + target, sources, env, vars = options.values_at(:target, :sources, :env, :vars) + suffixes = env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], vars) + # Register builders to build each source to an object file or library. + env.register_builds(target, sources, suffixes, vars) + end + # Run the builder to produce a build target. # - # @param target [String] Target file name. - # @param sources [Array] Source file name(s). - # @param cache [Cache] The Cache object. - # @param env [Environment] The Environment executing the builder. - # @param vars [Hash,VarSet] Extra construction variables. + # @param options [Hash] Builder run options. # # @return [String,false] # Name of the target file on success or false on failure. - def run(target, sources, cache, env, vars) - # build sources to linkable objects - objects = env.build_sources(sources, env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], vars).flatten, cache, vars) - if objects - vars = vars.merge({ - '_TARGET' => target, - '_SOURCES' => objects, - }) - command = env.build_command("${ARCMD}", vars) - standard_build("AR #{target}", target, command, objects, env, cache) - end + def run(options) + target, sources, cache, env, vars, objects = options.values_at(:target, :sources, :cache, :env, :vars, :setup_info) + vars = vars.merge({ + '_TARGET' => target, + '_SOURCES' => objects, + }) + command = env.build_command("${ARCMD}", vars) + standard_build("AR #{target}", target, command, objects, env, cache) end + end end end diff --git a/lib/rscons/builders/object.rb b/lib/rscons/builders/object.rb index d755cf8..b9229b2 100644 --- a/lib/rscons/builders/object.rb +++ b/lib/rscons/builders/object.rb @@ -3,6 +3,7 @@ module Rscons # A default Rscons builder which knows how to produce an object file from # various types of source files. class Object < Builder + # Mapping of known sources from which to build object files. KNOWN_SUFFIXES = { "AS" => "ASSUFFIX", @@ -76,15 +77,12 @@ module Rscons # Run the builder to produce a build target. # - # @param target [String] Target file name. - # @param sources [Array] Source file name(s). - # @param cache [Cache] The Cache object. - # @param env [Environment] The Environment executing the builder. - # @param vars [Hash,VarSet] Extra construction variables. + # @param options [Hash] Builder run options. # - # @return [String,false] - # Name of the target file on success or false on failure. - def run(target, sources, cache, env, vars) + # @return [ThreadedCommand] + # Threaded command to execute. + def run(options) + target, sources, cache, env, vars = options.values_at(:target, :sources, :cache, :env, :vars) vars = vars.merge({ '_TARGET' => target, '_SOURCES' => sources, @@ -96,19 +94,36 @@ module Rscons v.nil? and raise "Error: unknown input file type: #{sources.first.inspect}" end.first command = env.build_command("${#{com_prefix}CMD}", vars) - unless cache.up_to_date?(target, command, sources, env) + if cache.up_to_date?(target, command, sources, env) + target + else cache.mkdir_p(File.dirname(target)) FileUtils.rm_f(target) - return false unless env.execute("#{com_prefix} #{target}", command) - deps = sources + ThreadedCommand.new( + command, + short_description: "#{com_prefix} #{target}", + builder_info: options.merge(vars: vars, command: command)) + end + end + + # Finalize the build operation. + # + # @param options [Hash] Builder finalize options. + # + # @return [String,nil] + # Name of the target file on success or nil on failure. + def finalize(options) + if options[:command_status] + target, deps, cache, env, vars, command = options[:builder_info].values_at(:target, :sources, :cache, :env, :vars, :command) if File.exists?(vars['_DEPFILE']) deps += Environment.parse_makefile_deps(vars['_DEPFILE'], target) FileUtils.rm_f(vars['_DEPFILE']) end cache.register_build(target, command, deps.uniq, env) + target end - target end + end end end diff --git a/lib/rscons/builders/program.rb b/lib/rscons/builders/program.rb index 4785117..ce21c19 100644 --- a/lib/rscons/builders/program.rb +++ b/lib/rscons/builders/program.rb @@ -3,6 +3,7 @@ module Rscons # A default Rscons builder that knows how to link object files into an # executable program. class Program < Builder + # Return default construction variables for the builder. # # @param env [Environment] The Environment using the builder. @@ -45,20 +46,28 @@ module Rscons super(my_options) end + # Set up a build operation using this builder. + # + # @param options [Hash] Builder setup options. + # + # @return [Object] + # Any object that the builder author wishes to be saved and passed back + # in to the {#run} method. + def setup(options) + target, sources, env, vars = options.values_at(:target, :sources, :env, :vars) + suffixes = env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], vars) + # Register builders to build each source to an object file or library. + env.register_builds(target, sources, suffixes, vars) + end + # Run the builder to produce a build target. # - # @param target [String] Target file name. - # @param sources [Array] Source file name(s). - # @param cache [Cache] The Cache object. - # @param env [Environment] The Environment executing the builder. - # @param vars [Hash,VarSet] Extra construction variables. + # @param options [Hash] Builder run options. # # @return [String,false] # Name of the target file on success or false on failure. - def run(target, sources, cache, env, vars) - # build sources to linkable objects - objects = env.build_sources(sources, env.expand_varref(["${OBJSUFFIX}", "${LIBSUFFIX}"], vars).flatten, cache, vars) - return false unless objects + def run(options) + target, sources, cache, env, vars, objects = options.values_at(:target, :sources, :cache, :env, :vars, :setup_info) ld = env.expand_varref("${LD}", vars) ld = if ld != "" ld @@ -77,6 +86,7 @@ module Rscons command = env.build_command("${LDCMD}", vars) standard_build("LD #{target}", target, command, objects, env, cache) end + end end end diff --git a/spec/build_tests_spec.rb b/spec/build_tests_spec.rb index ce2a91c..44a3a5f 100644 --- a/spec/build_tests_spec.rb +++ b/spec/build_tests_spec.rb @@ -806,28 +806,27 @@ EOF end expect do Rscons::Environment.new do |env| - env.Program("simple", %w[simple.c two.c]) + env.Program("simple.exe", %w[simple.c two.c]) end - end.to raise_error /Failed to build simple/ + end.to raise_error /Failed to build two\.o/ result = lines - expect(result.size).to be > 2 - expect(result[0, 2]).to eq [ + expect(Set[*result]).to eq Set[ "CC simple.o", "CC two.o", ] expect(File.exists?("simple.o")).to be_truthy expect(File.exists?("two.o")).to be_falsey - expect(File.exists?("two_sources#{Rscons::Environment.new["PROGSUFFIX"]}")).to be_falsey + expect(File.exists?("simple.exe")).to be_falsey Rscons::Cache.reset! File.open("two.c", "w") {|fh|} Rscons::Environment.new do |env| - env.Program("simple", %w[simple.c two.c]) + env.Program("simple.exe", %w[simple.c two.c]) end expect(lines).to eq [ "CC two.o", - "LD simple", + "LD simple.exe", ] end