Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e900e74342 | ||
|
|
62ae3f162d | ||
|
|
099d26f33c | ||
|
|
89562c584a | ||
|
|
a9aeaf2356 | ||
|
|
5409b3cb34 | ||
|
|
6d04500c13 | ||
|
|
45e30662d2 | ||
|
|
8f7e044bfd | ||
|
|
dbea6f0a26 | ||
|
|
c923eb5c7c | ||
|
|
529d9aacaa | ||
|
|
65c1bac4f9 | ||
|
|
775363ddbd | ||
|
|
2a96495e83 | ||
|
|
15e52e488c | ||
|
|
c0b12132f0 | ||
|
|
9141cf91e7 | ||
|
|
7f7e6ef3da | ||
|
|
60b3fdbcac | ||
|
|
5263ea03c6 | ||
|
|
6c91823ce2 | ||
|
|
8deb1eb6f8 | ||
|
|
6d6319799a | ||
|
|
694642dfbd | ||
|
|
6dd70ff65e | ||
|
|
eca01c38df | ||
|
|
4ad6ce1d9c | ||
|
|
a49ebc486e | ||
|
|
74d19ea235 | ||
|
|
d7a6d69a92 |
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
rscons (1.10.0)
|
||||
rscons (1.13.0)
|
||||
json (~> 1.0)
|
||||
|
||||
GEM
|
||||
|
||||
@@ -230,14 +230,15 @@ An Environment consists of:
|
||||
* a collection of user-defined build targets
|
||||
* a collection of user-defined build hooks
|
||||
|
||||
When cloning an environment, by default the construction variables and builders
|
||||
are cloned, but the new environment does not inherit any of the targets, build
|
||||
hooks, build directories, or the build root from the source environment.
|
||||
When cloning an environment, by default the construction variables, builders,
|
||||
build hooks, build directories, and build root are cloned, but the new
|
||||
environment does not inherit any of the registered build targets.
|
||||
|
||||
The set of environment attributes that are cloned is controllable via the
|
||||
`:clone` option to the `#clone` method.
|
||||
For example, `env.clone(clone: :all)` will include construction variables,
|
||||
builders, build hooks, build directories, and the build root.
|
||||
For example, `env.clone(clone: [:variables, :builders])` will include
|
||||
construction variables, and builders but not build hooks, build directories, or
|
||||
the build root.
|
||||
|
||||
The set of pending targets is never cloned.
|
||||
|
||||
@@ -455,16 +456,14 @@ construction variables can be overridden by the user.
|
||||
| LIBSUFFIX | String/Array | Default static library file suffix | ".a" |
|
||||
| OBJDUMP | String | Objdump executable | "objdump" |
|
||||
| OBJSUFFIX | String/Array | Default object file suffix | ".o" |
|
||||
| This name will include variant components. |
|
||||
| The user should not change this construction variable. | Determined at runtime. |
|
||||
| PROGSUFFIX | String | Default program suffix. | Windows: ".exe", POSIX: "" |
|
||||
| SHCC | String | Shared object C compiler | "${CC}" |
|
||||
| SHCCCMD | Array | Shared object C compiler command line | ["${SHCC}", "-c", "-o", "${_TARGET}", "${CCDEPGEN}", "${INCPREFIX}${CPPPATH}", "${CPPFLAGS}", "${SHCFLAGS}", "${SHCCFLAGS}", "${_SOURCES}"] |
|
||||
| SHCCFLAGS | Array | Shared object C and C++ compiler flags | Windows: ["${CCFLAGS}"], POSIX: ["${CCFLAGS}", -fPIC"] |
|
||||
| SHCFLAGS | Array | Shared object C compiler flags | [] |
|
||||
| SHCFLAGS | Array | Shared object C compiler flags | ["${CFLAGS}"] |
|
||||
| SHCXX | String | Shared object C++ compiler | "${CXX}" |
|
||||
| SHCXXCMD | Array | Shared object C++ compiler command line | ["${SHCXX}", "-c", "-o", "${_TARGET}", "${CXXDEPGEN}", "${INCPREFIX}${CPPPATH}", "${CPPFLAGS}", "${SHCXXFLAGS}", "${SHCCFLAGS}", "${_SOURCES}"] |
|
||||
| SHCXXFLAGS | Array | Shared object C++ compiler flags | [] |
|
||||
| SHCXXFLAGS | Array | Shared object C++ compiler flags | ["${CXXFLAGS}"] |
|
||||
| SHDC | String | Shared object D compiler | "gdc" |
|
||||
| SHDCCMD | Array | Shared object D compiler command line | ["${SHDC}", "-c", "-o", "${_TARGET}", "${INCPREFIX}${D_IMPORT_PATH}", "${SHDFLAGS}", "${_SOURCES}"] |
|
||||
| SHDFLAGS | Array | Shared object D compiler flags | Windows: ["${DFLAGS}"], POSIX: ["${DFLAGS}", "-fPIC"] |
|
||||
@@ -561,10 +560,58 @@ env.depends("my_app", "config/link.ld", "README.txt", *Dir.glob("assets/**/*"))
|
||||
### API documentation
|
||||
|
||||
Documentation for the complete Rscons API can be found at
|
||||
http://rubydoc.info/github/holtrop/rscons/frames.
|
||||
http://www.rubydoc.info/github/holtrop/rscons/master.
|
||||
|
||||
## Release Notes
|
||||
|
||||
### v1.14.0
|
||||
|
||||
#### New Features
|
||||
|
||||
- #45 - Add Rscons::VarSet#values_at
|
||||
|
||||
#### Fixes
|
||||
|
||||
- #44 - Environment#print_builder_run_message should support string commands
|
||||
|
||||
### v1.13.0
|
||||
|
||||
#### New Features
|
||||
|
||||
- #43 - Add ability to record side-effect file production
|
||||
|
||||
### v1.12.0
|
||||
|
||||
#### New Features
|
||||
|
||||
- #40 - env.depends should imply env.build_after
|
||||
- #41 - be more colorful
|
||||
|
||||
#### Fixes
|
||||
|
||||
- #39 - wait for in-progress subcommands to complete on build failure
|
||||
- #42 - cloned Environments should inherit n_threads
|
||||
|
||||
### v1.11.1
|
||||
|
||||
#### Fixes
|
||||
|
||||
- fix the circular build dependency detection logic
|
||||
|
||||
### v1.11.0
|
||||
|
||||
#### New Features
|
||||
|
||||
- Change default Environment :clone option to :all to clone all attributes
|
||||
- #38 - raise error when circular dependencies are found
|
||||
- #34 - Allow overriding n_threads on a per-Environment level
|
||||
|
||||
#### Fixes
|
||||
|
||||
- #35 - env.build_after should expand paths
|
||||
- #36 - SHCFLAGS and SHCXXFLAGS should inherit non-SH flags by default
|
||||
- #37 - Fix non-blocking thread-wait if Rscons.n_threads is set to 0
|
||||
|
||||
### v1.10.0
|
||||
|
||||
#### New Features
|
||||
@@ -581,6 +628,7 @@ http://rubydoc.info/github/holtrop/rscons/frames.
|
||||
|
||||
- expand target and source paths before calling Builder#create_build_target
|
||||
- #29 - fix PROGSUFFIX handling
|
||||
- #32 - Pre-build hooks do not respect modified key values
|
||||
|
||||
### v1.9.3
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Rscons::Environment.new do |env|
|
||||
env.echo = :command
|
||||
env.Install("inst.exe", "install.rb")
|
||||
end
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
class MyBuilder < Rscons::Builder
|
||||
def run(options)
|
||||
env, target = options.values_at(:env, :target)
|
||||
env.print_builder_run_message("MyBuilder #{target}", "MyBuilder #{target} command")
|
||||
target
|
||||
end
|
||||
end
|
||||
|
||||
Rscons::Environment.new do |env|
|
||||
env.echo = :command
|
||||
env.add_builder(MyBuilder.new)
|
||||
env.MyBuilder("foo")
|
||||
end
|
||||
@@ -10,6 +10,6 @@ env1 = Rscons::Environment.new(echo: :command) do |env|
|
||||
env.Program('program.exe', Dir['src/*.c'])
|
||||
end
|
||||
|
||||
env2 = env1.clone(clone: :all) do |env|
|
||||
env2 = env1.clone do |env|
|
||||
env.Program('program2.exe', Dir['src/*.c'])
|
||||
end
|
||||
@@ -3,6 +3,8 @@ Rscons::Environment.new do |env|
|
||||
[],
|
||||
"CMD" => %w[ruby gen.rb ${_TARGET}],
|
||||
"CMD_DESC" => "Generating")
|
||||
env.build_after("#{env.build_root}/program.o", "inc.c")
|
||||
env["build_root"] = env.build_root
|
||||
env["inc_c"] = "inc.c"
|
||||
env.build_after("${build_root}/program.o", "${inc_c}")
|
||||
env.Program("program.exe", ["program.c", "inc.c"])
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
Rscons::Environment.new do |env|
|
||||
env["build_root"] = env.build_root
|
||||
env["inc_h"] = "inc.h"
|
||||
|
||||
env.Copy("copy_inc.h", "${inc_h}")
|
||||
env.depends("${build_root}/program.o", "${inc_h}")
|
||||
env.Program("program.exe", ["program.c", "inc.c"])
|
||||
|
||||
env.Command("inc.c",
|
||||
[],
|
||||
"CMD" => %w[ruby gen.rb ${_TARGET}],
|
||||
"CMD_DESC" => "Generating")
|
||||
env.produces("inc.c", "inc.h")
|
||||
end
|
||||
@@ -0,0 +1,7 @@
|
||||
base_env = Rscons::Environment.new do |env|
|
||||
env.n_threads = 165
|
||||
end
|
||||
|
||||
my_env = base_env.clone
|
||||
|
||||
puts my_env.n_threads
|
||||
@@ -0,0 +1,5 @@
|
||||
Rscons::Environment.new do |env|
|
||||
env.Command("foo", "bar")
|
||||
env.Command("bar", "baz")
|
||||
env.Command("baz", "foo")
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
Rscons::Environment.new do |env|
|
||||
env.Command("foo", "foo")
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
class TestBuilder < Rscons::Builder
|
||||
def run(options)
|
||||
target, env, vars, cache = options.values_at(:target, :env, :vars, :cache)
|
||||
if target == "two"
|
||||
return false unless File.exists?("one")
|
||||
end
|
||||
wait_time = env.expand_varref("${wait_time}", vars)
|
||||
command = ["ruby", "-e", "require 'fileutils'; sleep #{wait_time}; FileUtils.touch('#{target}');"]
|
||||
standard_threaded_build("TestBuilder", target, command, [], env, cache)
|
||||
end
|
||||
|
||||
def finalize(options)
|
||||
standard_finalize(options)
|
||||
end
|
||||
end
|
||||
|
||||
Rscons::Environment.new do |env|
|
||||
env.add_builder(TestBuilder.new)
|
||||
env.TestBuilder("one", [], "wait_time" => "3")
|
||||
env.TestBuilder("two", [], "wait_time" => "0")
|
||||
env.depends("two", "one")
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
class Fail < Rscons::Builder
|
||||
def run(options)
|
||||
target, cache, env, vars = options.values_at(:target, :cache, :env, :vars)
|
||||
wait_time = env.expand_varref("${wait_time}", vars)
|
||||
ruby_command = %[sleep #{wait_time}; exit 2]
|
||||
command = %W[ruby -e #{ruby_command}]
|
||||
standard_threaded_build("Fail #{target}", target, command, [], env, cache)
|
||||
end
|
||||
def finalize(options)
|
||||
standard_finalize(options)
|
||||
end
|
||||
end
|
||||
|
||||
Rscons::Environment.new do |env|
|
||||
env.add_builder(Fail.new)
|
||||
4.times do |i|
|
||||
wait_time = i + 1
|
||||
env.Fail("foo_#{wait_time}", [], "wait_time" => wait_time.to_s)
|
||||
end
|
||||
end
|
||||
@@ -1,3 +1,4 @@
|
||||
require_relative "rscons/ansi"
|
||||
require_relative "rscons/build_target"
|
||||
require_relative "rscons/builder"
|
||||
require_relative "rscons/cache"
|
||||
@@ -50,6 +51,10 @@ module Rscons
|
||||
# The number of threads to use when scheduling subprocesses.
|
||||
attr_accessor :n_threads
|
||||
|
||||
# @return [Boolean]
|
||||
# Whether to output ANSI color escape sequences.
|
||||
attr_accessor :do_ansi_color
|
||||
|
||||
# Remove all generated files.
|
||||
#
|
||||
# @return [void]
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
module Rscons
|
||||
# Module to contain logic to write ANSI color escape codes.
|
||||
module Ansi
|
||||
class << self
|
||||
|
||||
# Write a message to an IO with ANSI escape codes.
|
||||
#
|
||||
# @param io [IO]
|
||||
# The IO to write to.
|
||||
# @param message [Array<String, Symbol>]
|
||||
# Strings to be printed, with Symbols representing ANSI escape codes.
|
||||
#
|
||||
# @return [void]
|
||||
def write(io, *message)
|
||||
do_color = Rscons.do_ansi_color
|
||||
if do_color.nil?
|
||||
do_color = do_ansi?(io)
|
||||
end
|
||||
out = ""
|
||||
message.each do |m|
|
||||
if m.is_a?(String)
|
||||
out += m
|
||||
elsif do_color
|
||||
case m
|
||||
when :red
|
||||
out += "\e[0;31m"
|
||||
when :cyan
|
||||
out += "\e[0;36m"
|
||||
when :reset
|
||||
out += "\e[0m"
|
||||
end
|
||||
end
|
||||
end
|
||||
io.write(out)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Determine whether to output ANSI color escape codes.
|
||||
#
|
||||
# @return [Boolean]
|
||||
# Whether to output ANSI color escape codes.
|
||||
def do_ansi?(io)
|
||||
if RUBY_PLATFORM =~ /mingw/
|
||||
(ENV["TERM"] == "xterm") && %w[fifo characterSpecial].include?(io.stat.ftype)
|
||||
else
|
||||
io.tty?
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -231,7 +231,7 @@ module Rscons
|
||||
# @param env [Environment] The Environment executing the builder.
|
||||
# @param cache [Cache] The Cache object.
|
||||
# @param options [Hash] Options.
|
||||
# @options options [String] :stdout
|
||||
# @option options [String] :stdout
|
||||
# File name to redirect standard output to.
|
||||
#
|
||||
# @return [String,ThreadedCommand]
|
||||
|
||||
@@ -17,10 +17,10 @@ module Rscons
|
||||
if File.directory?(target)
|
||||
target
|
||||
elsif File.exists?(target)
|
||||
$stderr.puts "Error: `#{target}' already exists and is not a directory"
|
||||
Ansi.write($stderr, :red, "Error: `#{target}' already exists and is not a directory", :reset, "\n")
|
||||
false
|
||||
else
|
||||
puts "Directory #{target}"
|
||||
env.print_builder_run_message("Directory #{target}", nil)
|
||||
cache.mkdir_p(target)
|
||||
target
|
||||
end
|
||||
|
||||
@@ -43,7 +43,7 @@ module Rscons
|
||||
# Check the cache and copy if necessary
|
||||
unless cache.up_to_date?(dest, :Copy, [src], env)
|
||||
unless printed_message
|
||||
puts "#{name} #{target}"
|
||||
env.print_builder_run_message("#{name} #{target}", nil)
|
||||
printed_message = true
|
||||
end
|
||||
cache.mkdir_p(File.dirname(dest))
|
||||
|
||||
@@ -24,11 +24,11 @@ module Rscons
|
||||
'SHCCFLAGS' => ['${CCFLAGS}'] + pic_flags,
|
||||
|
||||
'SHCC' => '${CC}',
|
||||
'SHCFLAGS' => [],
|
||||
'SHCFLAGS' => ['${CFLAGS}'],
|
||||
'SHCCCMD' => ['${SHCC}', '-c', '-o', '${_TARGET}', '${CCDEPGEN}', '${INCPREFIX}${CPPPATH}', '${CPPFLAGS}', '${SHCFLAGS}', '${SHCCFLAGS}', '${_SOURCES}'],
|
||||
|
||||
'SHCXX' => '${CXX}',
|
||||
'SHCXXFLAGS' => [],
|
||||
'SHCXXFLAGS' => ['${CXXFLAGS}'],
|
||||
'SHCXXCMD' => ['${SHCXX}', '-c', '-o', '${_TARGET}', '${CXXDEPGEN}', '${INCPREFIX}${CPPPATH}', '${CPPFLAGS}', '${SHCXXFLAGS}', '${SHCCFLAGS}', '${_SOURCES}'],
|
||||
|
||||
'SHDC' => 'gdc',
|
||||
|
||||
+9
-1
@@ -39,6 +39,15 @@ module Rscons
|
||||
Rscons.n_threads = n_threads.to_i
|
||||
end
|
||||
|
||||
opts.on("-r", "--color MODE", "Set color mode (off, auto, force)") do |color_mode|
|
||||
case color_mode
|
||||
when "off"
|
||||
Rscons.do_ansi_color = false
|
||||
when "force"
|
||||
Rscons.do_ansi_color = true
|
||||
end
|
||||
end
|
||||
|
||||
opts.on_tail("--version", "Show version") do
|
||||
puts "Rscons version #{Rscons::VERSION}"
|
||||
exit 0
|
||||
@@ -70,7 +79,6 @@ module Rscons
|
||||
begin
|
||||
load rsconsfile
|
||||
rescue Rscons::BuildError => e
|
||||
$stderr.puts e.message
|
||||
exit 1
|
||||
end
|
||||
|
||||
|
||||
+103
-26
@@ -17,6 +17,11 @@ module Rscons
|
||||
# @return [String] The build root.
|
||||
attr_reader :build_root
|
||||
|
||||
# @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.
|
||||
attr_writer :n_threads
|
||||
|
||||
# Set the build root.
|
||||
#
|
||||
# @param build_root [String] The build root.
|
||||
@@ -40,8 +45,9 @@ module Rscons
|
||||
def initialize(options = {})
|
||||
@threaded_commands = Set.new
|
||||
@registered_build_dependencies = {}
|
||||
@side_effects = {}
|
||||
@varset = VarSet.new
|
||||
@job_set = JobSet.new(@registered_build_dependencies)
|
||||
@job_set = JobSet.new(@registered_build_dependencies, @side_effects)
|
||||
@user_deps = {}
|
||||
@builders = {}
|
||||
@build_dirs = []
|
||||
@@ -73,9 +79,9 @@ module Rscons
|
||||
# following:
|
||||
# - :variables to clone construction variables (on by default)
|
||||
# - :builders to clone the builders (on by default)
|
||||
# - :build_root to clone the build root (off by default)
|
||||
# - :build_dirs to clone the build directories (off by default)
|
||||
# - :build_hooks to clone the build hooks (off 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.
|
||||
@@ -84,7 +90,7 @@ module Rscons
|
||||
#
|
||||
# @return [Environment] The newly created {Environment} object.
|
||||
def clone(options = {})
|
||||
clone = options[:clone] || Set[:variables, :builders]
|
||||
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)
|
||||
@@ -101,7 +107,7 @@ module Rscons
|
||||
env.append(@varset) if clone.include?(:variables)
|
||||
env.build_root = @build_root if clone.include?(:build_root)
|
||||
if clone.include?(:build_dirs)
|
||||
@build_dirs.each do |src_dir, obj_dir|
|
||||
@build_dirs.reverse.each do |src_dir, obj_dir|
|
||||
env.build_dir(src_dir, obj_dir)
|
||||
end
|
||||
end
|
||||
@@ -113,6 +119,7 @@ module Rscons
|
||||
env.add_post_build_hook(&build_hook_block)
|
||||
end
|
||||
end
|
||||
env.instance_variable_set(:@n_threads, @n_threads)
|
||||
|
||||
if block_given?
|
||||
yield env
|
||||
@@ -222,7 +229,7 @@ module Rscons
|
||||
if src_dir.is_a?(String)
|
||||
src_dir = src_dir.gsub("\\", "/").sub(%r{/*$}, "")
|
||||
end
|
||||
@build_dirs << [src_dir, obj_dir]
|
||||
@build_dirs.unshift([src_dir, obj_dir])
|
||||
end
|
||||
|
||||
# Return the file name to be built from +source_fname+ with suffix
|
||||
@@ -297,13 +304,19 @@ module Rscons
|
||||
# @return [void]
|
||||
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.
|
||||
@@ -318,7 +331,9 @@ module Rscons
|
||||
allow_delayed_execution: true,
|
||||
setup_info: job[:setup_info])
|
||||
unless result
|
||||
raise BuildError.new("Failed to build #{job[:target]}")
|
||||
failure = "Failed to build #{job[:target]}"
|
||||
Ansi.write($stderr, :red, failure, :reset, "\n")
|
||||
next
|
||||
end
|
||||
end
|
||||
|
||||
@@ -330,7 +345,8 @@ module Rscons
|
||||
end
|
||||
|
||||
# If needed, do a blocking wait.
|
||||
if (completed_tcs.empty? and job.nil?) or @threaded_commands.size >= Rscons.n_threads
|
||||
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
|
||||
|
||||
@@ -343,9 +359,11 @@ module Rscons
|
||||
end
|
||||
else
|
||||
unless @echo == :command
|
||||
$stdout.puts "Failed command was: #{command_to_s(tc.command)}"
|
||||
print_failed_command(tc.command)
|
||||
end
|
||||
raise BuildError.new("Failed to build #{tc.build_operation[:target]}")
|
||||
failure = "Failed to build #{tc.build_operation[:target]}"
|
||||
Ansi.write($stderr, :red, failure, :reset, "\n")
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
@@ -353,6 +371,9 @@ module Rscons
|
||||
ensure
|
||||
cache.write
|
||||
end
|
||||
if failure
|
||||
raise BuildError.new(failure)
|
||||
end
|
||||
end
|
||||
|
||||
# Clear all targets registered for the Environment.
|
||||
@@ -392,16 +413,12 @@ module Rscons
|
||||
#
|
||||
# @return [true,false,nil] Return value from Kernel.system().
|
||||
def execute(short_desc, command, options = {})
|
||||
if @echo == :command
|
||||
puts command_to_s(command)
|
||||
elsif @echo == :short
|
||||
puts short_desc
|
||||
end
|
||||
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
|
||||
$stdout.puts "Failed command was: #{command_to_s(command)}"
|
||||
print_failed_command(command)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -445,6 +462,7 @@ module Rscons
|
||||
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
|
||||
|
||||
# Manually record the given target(s) as needing to be built after the
|
||||
@@ -476,13 +494,35 @@ module Rscons
|
||||
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
|
||||
|
||||
# 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]
|
||||
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
|
||||
|
||||
# Return the list of user dependencies for a given target.
|
||||
#
|
||||
# @param target [String] Target file name.
|
||||
@@ -634,7 +674,7 @@ module Rscons
|
||||
call_build_hooks[:post]
|
||||
else
|
||||
unless @echo == :command
|
||||
$stdout.puts "Failed command was: #{command_to_s(tc.command)}"
|
||||
print_failed_command(tc.command)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -821,10 +861,53 @@ module Rscons
|
||||
varset_hash = @varset.to_h
|
||||
varset_hash.keys.sort_by(&:to_s).each do |var|
|
||||
var_str = var.is_a?(Symbol) ? var.inspect : var
|
||||
puts "#{var_str} => #{varset_hash[var].inspect}"
|
||||
Ansi.write($stdout, :cyan, var_str, :reset, " => #{varset_hash[var].inspect}\n")
|
||||
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.
|
||||
def n_threads
|
||||
@n_threads || Rscons.n_threads
|
||||
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]
|
||||
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]
|
||||
def print_failed_command(command)
|
||||
Ansi.write($stdout, :red, "Failed command was: #{command_to_s(command)}", :reset, "\n")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Add a build target.
|
||||
@@ -857,13 +940,7 @@ module Rscons
|
||||
#
|
||||
# @return [void]
|
||||
def start_threaded_command(tc)
|
||||
if @echo == :command
|
||||
puts command_to_s(tc.command)
|
||||
elsif @echo == :short
|
||||
if tc.short_description
|
||||
puts tc.short_description
|
||||
end
|
||||
end
|
||||
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] : []
|
||||
|
||||
+19
-11
@@ -9,9 +9,14 @@ module Rscons
|
||||
# @param build_dependencies [Hash]
|
||||
# Hash mapping targets to a set of build dependencies. A job will not be
|
||||
# returned as ready to run if any of its dependencies are still building.
|
||||
def initialize(build_dependencies)
|
||||
# @param side_effects [Hash]
|
||||
# Hash mapping targets to a set of side-effect files. A job will not be
|
||||
# returned as ready to run if any of its dependencies is a side-effect
|
||||
# of another target that has not yet been built.
|
||||
def initialize(build_dependencies, side_effects)
|
||||
@jobs = {}
|
||||
@build_dependencies = build_dependencies
|
||||
@side_effects = side_effects
|
||||
end
|
||||
|
||||
# Add a job to the JobSet.
|
||||
@@ -47,18 +52,16 @@ module Rscons
|
||||
# @return [nil, Hash]
|
||||
# The next job to run.
|
||||
def get_next_job_to_run(targets_still_building)
|
||||
targets_not_built_yet = targets_still_building + @jobs.keys
|
||||
side_effects = targets_not_built_yet.map do |target|
|
||||
@side_effects[target] || []
|
||||
end.flatten
|
||||
targets_not_built_yet += side_effects
|
||||
|
||||
@jobs.keys.each do |target|
|
||||
skip = false
|
||||
(@jobs[target][0][:sources] + (@build_dependencies[target] || []).to_a).each do |src|
|
||||
if @jobs.include?(src)
|
||||
# Skip this target because it depends on another target later in
|
||||
# the job set.
|
||||
skip = true
|
||||
break
|
||||
end
|
||||
if targets_still_building.include?(src)
|
||||
# Skip this target because it depends on another target that is
|
||||
# still being built.
|
||||
if targets_not_built_yet.include?(src)
|
||||
skip = true
|
||||
break
|
||||
end
|
||||
@@ -73,7 +76,12 @@ module Rscons
|
||||
return job
|
||||
end
|
||||
|
||||
nil
|
||||
# If there is a job to run, and nothing is still building, but we did
|
||||
# not find a job to run above, then there might be a circular dependency
|
||||
# introduced by the user.
|
||||
if (@jobs.size > 0) and targets_still_building.empty?
|
||||
raise "Could not find a runnable job. Possible circular dependency for #{@jobs.keys.first}"
|
||||
end
|
||||
end
|
||||
|
||||
# Remove all jobs from the JobSet.
|
||||
|
||||
@@ -143,6 +143,19 @@ module Rscons
|
||||
end
|
||||
end
|
||||
|
||||
# Return an array containing the values associated with the given keys.
|
||||
#
|
||||
# @param keys [Array<String, Symbol>]
|
||||
# Keys to look up in the VarSet.
|
||||
#
|
||||
# @return [Array]
|
||||
# An array containing the values associated with the given keys.
|
||||
def values_at(*keys)
|
||||
keys.map do |key|
|
||||
self[key]
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Move all VarSet variables into the copy-on-access list.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module Rscons
|
||||
# gem version
|
||||
VERSION = "1.10.0"
|
||||
VERSION = "1.14.0"
|
||||
end
|
||||
@@ -336,7 +336,7 @@ EOF
|
||||
]
|
||||
end
|
||||
|
||||
it 'allows cloning all attributes of an Environment object' do
|
||||
it 'clones all attributes of an Environment object by default' do
|
||||
test_dir('clone_env')
|
||||
result = run_test(rsconsfile: "clone_all.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
@@ -732,6 +732,82 @@ EOF
|
||||
expect(`./test-static.exe`).to match /Hi from one/
|
||||
end
|
||||
|
||||
it "raises an error for a circular dependency" do
|
||||
test_dir("simple")
|
||||
result = run_test(rsconsfile: "error_circular_dependency.rb")
|
||||
expect(result.stderr).to match /Possible circular dependency for (foo|bar|baz)/
|
||||
expect(result.status).to_not eq 0
|
||||
end
|
||||
|
||||
it "raises an error for a circular dependency where a build target contains itself in its source list" do
|
||||
test_dir("simple")
|
||||
result = run_test(rsconsfile: "error_circular_dependency2.rb")
|
||||
expect(result.stderr).to match /Possible circular dependency for foo/
|
||||
expect(result.status).to_not eq 0
|
||||
end
|
||||
|
||||
it "orders builds to respect user dependencies" do
|
||||
test_dir("simple")
|
||||
result = run_test(rsconsfile: "user_dep_build_order.rb", rscons_args: %w[-j4])
|
||||
expect(result.stderr).to eq ""
|
||||
end
|
||||
|
||||
it "waits for all parallelized builds to complete if one fails" do
|
||||
test_dir("simple")
|
||||
result = run_test(rsconsfile: "wait_for_builds_on_failure.rb", rscons_args: %w[-j4])
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stderr).to match /Failed to build foo_1/
|
||||
expect(result.stderr).to match /Failed to build foo_2/
|
||||
expect(result.stderr).to match /Failed to build foo_3/
|
||||
expect(result.stderr).to match /Failed to build foo_4/
|
||||
end
|
||||
|
||||
it "clones n_threads attribute when cloning an Environment" do
|
||||
test_dir("simple")
|
||||
result = run_test(rsconsfile: "clone_n_threads.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(lines(result.stdout)).to eq ["165"]
|
||||
end
|
||||
|
||||
it "prints a builder's short description with 'command' echo mode if there is no command" do
|
||||
test_dir("build_dir")
|
||||
|
||||
result = run_test(rsconsfile: "echo_command_ruby_builder.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(lines(result.stdout)).to eq ["Install inst.exe"]
|
||||
end
|
||||
|
||||
it "supports a string for a builder's echoed 'command' with Environment#print_builder_run_message" do
|
||||
test_dir("build_dir")
|
||||
|
||||
result = run_test(rsconsfile: "echo_command_string.rb")
|
||||
expect(result.stderr).to eq ""
|
||||
expect(lines(result.stdout)).to eq ["MyBuilder foo command"]
|
||||
end
|
||||
|
||||
context "colored output" do
|
||||
it "does not output in color with --color=off" do
|
||||
test_dir("simple")
|
||||
result = run_test(rscons_args: %w[--color=off])
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to_not match(/\e\[/)
|
||||
end
|
||||
|
||||
it "displays output in color with --color=force" do
|
||||
test_dir("simple")
|
||||
|
||||
result = run_test(rscons_args: %w[--color=force])
|
||||
expect(result.stderr).to eq ""
|
||||
expect(result.stdout).to match(/\e\[/)
|
||||
|
||||
File.open("simple.c", "wb") do |fh|
|
||||
fh.write("foobar")
|
||||
end
|
||||
result = run_test(rscons_args: %w[--color=force])
|
||||
expect(result.stderr).to match(/\e\[/)
|
||||
end
|
||||
end
|
||||
|
||||
context "backward compatibility" do
|
||||
it "allows a builder to call Environment#run_builder in a non-threaded manner" do
|
||||
test_dir("simple")
|
||||
@@ -754,6 +830,21 @@ EOF
|
||||
]
|
||||
end
|
||||
|
||||
it "prints the failed build command for a non-threaded builder" do
|
||||
test_dir("simple")
|
||||
File.open("simple.c", "wb") do |fh|
|
||||
fh.write(<<EOF)
|
||||
void one()
|
||||
{
|
||||
}
|
||||
EOF
|
||||
end
|
||||
result = run_test(rsconsfile: "build_sources.rb")
|
||||
expect(result.status).to_not eq 0
|
||||
expect(result.stderr).to match /main/
|
||||
expect(result.stdout).to match /Failed command was: gcc/
|
||||
end
|
||||
|
||||
it "prints the failed build command for a threaded builder when called via Environment#run_builder without delayed execution" do
|
||||
test_dir("simple")
|
||||
File.open("simple.c", "wb") do |fh|
|
||||
@@ -1231,6 +1322,13 @@ EOF
|
||||
result = run_test(rsconsfile: "build_after.rb", rscons_args: %w[-j 4])
|
||||
expect(result.stderr).to eq ""
|
||||
end
|
||||
|
||||
it "allows the user to specify side-effect files produced by another builder" do
|
||||
test_dir("custom_builder")
|
||||
result = run_test(rsconsfile: "produces.rb", rscons_args: %w[-j 4])
|
||||
expect(result.stderr).to eq ""
|
||||
expect(File.exists?("copy_inc.h")).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context "CLI" do
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
module Rscons
|
||||
describe Ansi do
|
||||
describe ".do_ansi?" do
|
||||
|
||||
context "on Windows" do
|
||||
it "returns true when IO is a fifo on an xterm" do
|
||||
stub_const("RUBY_PLATFORM", "mingw")
|
||||
expect(ENV).to receive(:[]).with("TERM").and_return("xterm")
|
||||
io = double
|
||||
expect(io).to receive(:stat).and_return(Struct.new(:ftype).new("fifo"))
|
||||
expect(Ansi.__send__(:do_ansi?, io)).to be_truthy
|
||||
end
|
||||
|
||||
it "returns false when TERM is not set appropriately" do
|
||||
stub_const("RUBY_PLATFORM", "mingw")
|
||||
expect(ENV).to receive(:[]).with("TERM").and_return(nil)
|
||||
io = double
|
||||
expect(Ansi.__send__(:do_ansi?, io)).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context "on POSIX" do
|
||||
it "returns true when IO is a TTY" do
|
||||
stub_const("RUBY_PLATFORM", "linux")
|
||||
io = double
|
||||
expect(io).to receive(:tty?).and_return(true)
|
||||
expect(Ansi.__send__(:do_ansi?, io)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -190,38 +190,6 @@ module Rscons
|
||||
end
|
||||
end
|
||||
|
||||
describe "#execute" do
|
||||
context "with echo: :short" do
|
||||
context "with no errors" do
|
||||
it "prints the short description and executes the command" do
|
||||
env = Environment.new(echo: :short)
|
||||
expect(env).to receive(:puts).with("short desc")
|
||||
expect(env).to receive(:system).with(*Rscons.command_executer, "a", "command").and_return(true)
|
||||
env.execute("short desc", ["a", "command"])
|
||||
end
|
||||
end
|
||||
|
||||
context "with errors" do
|
||||
it "prints the short description, executes the command, and prints the failed command line" do
|
||||
env = Environment.new(echo: :short)
|
||||
expect(env).to receive(:puts).with("short desc")
|
||||
expect(env).to receive(:system).with(*Rscons.command_executer, "a", "command").and_return(false)
|
||||
expect($stdout).to receive(:puts).with("Failed command was: a command")
|
||||
env.execute("short desc", ["a", "command"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with echo: :command" do
|
||||
it "prints the command executed and executes the command" do
|
||||
env = Environment.new(echo: :command)
|
||||
expect(env).to receive(:puts).with("a command '--arg=val with spaces'")
|
||||
expect(env).to receive(:system).with({modified: :environment}, *Rscons.command_executer, "a", "command", "--arg=val with spaces", {opt: :val}).and_return(false)
|
||||
env.execute("short desc", ["a", "command", "--arg=val with spaces"], env: {modified: :environment}, options: {opt: :val})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#method_missing" do
|
||||
it "calls the original method missing when the target method is not a known builder" do
|
||||
env = Environment.new
|
||||
|
||||
@@ -199,5 +199,14 @@ module Rscons
|
||||
end
|
||||
end
|
||||
|
||||
describe "#values_at" do
|
||||
it "returns an array of the values associated with the given keys" do
|
||||
v = VarSet.new({"fuz" => "a string", "foo" => 42, "bar" => :baz,
|
||||
"qax" => [3, 6], "qux" => {a: :b}})
|
||||
expect(v.values_at).to eq []
|
||||
expect(v.values_at(*%w[fuz qux qax])).to eq ["a string", {a: :b}, [3, 6]]
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
Reference in new issue
Block a user