class Rscons::Environment
The Environment
class is the main programmatic interface to Rscons
. It contains a collection of construction variables, options, builders, and rules for building targets.
Attributes
@return [String] The build root.
@return [Hash] Set of !{“builder_name” => builder_object} pairs.
@return [Symbol] :command, :short, or :off
@return [Integer]
The number of threads to use for this Environment. If nil (the default), the global Rscons.n_threads default value will be used.
Public Class Methods
Create an Environment
object.
@param options [Hash] @option options [Symbol] :echo
:command, :short, or :off (default :short)
@option options [String] :build_root
Build root directory (default "build")
@option options [Boolean] :exclude_builders
Whether to omit adding default builders (default false)
If a block is given, the Environment
object is yielded to the block and when the block returns, the {#process} method is automatically called.
# File lib/rscons/environment.rb, line 44 def initialize(options = {}) @threaded_commands = Set.new @registered_build_dependencies = {} @side_effects = {} @varset = VarSet.new @job_set = JobSet.new(@registered_build_dependencies, @side_effects) @user_deps = {} @builders = {} @build_dirs = [] @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) end end @echo = options[:echo] || :short @build_root = options[:build_root] || "build" if block_given? yield self self.process end end
Private Class Methods
Parse dependencies from a Makefile.
This method is used internally by Rscons
builders.
@param mf_fname [String] File name of the Makefile to read.
@return [Array<String>] Paths of dependency files.
# File lib/rscons/environment.rb, line 1090 def self.parse_makefile_deps(mf_fname) deps = [] buildup = '' File.read(mf_fname).each_line do |line| if line =~ /^(.*)\\\s*$/ buildup += ' ' + $1 else buildup += ' ' + line if buildup =~ /^.*: (.*)$/ mf_deps = $1 deps += mf_deps.split(' ').map(&:strip) end buildup = '' end end deps end
Public Instance Methods
Get a construction variable's value.
@see VarSet#[]
# File lib/rscons/environment.rb, line 278 def [](*args) @varset.send(:[], *args) end
Set a construction variable's value.
@see VarSet#[]=
# File lib/rscons/environment.rb, line 303 def []=(*args) @varset.send(:[]=, *args) 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. - :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]
# File lib/rscons/environment.rb, line 186 def add_build_hook(&block) @build_hooks[:pre] << block end
Add a {Builder} object to the Environment
.
@overload add_builder
(builder)
Add the given builder to the Environment. @param builder [Builder] An instance of the builder to register.
@overload add_builder
(builder,&action)
Create a new {Builders::SimpleBuilder} instance and add it to the environment. @since 1.8.0 @param builder [String,Symbol] The name of the builder to add. @param action [Block] A block that will be called when the builder is executed to generate a target file. The provided block should have the same prototype as {Rscons::Builder#run}.
@return [void]
# File lib/rscons/environment.rb, line 154 def add_builder(builder, &action) if not builder.is_a? Rscons::Builder builder = Rscons::Builders::SimpleBuilder.new(builder, &action) end @builders[builder.name] = builder var_defs = builder.default_variables(self) if var_defs var_defs.each_pair do |var, val| @varset[var] ||= val end end 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]
# File lib/rscons/environment.rb, line 210 def add_post_build_hook(&block) @build_hooks[:post] << block end
Add a set of construction variables to the Environment
.
@param values [VarSet, Hash] New set of variables.
@return [void]
# File lib/rscons/environment.rb, line 312 def append(values) @varset.append(values) end
Manually record the given target(s) as needing to be built after the given prerequisite(s).
For example, consider a builder registered to generate gen.c which also generates gen.h as a side-effect. If program.c includes gen.h, then it should not be compiled before gen.h has been generated. When using multiple threads to build, Rscons
may attempt to compile program.c before gen.h has been generated because it does not know that gen.h will be generated along with gen.c. One way to prevent that situation would be to first process the Environment
with just the code-generation builders in place and then register the compilation builders. Another way is to use this method to record that a certain target should not be built until another has completed. For example, for the situation previously described:
env.build_after("program.o", "gen.c")
@since 1.10.0
@param targets [String, Array<String>]
Target files to wait to build until the prerequisites are finished building.
@param prerequisites [String, Array<String>]
Files that must be built before building the specified targets.
@return [void]
# File lib/rscons/environment.rb, line 511 def build_after(targets, prerequisites) targets = Array(targets) prerequisites = Array(prerequisites) targets.each do |target| target = expand_path(expand_varref(target)) @registered_build_dependencies[target] ||= Set.new prerequisites.each do |prerequisite| prerequisite = expand_path(expand_varref(prerequisite)) @registered_build_dependencies[target] << prerequisite end end end
Specify a build directory for this Environment
.
Source files from src_dir will produce object files under obj_dir.
@param src_dir [String, Regexp]
Path to the source directory. If a Regexp is given, it will be matched to source file names.
@param obj_dir [String]
Path to the object directory. If a Regexp is given as src_dir, then obj_dir can contain backreferences to groups matched from the source file name.
@return [void]
# File lib/rscons/environment.rb, line 227 def build_dir(src_dir, obj_dir) if src_dir.is_a?(String) src_dir = src_dir.gsub("\\", "/").sub(%r{/*$}, "") end @build_dirs.unshift([src_dir, obj_dir]) end
Set the build root.
@param build_root
[String] The build root.
# File lib/rscons/environment.rb, line 27 def build_root=(build_root) raise "build_root must be non-nil" unless build_root @build_root = build_root.gsub("\\", "/") end
Build a list of source files into files containing one of the suffixes given by suffixes.
This method is used internally by Rscons
builders.
@deprecated Use {#register_builds} instead.
@param sources [Array<String>] List of source files to build. @param suffixes [Array<String>]
List of suffixes to try to convert source files into.
@param cache [Cache] The Cache
. @param vars [Hash] Extra variables to pass to the builder.
@return [Array<String>] List of the converted file name(s).
# File lib/rscons/environment.rb, line 569 def build_sources(sources, suffixes, cache, vars) sources.map do |source| if source.end_with?(*suffixes) source else converted = nil suffixes.each do |suffix| converted_fname = get_build_fname(source, suffix) if builder = find_builder_for(converted_fname, source, []) converted = run_builder(builder, converted_fname, [source], cache, vars) return nil unless converted break end end converted or raise "Could not find a builder to handle #{source.inspect}." end end end
Clear all targets registered for the Environment
.
@return [void]
# File lib/rscons/environment.rb, line 400 def clear_targets @job_set.clear! end
Make a copy of the Environment
object.
By default, a cloned environment will contain a copy of all environment options, construction variables, and builders, but not a copy of the targets, build hooks, build directories, or the build root.
Exactly which items are cloned are controllable via the optional :clone parameter, which can be :none, :all, or a set or array of any of the following:
-
:variables to clone construction variables (on by default)
-
:builders to clone the builders (on by default)
-
:build_root to clone the build root (on by default)
-
:build_dirs to clone the build directories (on by default)
-
:build_hooks to clone the build hooks (on by default)
If a block is given, the Environment
object is yielded to the block and when the block returns, the {#process} method is automatically called.
Any options that initialize receives can also be specified here.
@return [Environment] The newly created {Environment} object.
# File lib/rscons/environment.rb, line 91 def clone(options = {}) clone = options[:clone] || :all clone = Set[:variables, :builders, :build_root, :build_dirs, :build_hooks] if clone == :all clone = Set[] if clone == :none clone = Set.new(clone) if clone.is_a?(Array) clone.delete(:builders) if options[:exclude_builders] env = self.class.new( echo: options[:echo] || @echo, build_root: options[:build_root], exclude_builders: true) if clone.include?(:builders) @builders.each do |builder_name, builder| env.add_builder(builder) end end env.append(@varset) if clone.include?(:variables) env.build_root = @build_root if clone.include?(:build_root) if clone.include?(:build_dirs) @build_dirs.reverse.each do |src_dir, obj_dir| env.build_dir(src_dir, obj_dir) end end if clone.include?(:build_hooks) @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 env.instance_variable_set(:@n_threads, @n_threads) if block_given? yield env env.process end env end
Manually record a given target as depending on the specified files.
@param target [String,BuildTarget] Target file. @param user_deps [Array<String>] Dependency files.
@return [void]
# File lib/rscons/environment.rb, line 478 def depends(target, *user_deps) target = expand_varref(target.to_s) user_deps = user_deps.map {|ud| expand_varref(ud)} @user_deps[target] ||= [] @user_deps[target] = (@user_deps[target] + user_deps).uniq build_after(target, user_deps) end
Print the Environment's construction variables for debugging.
# File lib/rscons/environment.rb, line 878 def dump varset_hash = @varset.to_h varset_hash.keys.sort_by(&:to_s).each do |var| var_str = var.is_a?(Symbol) ? var.inspect : var Ansi.write($stdout, :cyan, var_str, :reset, " => #{varset_hash[var].inspect}\n") end end
Execute a builder command.
@param short_desc [String] Message to print if the Environment's echo
mode is set to :short
@param command [Array] The command to execute. @param options [Hash] Optional options, possible keys:
- :env - environment Hash to pass to Kernel#system. - :options - options Hash to pass to Kernel#system.
@return [true,false,nil] Return value from Kernel.system().
# File lib/rscons/environment.rb, line 433 def execute(short_desc, command, options = {}) print_builder_run_message(short_desc, command) env_args = options[:env] ? [options[:env]] : [] options_args = options[:options] ? [options[:options]] : [] system(*env_args, *Rscons.command_executer, *command, *options_args).tap do |result| unless result or @echo == :command print_failed_command(command) end end end
Expand a path to be relative to the Environment's build root.
Paths beginning with “^/” are expanded by replacing “^” with the Environment's build root.
@param path [String, Array<String>]
The path(s) to expand.
@return [String, Array<String>]
The expanded path(s).
# File lib/rscons/environment.rb, line 716 def expand_path(path) if Rscons.phony_target?(path) path elsif path.is_a?(Array) path.map do |path| expand_path(path) end else path.sub(%r{^\^(?=[\\/])}, @build_root).gsub("\\", "/") end end
Expand a construction variable reference.
@param varref [nil, String, Array, Proc, Symbol, TrueClass, FalseClass] Variable reference to expand. @param extra_vars [Hash, VarSet]
Extra variables to use in addition to (or replace) the Environment's construction variables when expanding the variable reference.
@return [nil, String, Array, Symbol, TrueClass, FalseClass] Expansion of the variable reference.
# File lib/rscons/environment.rb, line 412 def expand_varref(varref, extra_vars = nil) vars = if extra_vars.nil? @varset else @varset.merge(extra_vars) end lambda_args = [env: self, vars: vars] vars.expand_varref(varref, lambda_args) end
Return the file name to be built from source_fname
with suffix suffix
.
This method takes into account the Environment's build directories.
@param source_fname [String]
Source file name.
@param suffix [String]
Suffix, including "." if desired.
@param options [Hash]
Extra options.
@option options [Array<String>] :features
Builder features to be used for this build. See {#register_builds}.
@return [String]
The file name to be built from +source_fname+ with suffix +suffix+.
# File lib/rscons/environment.rb, line 250 def get_build_fname(source_fname, suffix, options = {}) build_fname = Rscons.set_suffix(source_fname, suffix).gsub('\\', '/') options[:features] ||= [] extra_path = options[:features].include?("shared") ? "/_shared" : "" found_match = @build_dirs.find do |src_dir, obj_dir| if src_dir.is_a?(Regexp) build_fname.sub!(src_dir, "#{obj_dir}#{extra_path}") else build_fname.sub!(%r{^#{src_dir}/}, "#{obj_dir}#{extra_path}/") end end unless found_match if Rscons.absolute_path?(build_fname) if build_fname =~ %r{^(\w):(.*)$} build_fname = "#{@build_root}#{extra_path}/_#{$1}#{$2}" else build_fname = "#{@build_root}#{extra_path}/_#{build_fname}" end elsif !build_fname.start_with?("#{@build_root}/") build_fname = "#{@build_root}#{extra_path}/#{build_fname}" end end build_fname.gsub('\\', '/') end
Return the list of user dependencies for a given target.
@param target [String] Target file name.
@return [Array<String>,nil]
List of user-specified dependencies for the target, or nil if none were specified.
# File lib/rscons/environment.rb, line 551 def get_user_deps(target) @user_deps[target] end
Access the value of a construction variable.
@since 1.18.0
This method is similar to []
but does not make a copy-on-access copy of the variable accessed. This means that the returned value is NOT safe to be modified by the caller. Thus the caller must guarantee that it does not modify the returned value.
@param key [String, Symbol]
The construction variable name.
@return [Object]
The construction variable's value.
# File lib/rscons/environment.rb, line 296 def get_var(key) @varset.get_var(key) end
Merge construction variable flags into this Environment's construction variables.
This method does the same thing as {#append}, except that Array values in flags
are appended to the end of Array construction variables instead of replacing their contents.
@param flags [Hash]
Set of construction variables to merge into the current Environment. This can be the value (or a modified version) returned by {#parse_flags}.
@return [void]
# File lib/rscons/environment.rb, line 867 def merge_flags(flags) flags.each_pair do |key, val| if self.get_var(key).is_a?(Array) and val.is_a?(Array) self[key] += val else self[key] = val end end end
Define a build target.
@param method [Symbol] Method name. @param args [Array] Method arguments.
@return [BuildTarget]
The {BuildTarget} object registered, if the method called is a {Builder}.
# File lib/rscons/environment.rb, line 452 def method_missing(method, *args) if @builders.has_key?(method.to_s) target, sources, vars, *rest = args vars ||= {} unless vars.is_a?(Hash) or vars.is_a?(VarSet) raise "Unexpected construction variable set: #{vars.inspect}" end builder = @builders[method.to_s] target = expand_path(expand_varref(target)) sources = Array(sources).map do |source| expand_path(expand_varref(source)) end.flatten build_target = builder.create_build_target(env: self, target: target, sources: sources, vars: vars) add_target(build_target.to_s, builder, sources, vars, rest) build_target else super end end
Get the number of threads to use for parallelized builds in this Environment
.
@return [Integer]
Number of threads to use for parallelized builds in this Environment.
# File lib/rscons/environment.rb, line 891 def n_threads @n_threads || Rscons.n_threads end
@!method parse_flags
(flags) @!method parse_flags
!(flags)
Parse command-line flags for compilation/linking options into separate construction variables.
For {#parse_flags}, the parsed construction variables are returned in a Hash instead of merging them directly to the Environment
. They can be merged with {#merge_flags}. The {#parse_flags!} version immediately merges the parsed flags as well.
Example:
# Import FreeType build options env.parse_flags!("!freetype-config --cflags --libs")
@param flags [String]
String containing the flags to parse, or if the flags string begins with "!", a shell command to execute using {#shell} to obtain the flags to parse.
@return [Hash] Set of construction variables to append.
# File lib/rscons/environment.rb, line 772 def parse_flags(flags) if flags =~ /^!(.*)$/ flags = shell($1) end rv = {} words = Shellwords.split(flags) skip = false words.each_with_index do |word, i| if skip skip = false next end append = lambda do |var, val| rv[var] ||= [] rv[var] += val end handle = lambda do |var, val| if val.nil? or val.empty? val = words[i + 1] skip = true end if val and not val.empty? append[var, [val]] end end if word == "-arch" if val = words[i + 1] append["CCFLAGS", ["-arch", val]] append["LDFLAGS", ["-arch", val]] end skip = true elsif word =~ /^#{get_var("CPPDEFPREFIX")}(.*)$/ handle["CPPDEFINES", $1] elsif word == "-include" if val = words[i + 1] append["CCFLAGS", ["-include", val]] end skip = true elsif word == "-isysroot" if val = words[i + 1] append["CCFLAGS", ["-isysroot", val]] append["LDFLAGS", ["-isysroot", val]] end skip = true elsif word =~ /^#{get_var("INCPREFIX")}(.*)$/ handle["CPPPATH", $1] elsif word =~ /^#{get_var("LIBLINKPREFIX")}(.*)$/ handle["LIBS", $1] elsif word =~ /^#{get_var("LIBDIRPREFIX")}(.*)$/ handle["LIBPATH", $1] elsif word == "-mno-cygwin" append["CCFLAGS", [word]] append["LDFLAGS", [word]] elsif word == "-mwindows" append["LDFLAGS", [word]] elsif word == "-pthread" append["CCFLAGS", [word]] append["LDFLAGS", [word]] elsif word =~ /^-Wa,(.*)$/ append["ASFLAGS", $1.split(",")] elsif word =~ /^-Wl,(.*)$/ append["LDFLAGS", $1.split(",")] elsif word =~ /^-Wp,(.*)$/ append["CPPFLAGS", $1.split(",")] elsif word.start_with?("-") append["CCFLAGS", [word]] elsif word.start_with?("+") append["CCFLAGS", [word]] append["LDFLAGS", [word]] else append["LIBS", [word]] end end rv end
# File lib/rscons/environment.rb, line 848 def parse_flags!(flags) flags = parse_flags(flags) merge_flags(flags) flags end
Print the builder run message, depending on the Environment's echo mode.
@param short_description [String]
Builder short description, printed if the echo mode is :short.
@param command [Array<String>]
Builder command, printed if the echo mode is :command.
@return [void]
# File lib/rscons/environment.rb, line 903 def print_builder_run_message(short_description, command) case @echo when :command if command.is_a?(Array) message = command_to_s(command) elsif command.is_a?(String) message = command elsif short_description.is_a?(String) message = short_description end when :short message = short_description if short_description end Ansi.write($stdout, :cyan, message, :reset, "\n") if message end
Print a failed command.
@param command [Array<String>]
Builder command.
@return [void]
# File lib/rscons/environment.rb, line 925 def print_failed_command(command) Ansi.write($stdout, :red, "Failed command was: #{command_to_s(command)}", :reset, "\n") end
Build all build targets specified in the Environment
.
When a block is passed to Environment.new
, this method is automatically called after the block returns.
@return [void]
# File lib/rscons/environment.rb, line 322 def process cache = Cache.instance failure = nil begin while @job_set.size > 0 or @threaded_commands.size > 0 if failure @job_set.clear! job = nil else targets_still_building = @threaded_commands.map do |tc| tc.build_operation[:target] end job = @job_set.get_next_job_to_run(targets_still_building) end # TODO: have Cache determine when checksums may be invalid based on # file size and/or timestamp. cache.clear_checksum_cache! if job validate_user_deps(job[:target], @user_deps[job[:target]], cache) result = run_builder(job[:builder], job[:target], job[:sources], cache, job[:vars], allow_delayed_execution: true, setup_info: job[:setup_info]) unless result failure = "Failed to build #{job[:target]}" Ansi.write($stderr, :red, failure, :reset, "\n") next end end completed_tcs = Set.new # First do a non-blocking wait to pick up any threads that have # completed since last time. while tc = wait_for_threaded_commands(nonblock: true) completed_tcs << tc end # If needed, do a blocking wait. if (@threaded_commands.size > 0) and ((completed_tcs.empty? and job.nil?) or (@threaded_commands.size >= n_threads)) completed_tcs << wait_for_threaded_commands end # Process all completed {ThreadedCommand} objects. completed_tcs.each do |tc| result = finalize_builder(tc) if result @build_hooks[:post].each do |build_hook_block| build_hook_block.call(tc.build_operation) end else unless @echo == :command print_failed_command(tc.command) end failure = "Failed to build #{tc.build_operation[:target]}" Ansi.write($stderr, :red, failure, :reset, "\n") break end end end ensure cache.write end if failure raise BuildError.new(failure) end end
Manually record the given side effect file(s) as being produced when the named target is produced.
@since 1.13.0
@param target [String]
Target of a build operation.
@param side_effects [Array<String>]
File(s) produced when the target file is produced.
@return [void]
# File lib/rscons/environment.rb, line 535 def produces(target, *side_effects) target = expand_path(expand_varref(target)) side_effects = Array(side_effects).map do |side_effect| expand_path(expand_varref(side_effect)) end.flatten @side_effects[target] ||= [] @side_effects[target] += side_effects end
Find and register builders to build source files into files containing one of the suffixes given by suffixes.
This method is used internally by Rscons
builders. It should be called from the builder's setup method.
@since 1.10.0
@param target [String]
The target that depends on these builds.
@param sources [Array<String>]
List of source file(s) to build.
@param suffixes [Array<String>]
List of suffixes to try to convert source files into.
@param vars [Hash]
Extra variables to pass to the builders.
@param options [Hash]
Extra options.
@option options [Array<String>] :features
Set of features the builder must provide. Each feature can be proceeded by a "-" character to indicate that the builder must /not/ provide the given feature. * shared - builder builds a shared object/library
@return [Array<String>]
List of the output file name(s).
# File lib/rscons/environment.rb, line 614 def register_builds(target, sources, suffixes, vars, options = {}) options[:features] ||= [] @registered_build_dependencies[target] ||= Set.new sources.map do |source| if source.end_with?(*suffixes) source else output_fname = nil suffixes.each do |suffix| attempt_output_fname = get_build_fname(source, suffix, features: options[:features]) if builder = find_builder_for(attempt_output_fname, source, options[:features]) output_fname = attempt_output_fname self.__send__(builder.name, output_fname, source, vars) @registered_build_dependencies[target] << output_fname break end end output_fname or raise "Could not find a builder for #{source.inspect}." end end end
Invoke a builder to build the given target based on the given sources.
@param builder [Builder] The Builder
to use. @param target [String] The target output file. @param sources [Array<String>] List of source files. @param cache [Cache] The Cache
. @param vars [Hash] Extra variables to pass to the builder. @param options [Hash]
@since 1.10.0 Options.
@option options [Boolean] :allow_delayed_execution
@since 1.10.0 Allow a threaded command to be scheduled but not yet completed before this method returns.
@option options [Object] :setup_info
Arbitrary builder info returned by Builder#setup.
@return [String,false] Return value from the {Builder}'s run
method.
# File lib/rscons/environment.rb, line 654 def run_builder(builder, target, sources, cache, vars, options = {}) vars = @varset.merge(vars) build_operation = { builder: builder, target: target, sources: sources, cache: cache, env: self, vars: vars, setup_info: options[:setup_info] } call_build_hooks = lambda do |sec| @build_hooks[sec].each do |build_hook_block| build_hook_block.call(build_operation) end end # Invoke pre-build hooks. call_build_hooks[:pre] # Call the builder's #run method. if builder.method(:run).arity == 5 rv = builder.run(*build_operation.values_at(:target, :sources, :cache, :env, :vars)) else rv = builder.run(build_operation) end if rv.is_a?(ThreadedCommand) # Store the build operation so the post-build hooks can be called # with it when the threaded command completes. rv.build_operation = build_operation start_threaded_command(rv) unless options[:allow_delayed_execution] # Delayed command execution is not allowed, so we need to execute # the command and finalize the builder now. tc = wait_for_threaded_commands(which: [rv]) rv = finalize_builder(tc) if rv call_build_hooks[:post] else unless @echo == :command print_failed_command(tc.command) end end end else call_build_hooks[:post] if rv end rv end
Execute a command using the system shell.
The shell is automatically determined but can be overridden by the SHELL construction variable. If the SHELL construction variable is specified, the flag to pass to the shell is automatically dtermined but can be overridden by the SHELLFLAG construction variable.
@param command [String] Command to execute.
@return [String] The command's standard output.
# File lib/rscons/environment.rb, line 738 def shell(command) shell_cmd = if self["SHELL"] flag = self["SHELLFLAG"] || (self["SHELL"] == "cmd" ? "/c" : "-c") [self["SHELL"], flag] else Rscons.get_system_shell end IO.popen([*shell_cmd, command]) do |io| io.read end end
Private Instance Methods
Add a build target.
@param target [String] Build target file name. @param builder [Builder] The {Builder} to use to build the target. @param sources [Array<String>] Source file name(s). @param vars [Hash] Construction variable overrides. @param args [Object] Deprecated; unused.
@return [void]
# File lib/rscons/environment.rb, line 940 def add_target(target, builder, sources, vars, args) setup_info = builder.setup( target: target, sources: sources, env: self, vars: vars) @job_set.add_job( builder: builder, target: target, sources: sources, vars: vars, setup_info: setup_info) end
Return a string representation of a command.
@param command [Array<String>]
The command.
@return [String]
The string representation of the command.
# File lib/rscons/environment.rb, line 1025 def command_to_s(command) command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ') end
Determine if a builder meets the requested features.
@param builder [Builder]
The builder.
@param features [Array<String>]
See {#register_builds}.
@return [Boolean]
Whether the builder meets the requested features.
# File lib/rscons/environment.rb, line 1070 def features_met?(builder, features) builder_features = builder.features features.all? do |feature| want_feature = true if feature =~ /^-(.*)$/ want_feature = false feature = $1 end builder_has_feature = builder_features.include?(feature) want_feature ? builder_has_feature : !builder_has_feature end end
Call a builder's finalize method after a ThreadedCommand
terminates.
@param tc [ThreadedCommand]
The ThreadedCommand returned from the builder's #run method.
@return [String, false]
Result of Builder#finalize.
# File lib/rscons/environment.rb, line 1036 def finalize_builder(tc) tc.build_operation[:builder].finalize( tc.build_operation.merge( command_status: tc.thread.value, tc: tc)) end
Find a builder that meets the requested features and produces a target of the requested name.
@param target [String]
Target file name.
@param source [String]
Source file name.
@param features [Array<String>]
See {#register_builds}.
@return [Builder, nil]
The builder found, if any.
# File lib/rscons/environment.rb, line 1055 def find_builder_for(target, source, features) @builders.values.find do |builder| features_met?(builder, features) and builder.produces?(target, source, self) end end
Check if any of the requested threads are finished.
@param threads [Array<Thread>]
The threads to check.
@param nonblock [Boolean]
Whether to be non-blocking. If true, nil will be returned if no thread is finished. If false, the method will wait until one of the threads is finished.
@return [Thread, nil]
The finished thread, if any.
# File lib/rscons/environment.rb, line 1008 def find_finished_thread(threads, nonblock) if nonblock threads.find do |thread| !thread.alive? end else Util.wait_for_thread(*threads) end end
Start a threaded command in a new thread.
@param tc [ThreadedCommand]
The ThreadedCommand to start.
@return [void]
# File lib/rscons/environment.rb, line 960 def start_threaded_command(tc) print_builder_run_message(tc.short_description, tc.command) env_args = tc.system_env ? [tc.system_env] : [] options_args = tc.system_options ? [tc.system_options] : [] system_args = [*env_args, *Rscons.command_executer, *tc.command, *options_args] tc.thread = Thread.new do system(*system_args) end @threaded_commands << tc end
Ensures that user dependencies exist with valid checksums in the cache. Raises an exception if any dependency is invalid.
@param target [String]
Target to be built
@param user_deps [Array<String>, nil]
User dependencies of the target
@param cache [Cache]
Rscons cache instance
@return [void]
# File lib/rscons/environment.rb, line 1119 def validate_user_deps(target, user_deps, cache) return if user_deps.nil? user_deps.each do |dep| if cache.lookup_checksum(dep) == "" raise "User dependency #{dep} of target #{target} is invalid" end end end
Wait for threaded commands to complete.
@param options [Hash]
Options.
@option options [Set<ThreadedCommand>, Array<ThreadedCommand>] :which
Which {ThreadedCommand} objects to wait for. If not specified, this method will wait for any.
@option options [Boolean] :nonblock
Set to true to not block.
@return [ThreadedCommand, nil]
The {ThreadedCommand} object that is finished.
# File lib/rscons/environment.rb, line 985 def wait_for_threaded_commands(options = {}) options[:which] ||= @threaded_commands threads = options[:which].map(&:thread) if finished_thread = find_finished_thread(threads, options[:nonblock]) threaded_command = @threaded_commands.find do |tc| tc.thread == finished_thread end @threaded_commands.delete(threaded_command) threaded_command end end