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)



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/rscons/environment.rb', line 45

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:



434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/rscons/environment.rb', line 434

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.



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

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.



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

def builders
  @builders
end

#echoSymbol

Returns :command, :short, or :off.

Returns:

  • (Symbol)

    :command, :short, or :off



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

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.



873
874
875
# File 'lib/rscons/environment.rb', line 873

def n_threads
  @n_threads || Rscons.n_threads
end

Instance Method Details

#[](*args) ⇒ Object

Get a construction variable’s value.

See Also:



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

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

#[]=(*args) ⇒ Object

Set a construction variable’s value.

See Also:



286
287
288
# File 'lib/rscons/environment.rb', line 286

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.



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

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



155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/rscons/environment.rb', line 155

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



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

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.



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

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



493
494
495
496
497
498
499
500
501
502
503
504
# File 'lib/rscons/environment.rb', line 493

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.



228
229
230
231
232
233
# File 'lib/rscons/environment.rb', line 228

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



551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
# File 'lib/rscons/environment.rb', line 551

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.



382
383
384
# File 'lib/rscons/environment.rb', line 382

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:



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
129
# File 'lib/rscons/environment.rb', line 92

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.



460
461
462
463
464
465
466
# File 'lib/rscons/environment.rb', line 460

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.



860
861
862
863
864
865
866
# File 'lib/rscons/environment.rb', line 860

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().



415
416
417
418
419
420
421
422
423
424
# File 'lib/rscons/environment.rb', line 415

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



698
699
700
701
702
703
704
705
706
707
708
# File 'lib/rscons/environment.rb', line 698

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.



394
395
396
397
398
399
400
401
402
# File 'lib/rscons/environment.rb', line 394

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.



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/rscons/environment.rb', line 251

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.



533
534
535
# File 'lib/rscons/environment.rb', line 533

def get_user_deps(target)
  @user_deps[target]
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.



849
850
851
852
853
854
855
856
857
# File 'lib/rscons/environment.rb', line 849

def merge_flags(flags)
  flags.each_pair do |key, val|
    if self[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.



754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
# File 'lib/rscons/environment.rb', line 754

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 =~ /^#{self["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 =~ /^#{self["INCPREFIX"]}(.*)$/
      handle["CPPPATH", $1]
    elsif word =~ /^#{self["LIBLINKPREFIX"]}(.*)$/
      handle["LIBS", $1]
    elsif word =~ /^#{self["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.



754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
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
# File 'lib/rscons/environment.rb', line 754

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 =~ /^#{self["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 =~ /^#{self["INCPREFIX"]}(.*)$/
      handle["CPPPATH", $1]
    elsif word =~ /^#{self["LIBLINKPREFIX"]}(.*)$/
      handle["LIBS", $1]
    elsif word =~ /^#{self["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.



885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
# File 'lib/rscons/environment.rb', line 885

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.



907
908
909
# File 'lib/rscons/environment.rb', line 907

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.



305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
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
# File 'lib/rscons/environment.rb', line 305

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



517
518
519
520
521
522
523
524
# File 'lib/rscons/environment.rb', line 517

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



596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
# File 'lib/rscons/environment.rb', line 596

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.



636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
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
# File 'lib/rscons/environment.rb', line 636

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.



720
721
722
723
724
725
726
727
728
729
730
731
# File 'lib/rscons/environment.rb', line 720

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