Class: Rscons::Environment

Inherits:
Object
  • Object
show all
Defined in:
lib/rscons/environment.rb

Overview

The Environment class is the main programmatic interface to Rscons. It contains a collection of construction variables, options, builders, and rules for building targets.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Environment

Create an Environment object.

If a block is given, the Environment object is yielded to the block and when the block returns, the #process method is automatically called.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :echo (Symbol)

    :command, :short, or :off (default :short)

  • :build_root (String)

    Build root directory (default “build”)

  • :exclude_builders (Boolean)

    Whether to omit adding default builders (default false)



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ BuildTarget

Define a build target.

Parameters:

  • method (Symbol)

    Method name.

  • args (Array)

    Method arguments.

Returns:



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
# 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

Instance Attribute Details

#build_rootString

Returns The build root.

Returns:

  • (String)

    The build root.



17
18
19
# File 'lib/rscons/environment.rb', line 17

def build_root
  @build_root
end

#buildersHash (readonly)

Returns Set of {“builder_name” => builder_object} pairs.

Returns:

  • (Hash)

    Set of {“builder_name” => builder_object} pairs.



11
12
13
# File 'lib/rscons/environment.rb', line 11

def builders
  @builders
end

#echoSymbol

Returns :command, :short, or :off.

Returns:

  • (Symbol)

    :command, :short, or :off



14
15
16
# File 'lib/rscons/environment.rb', line 14

def echo
  @echo
end

#n_threadsInteger

Get the number of threads to use for parallelized builds in this Environment.

Returns:

  • (Integer)

    Number of threads to use for parallelized builds in this Environment.



891
892
893
# File 'lib/rscons/environment.rb', line 891

def n_threads
  @n_threads || Rscons.n_threads
end

Instance Method Details

#[](*args) ⇒ Object

Get a construction variable’s value.

See Also:



278
279
280
# File 'lib/rscons/environment.rb', line 278

def [](*args)
  @varset.send(:[], *args)
end

#[]=(*args) ⇒ Object

Set a construction variable’s value.

See Also:



303
304
305
# File 'lib/rscons/environment.rb', line 303

def []=(*args)
  @varset.send(:[]=, *args)
end

#add_build_hook {|build_op| ... } ⇒ void

This method returns an undefined value.

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.

Yields:

  • (build_op)

    Invoke the given block with the current build operation.

Yield Parameters:

  • 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.



186
187
188
# File 'lib/rscons/environment.rb', line 186

def add_build_hook(&block)
  @build_hooks[:pre] << block
end

#add_builder(builder) ⇒ void #add_builder(builder, &action) ⇒ void

This method returns an undefined value.

Add a Builder object to the Environment.

Overloads:

  • #add_builder(builder) ⇒ void

    Add the given builder to the Environment.

    Parameters:

    • builder (Builder)

      An instance of the builder to register.

  • #add_builder(builder, &action) ⇒ void

    Create a new Builders::SimpleBuilder instance and add it to the environment.

    Parameters:

    • builder (String, Symbol)

      The name of the builder to add.

    • 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 Builder#run.

    Since:

    • 1.8.0



154
155
156
157
158
159
160
161
162
163
164
165
# 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_post_build_hook {|build_op| ... } ⇒ void

This method returns an undefined value.

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.

Yields:

  • (build_op)

    Invoke the given block with the current build operation.

Yield Parameters:

  • 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.

Since:

  • 1.7.0



210
211
212
# File 'lib/rscons/environment.rb', line 210

def add_post_build_hook(&block)
  @build_hooks[:post] << block
end

#append(values) ⇒ void

This method returns an undefined value.

Add a set of construction variables to the Environment.

Parameters:

  • values (VarSet, Hash)

    New set of variables.



312
313
314
# File 'lib/rscons/environment.rb', line 312

def append(values)
  @varset.append(values)
end

#build_after(targets, prerequisites) ⇒ void

This method returns an undefined value.

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")

Parameters:

  • targets (String, Array<String>)

    Target files to wait to build until the prerequisites are finished building.

  • prerequisites (String, Array<String>)

    Files that must be built before building the specified targets.

Since:

  • 1.10.0



511
512
513
514
515
516
517
518
519
520
521
522
# 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

#build_dir(src_dir, obj_dir) ⇒ void

This method returns an undefined value.

Specify a build directory for this Environment.

Source files from src_dir will produce object files under obj_dir.

Parameters:

  • src_dir (String, Regexp)

    Path to the source directory. If a Regexp is given, it will be matched to source file names.

  • 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.



227
228
229
230
231
232
# 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

#build_sources(sources, suffixes, cache, vars) ⇒ Array<String>

Deprecated.

Use #register_builds instead.

Build a list of source files into files containing one of the suffixes given by suffixes.

This method is used internally by Rscons builders.

Parameters:

  • sources (Array<String>)

    List of source files to build.

  • suffixes (Array<String>)

    List of suffixes to try to convert source files into.

  • cache (Cache)

    The Cache.

  • vars (Hash)

    Extra variables to pass to the builder.

Returns:

  • (Array<String>)

    List of the converted file name(s).



569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
# 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_targetsvoid

This method returns an undefined value.

Clear all targets registered for the Environment.



400
401
402
# File 'lib/rscons/environment.rb', line 400

def clear_targets
  @job_set.clear!
end

#clone(options = {}) ⇒ Environment

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.

Returns:



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# 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

#depends(target, *user_deps) ⇒ void

This method returns an undefined value.

Manually record a given target as depending on the specified files.

Parameters:

  • target (String, BuildTarget)

    Target file.

  • user_deps (Array<String>)

    Dependency files.



478
479
480
481
482
483
484
# 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

#dumpObject

Print the Environment’s construction variables for debugging.



878
879
880
881
882
883
884
# 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(short_desc, command, options = {}) ⇒ true, ...

Execute a builder command.

Parameters:

  • short_desc (String)

    Message to print if the Environment’s echo mode is set to :short

  • command (Array)

    The command to execute.

  • options (Hash) (defaults to: {})

    Optional options, possible keys:

    • :env - environment Hash to pass to Kernel#system.

    • :options - options Hash to pass to Kernel#system.

Returns:

  • (true, false, nil)

    Return value from Kernel.system().



433
434
435
436
437
438
439
440
441
442
# 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_path(path) ⇒ String+

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.

Parameters:

  • path (String, Array<String>)

    The path(s) to expand.

Returns:

  • (String, Array<String>)

    The expanded path(s).



716
717
718
719
720
721
722
723
724
725
726
# 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_varref(varref, extra_vars = nil) ⇒ nil, ... Also known as: build_command

Expand a construction variable reference.

Parameters:

  • varref (nil, String, Array, Proc, Symbol, TrueClass, FalseClass)

    Variable reference to expand.

  • extra_vars (Hash, VarSet) (defaults to: nil)

    Extra variables to use in addition to (or replace) the Environment’s construction variables when expanding the variable reference.

Returns:

  • (nil, String, Array, Symbol, TrueClass, FalseClass)

    Expansion of the variable reference.



412
413
414
415
416
417
418
419
420
# 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

#get_build_fname(source_fname, suffix, options = {}) ⇒ String

Return the file name to be built from source_fname with suffix suffix.

This method takes into account the Environment’s build directories.

Parameters:

  • source_fname (String)

    Source file name.

  • suffix (String)

    Suffix, including “.” if desired.

  • options (Hash) (defaults to: {})

    Extra options.

Options Hash (options):

  • :features (Array<String>)

    Builder features to be used for this build. See #register_builds.

Returns:

  • (String)

    The file name to be built from source_fname with suffix suffix.



250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# 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

#get_user_deps(target) ⇒ Array<String>?

Return the list of user dependencies for a given target.

Parameters:

  • target (String)

    Target file name.

Returns:

  • (Array<String>, nil)

    List of user-specified dependencies for the target, or nil if none were specified.



551
552
553
# File 'lib/rscons/environment.rb', line 551

def get_user_deps(target)
  @user_deps[target]
end

#get_var(key) ⇒ Object

Access the value of a construction variable.

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.

Parameters:

  • key (String, Symbol)

    The construction variable name.

Returns:

  • (Object)

    The construction variable’s value.

Since:

  • 1.18.0



296
297
298
# File 'lib/rscons/environment.rb', line 296

def get_var(key)
  @varset.get_var(key)
end

#merge_flags(flags) ⇒ void

This method returns an undefined value.

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.

Parameters:

  • 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.



867
868
869
870
871
872
873
874
875
# 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

#parse_flags(flags) ⇒ Hash

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")

Parameters:

  • 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.

Returns:

  • (Hash)

    Set of construction variables to append.



772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
# 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

#parse_flags!(flags) ⇒ Hash

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")

Parameters:

  • 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.

Returns:

  • (Hash)

    Set of construction variables to append.



772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
# 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

This method returns an undefined value.

Print the builder run message, depending on the Environment’s echo mode.

Parameters:

  • short_description (String)

    Builder short description, printed if the echo mode is :short.

  • command (Array<String>)

    Builder command, printed if the echo mode is :command.



903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
# 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

This method returns an undefined value.

Print a failed command.

Parameters:

  • command (Array<String>)

    Builder command.



925
926
927
# 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

#processvoid

This method returns an undefined value.

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.



322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# 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

#produces(target, *side_effects) ⇒ void

This method returns an undefined value.

Manually record the given side effect file(s) as being produced when the named target is produced.

Parameters:

  • target (String)

    Target of a build operation.

  • side_effects (Array<String>)

    File(s) produced when the target file is produced.

Since:

  • 1.13.0



535
536
537
538
539
540
541
542
# 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

#register_builds(target, sources, suffixes, vars, options = {}) ⇒ Array<String>

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.

Parameters:

  • target (String)

    The target that depends on these builds.

  • sources (Array<String>)

    List of source file(s) to build.

  • suffixes (Array<String>)

    List of suffixes to try to convert source files into.

  • vars (Hash)

    Extra variables to pass to the builders.

  • options (Hash) (defaults to: {})

    Extra options.

Options Hash (options):

  • :features (Array<String>)

    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

Returns:

  • (Array<String>)

    List of the output file name(s).

Since:

  • 1.10.0



614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
# 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

#run_builder(builder, target, sources, cache, vars, options = {}) ⇒ String, false

Invoke a builder to build the given target based on the given sources.

Parameters:

  • builder (Builder)

    The Builder to use.

  • target (String)

    The target output file.

  • sources (Array<String>)

    List of source files.

  • cache (Cache)

    The Cache.

  • vars (Hash)

    Extra variables to pass to the builder.

  • options (Hash) (defaults to: {})

    @since 1.10.0 Options.

Options Hash (options):

  • :allow_delayed_execution (Boolean)

    @since 1.10.0 Allow a threaded command to be scheduled but not yet completed before this method returns.

  • :setup_info (Object)

    Arbitrary builder info returned by Builder#setup.

Returns:

  • (String, false)

    Return value from the Builder‘s run method.



654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
# 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

#shell(command) ⇒ String

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.

Parameters:

  • command (String)

    Command to execute.

Returns:

  • (String)

    The command’s standard output.



738
739
740
741
742
743
744
745
746
747
748
749
# 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