Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
469f575564 | ||
|
|
07725581e9 | ||
|
|
ebb69cedc2 | ||
|
|
c98b377ce8 | ||
|
|
a0874e7cf1 | ||
|
|
0b04229e3d | ||
|
|
20f3da3b04 | ||
|
|
a6a79b8ef1 | ||
|
|
6d4f27602e | ||
|
|
453295a49b | ||
|
|
dee2b98f6e | ||
|
|
b186b3102c | ||
|
|
23c94f7841 |
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
rscons (1.6.1)
|
||||
rscons (1.7.0)
|
||||
json (~> 1.0)
|
||||
|
||||
GEM
|
||||
|
||||
@@ -173,6 +173,9 @@ Each build hook block will be invoked for every build operation, so the block
|
||||
should test the target or sources if its action should only apply to some
|
||||
subset of build targets or source files.
|
||||
|
||||
Build hooks can alter construction variable values for a particular build
|
||||
operation. Build hooks can also register new build targets.
|
||||
|
||||
The `build_op` parameter to the build hook block is a Hash describing the
|
||||
build operation with the following keys:
|
||||
* `:builder` - `Builder` instance in use
|
||||
@@ -317,6 +320,19 @@ cloned_env["CPPPATH"] << "three"
|
||||
|
||||
`base_env["CPPPATH"]` will not include "three".
|
||||
|
||||
#### Build Hooks
|
||||
|
||||
Environments can have build hooks which are added with `env.add_build_hook()`.
|
||||
Build hooks are invoked immediately before a builder executes.
|
||||
Build hooks can modify the construction variables in use for the build
|
||||
operation.
|
||||
They can also register new build targets.
|
||||
|
||||
Environments can also have post-build hooks added with `env.add_post_build_hook()`.
|
||||
Post-build hooks are only invoked if the build operation was a success.
|
||||
Post-build hooks can invoke commands using the newly-built files, or register
|
||||
new build targets.
|
||||
|
||||
### Construction Variable Naming
|
||||
|
||||
* uppercase strings - the default construction variables that Rscons uses
|
||||
@@ -329,6 +345,13 @@ http://rubydoc.info/github/holtrop/rscons/frames.
|
||||
|
||||
## Release Notes
|
||||
|
||||
### v1.7.0
|
||||
|
||||
- allow build hooks to register new build targets
|
||||
- add post-build hooks (register with Environment#add_post_build_hook)
|
||||
- clear all build targets after processing an Environment
|
||||
- allow trailing slashes in arguments to Environment#build_dir
|
||||
|
||||
### v1.6.1
|
||||
|
||||
- add DEPFILESUFFIX construction variable to override dependency file suffix
|
||||
|
||||
+4
-8
@@ -8,6 +8,10 @@ end
|
||||
require "bundler/gem_tasks"
|
||||
require "rspec/core/rake_task"
|
||||
require "yard"
|
||||
require "rake/clean"
|
||||
|
||||
CLEAN.include %w[build_test_run .yardoc doc coverage]
|
||||
CLOBBER.include %w[pkg]
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec)
|
||||
|
||||
@@ -16,11 +20,3 @@ YARD::Rake::YardocTask.new do |yard|
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
|
||||
task :clean do
|
||||
FileUtils.rm_rf(["build_test_run", "doc", "coverage"])
|
||||
end
|
||||
|
||||
task :clobber => :clean do
|
||||
FileUtils.rm_rf(["pkg"])
|
||||
end
|
||||
+57
-15
@@ -7,7 +7,7 @@ module Rscons
|
||||
# contains a collection of construction variables, options, builders, and
|
||||
# rules for building targets.
|
||||
class Environment
|
||||
# @return [Hash] Set of \{"builder_name" => builder_object} pairs.
|
||||
# @return [Hash] Set of !{"builder_name" => builder_object} pairs.
|
||||
attr_reader :builders
|
||||
|
||||
# :command, :short, or :off
|
||||
@@ -42,7 +42,7 @@ module Rscons
|
||||
@user_deps = {}
|
||||
@builders = {}
|
||||
@build_dirs = []
|
||||
@build_hooks = []
|
||||
@build_hooks = {pre: [], post: []}
|
||||
unless options[:exclude_builders]
|
||||
DEFAULT_BUILDERS.each do |builder_class_name|
|
||||
builder_class = Builders.const_get(builder_class_name)
|
||||
@@ -103,9 +103,12 @@ module Rscons
|
||||
end
|
||||
end
|
||||
if clone.include?(:build_hooks)
|
||||
@build_hooks.each do |build_hook_block|
|
||||
@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
|
||||
|
||||
if block_given?
|
||||
@@ -132,6 +135,12 @@ module Rscons
|
||||
|
||||
# Add a build hook to the Environment.
|
||||
#
|
||||
# Build hooks are Ruby blocks which are invoked immediately before a
|
||||
# build operation takes place. Build hooks have an opportunity to modify
|
||||
# the construction variables in use for the build operation based on the
|
||||
# builder in use, target file name, or sources. Build hooks can also
|
||||
# register new build targets.
|
||||
#
|
||||
# @yield [build_op]
|
||||
# Invoke the given block with the current build operation.
|
||||
# @yieldparam build_op [Hash]
|
||||
@@ -144,19 +153,45 @@ module Rscons
|
||||
#
|
||||
# @return [void]
|
||||
def add_build_hook(&block)
|
||||
@build_hooks << block
|
||||
@build_hooks[:pre] << block
|
||||
end
|
||||
|
||||
# Add a post build hook to the Environment.
|
||||
#
|
||||
# Post-build hooks are Ruby blocks which are invoked immediately after a
|
||||
# build operation takes place. Post-build hooks are only invoked if the
|
||||
# build operation succeeded. Post-build hooks can register new build
|
||||
# targets.
|
||||
#
|
||||
# @since 1.7.0
|
||||
#
|
||||
# @yield [build_op]
|
||||
# Invoke the given block with the current build operation.
|
||||
# @yieldparam build_op [Hash]
|
||||
# Hash with keys:
|
||||
# - :builder - The builder object in use.
|
||||
# - :target - Target file name.
|
||||
# - :sources - List of source file(s).
|
||||
# - :vars - Set of construction variable values in use.
|
||||
# - :env - The Environment invoking the builder.
|
||||
#
|
||||
# @return [void]
|
||||
def add_post_build_hook(&block)
|
||||
@build_hooks[:post] << block
|
||||
end
|
||||
|
||||
# Specify a build directory for this Environment.
|
||||
#
|
||||
# Source files from src_dir will produce object files under obj_dir.
|
||||
#
|
||||
# @param src_dir [String] Path to the source directory.
|
||||
# @param src_dir [String, Regexp] Path to the source directory.
|
||||
# @param obj_dir [String] Path to the object directory.
|
||||
#
|
||||
# @return [void]
|
||||
def build_dir(src_dir, obj_dir)
|
||||
src_dir = src_dir.gsub('\\', '/') if src_dir.is_a?(String)
|
||||
if src_dir.is_a?(String)
|
||||
src_dir = src_dir.gsub("\\", "/").sub(%r{/*$}, "")
|
||||
end
|
||||
@build_dirs << [src_dir, obj_dir]
|
||||
end
|
||||
|
||||
@@ -216,23 +251,25 @@ module Rscons
|
||||
#
|
||||
# @return [void]
|
||||
def process
|
||||
unless @targets.empty?
|
||||
expand_paths!
|
||||
while @targets.size > 0
|
||||
targets = @targets
|
||||
@targets = {}
|
||||
cache = Cache.instance
|
||||
cache.clear_checksum_cache!
|
||||
targets_processed = {}
|
||||
process_target = proc do |target|
|
||||
targets_processed[target] ||= begin
|
||||
@targets[target][:sources].each do |src|
|
||||
if @targets.include?(src) and not targets_processed.include?(src)
|
||||
targets[target][:sources].each do |src|
|
||||
if targets.include?(src) and not targets_processed.include?(src)
|
||||
process_target.call(src)
|
||||
end
|
||||
end
|
||||
result = run_builder(@targets[target][:builder],
|
||||
result = run_builder(targets[target][:builder],
|
||||
target,
|
||||
@targets[target][:sources],
|
||||
targets[target][:sources],
|
||||
cache,
|
||||
@targets[target][:vars] || {})
|
||||
targets[target][:vars] || {})
|
||||
unless result
|
||||
raise BuildError.new("Failed to build #{target}")
|
||||
end
|
||||
@@ -240,7 +277,7 @@ module Rscons
|
||||
end
|
||||
end
|
||||
begin
|
||||
@targets.each do |target, target_params|
|
||||
targets.each do |target, target_params|
|
||||
process_target.call(target)
|
||||
end
|
||||
ensure
|
||||
@@ -410,7 +447,8 @@ module Rscons
|
||||
# @return [String,false] Return value from the {Builder}'s +run+ method.
|
||||
def run_builder(builder, target, sources, cache, vars)
|
||||
vars = @varset.merge(vars)
|
||||
@build_hooks.each do |build_hook_block|
|
||||
call_build_hooks = lambda do |sec|
|
||||
@build_hooks[sec].each do |build_hook_block|
|
||||
build_operation = {
|
||||
builder: builder,
|
||||
target: target,
|
||||
@@ -420,7 +458,11 @@ module Rscons
|
||||
}
|
||||
build_hook_block.call(build_operation)
|
||||
end
|
||||
builder.run(target, sources, cache, self, vars)
|
||||
end
|
||||
call_build_hooks[:pre]
|
||||
rv = builder.run(target, sources, cache, self, vars)
|
||||
call_build_hooks[:post] if rv
|
||||
rv
|
||||
end
|
||||
|
||||
# Expand a path to be relative to the Environment's build root.
|
||||
|
||||
@@ -83,7 +83,7 @@ module Rscons
|
||||
end
|
||||
alias_method :clone, :merge
|
||||
|
||||
# Replace "$\{var}" variable references in varref with the expanded
|
||||
# Replace "$!{var}" variable references in varref with the expanded
|
||||
# variables' values, recursively.
|
||||
#
|
||||
# @param varref [nil, String, Array, Proc]
|
||||
@@ -92,7 +92,7 @@ module Rscons
|
||||
# Arguments to pass to any lambda variable values to be expanded.
|
||||
#
|
||||
# @return [nil, String, Array]
|
||||
# Expanded value with "$\{var}" variable references replaced.
|
||||
# Expanded value with "$!{var}" variable references replaced.
|
||||
def expand_varref(varref, lambda_args)
|
||||
if varref.is_a?(String)
|
||||
if varref =~ /^(.*)\$\{([^}]+)\}(.*)$/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module Rscons
|
||||
# gem version
|
||||
VERSION = "1.6.1"
|
||||
VERSION = "1.7.0"
|
||||
end
|
||||
+147
-9
@@ -10,6 +10,7 @@ class Dir
|
||||
end
|
||||
|
||||
describe Rscons do
|
||||
|
||||
BUILD_TEST_RUN_DIR = "build_test_run"
|
||||
|
||||
def rm_rf(dir)
|
||||
@@ -120,34 +121,43 @@ describe Rscons do
|
||||
|
||||
it 'rebuilds a C module when a header it depends on changes' do
|
||||
test_dir('header')
|
||||
env = Rscons::Environment.new do |env|
|
||||
make_env = lambda do
|
||||
Rscons::Environment.new do |env|
|
||||
env.Program('header', Dir['*.c'])
|
||||
end
|
||||
end
|
||||
make_env[]
|
||||
expect(`./header`).to eq "The value is 2\n"
|
||||
file_sub('header.h') {|line| line.sub(/2/, '5')}
|
||||
env.process
|
||||
make_env[]
|
||||
expect(`./header`).to eq "The value is 5\n"
|
||||
end
|
||||
|
||||
it 'does not rebuild a C module when its dependencies have not changed' do
|
||||
test_dir('header')
|
||||
env = Rscons::Environment.new do |env|
|
||||
make_env = lambda do
|
||||
Rscons::Environment.new do |env|
|
||||
env.Program('header', Dir['*.c'])
|
||||
end
|
||||
end
|
||||
env = make_env[]
|
||||
expect(`./header`).to eq "The value is 2\n"
|
||||
expect(lines).to eq [
|
||||
'CC header.o',
|
||||
"LD header#{env["PROGSUFFIX"]}",
|
||||
]
|
||||
env.process
|
||||
make_env[]
|
||||
expect(lines).to eq []
|
||||
end
|
||||
|
||||
it "does not rebuild a C module when only the file's timestamp has changed" do
|
||||
test_dir('header')
|
||||
env = Rscons::Environment.new do |env|
|
||||
make_env = lambda do
|
||||
Rscons::Environment.new do |env|
|
||||
env.Program('header', Dir['*.c'])
|
||||
end
|
||||
end
|
||||
env = make_env[]
|
||||
expect(`./header`).to eq "The value is 2\n"
|
||||
expect(lines).to eq [
|
||||
'CC header.o',
|
||||
@@ -155,7 +165,7 @@ describe Rscons do
|
||||
]
|
||||
sleep 0.05
|
||||
file_sub('header.c') {|line| line}
|
||||
env.process
|
||||
make_env[]
|
||||
expect(lines).to eq []
|
||||
end
|
||||
|
||||
@@ -187,6 +197,19 @@ describe Rscons do
|
||||
expect(File.exists?('build_two/two.o')).to be_truthy
|
||||
end
|
||||
|
||||
it "supports trailing slashes at the end of build_dir sources and destinations" do
|
||||
test_dir("build_dir")
|
||||
Rscons::Environment.new do |env|
|
||||
env.append("CPPPATH" => Dir["src/**/*/"])
|
||||
env.build_dir("src/one/", "build_one/")
|
||||
env.build_dir("src/two", "build_two")
|
||||
env.Program("build_dir", Dir["src/**/*.c"])
|
||||
end
|
||||
expect(`./build_dir`).to eq "Hello from two()\n"
|
||||
expect(File.exists?("build_one/one.o")).to be_truthy
|
||||
expect(File.exists?("build_two/two.o")).to be_truthy
|
||||
end
|
||||
|
||||
it 'uses build directories before build root' do
|
||||
test_dir('build_dir')
|
||||
env = Rscons::Environment.new do |env|
|
||||
@@ -303,11 +326,14 @@ EOF
|
||||
end
|
||||
end
|
||||
|
||||
env = Rscons::Environment.new do |env|
|
||||
make_env = lambda do
|
||||
Rscons::Environment.new do |env|
|
||||
env.add_builder(CHGen.new)
|
||||
env.CHGen("inc.c", ["program.c"])
|
||||
env.Program("program", Dir["*.c"] + ["inc.c"])
|
||||
env.Program("program", %w[program.c inc.c])
|
||||
end
|
||||
end
|
||||
env = make_env[]
|
||||
|
||||
expect(lines).to eq ["CHGen inc.c", "CC program.o", "CC inc.o", "LD program#{env["PROGSUFFIX"]}"]
|
||||
expect(File.exists?("inc.c")).to be_truthy
|
||||
@@ -315,7 +341,7 @@ EOF
|
||||
expect(`./program`).to eq "The value is 42\n"
|
||||
|
||||
File.open("inc.c", "w") {|fh| fh.puts "int THE_VALUE = 33;"}
|
||||
env.process
|
||||
make_env[]
|
||||
expect(lines).to eq ["CHGen inc.c"]
|
||||
expect(`./program`).to eq "The value is 42\n"
|
||||
end
|
||||
@@ -347,12 +373,16 @@ EOF
|
||||
it 'allows cloning all attributes of an Environment object' do
|
||||
test_dir('clone_env')
|
||||
|
||||
built_targets = []
|
||||
env1 = Rscons::Environment.new(echo: :command) do |env|
|
||||
env.build_dir('src', 'build')
|
||||
env['CFLAGS'] = '-O2'
|
||||
env.add_build_hook do |build_op|
|
||||
build_op[:vars]['CPPFLAGS'] = '-DSTRING="Hello"'
|
||||
end
|
||||
env.add_post_build_hook do |build_op|
|
||||
built_targets << build_op[:target]
|
||||
end
|
||||
env.Program('program', Dir['src/*.c'])
|
||||
end
|
||||
|
||||
@@ -365,6 +395,12 @@ EOF
|
||||
%Q{gcc -o program#{env1["PROGSUFFIX"]} build/program.o},
|
||||
%Q{gcc -o program2#{env2["PROGSUFFIX"]} build/program.o},
|
||||
]
|
||||
expect(built_targets).to eq([
|
||||
"build/program.o",
|
||||
"program#{env1['PROGSUFFIX']}",
|
||||
"build/program.o",
|
||||
"program2#{env1['PROGSUFFIX']}",
|
||||
])
|
||||
end
|
||||
|
||||
it 'builds a C++ program with one source file' do
|
||||
@@ -562,4 +598,106 @@ EOF
|
||||
expect(e2.expand_varref("${computed}")).to eq("-H38xyz")
|
||||
expect(env.expand_varref("${lambda_recurse}")).to eq("-Hello")
|
||||
end
|
||||
|
||||
it "supports registering build targets from within a build hook" do
|
||||
test_dir("simple")
|
||||
Rscons::Environment.new do |env|
|
||||
env.Program("simple", Dir["*.c"])
|
||||
env.add_build_hook do |build_op|
|
||||
if build_op[:target].end_with?(".o")
|
||||
env.Disassemble("#{build_op[:target]}.txt", build_op[:target])
|
||||
end
|
||||
end
|
||||
end
|
||||
expect(File.exists?("simple.o")).to be_truthy
|
||||
expect(File.exists?("simple.o.txt")).to be_truthy
|
||||
expect(`./simple`).to eq "This is a simple C program\n"
|
||||
end
|
||||
|
||||
it "supports post-build hooks" do
|
||||
test_dir("simple")
|
||||
built_targets = []
|
||||
env = Rscons::Environment.new do |env|
|
||||
env.Program("simple", Dir["*.c"])
|
||||
env.add_post_build_hook do |build_op|
|
||||
built_targets << build_op[:target]
|
||||
expect(File.exists?(build_op[:target])).to be_truthy
|
||||
end
|
||||
end
|
||||
expect(File.exists?("simple.o")).to be_truthy
|
||||
expect(`./simple`).to eq "This is a simple C program\n"
|
||||
expect(built_targets).to eq ["simple.o", "simple#{env["PROGSUFFIX"]}"]
|
||||
end
|
||||
|
||||
it "supports multiple values for CXXSUFFIX" do
|
||||
test_dir("simple_cc")
|
||||
File.open("other.cccc", "w") {|fh| fh.puts}
|
||||
Rscons::Environment.new do |env|
|
||||
env["CXXSUFFIX"] = %w[.cccc .cc]
|
||||
env["CXXFLAGS"] += %w[-x c++]
|
||||
env.Program("simple", Dir["*.cc"] + ["other.cccc"])
|
||||
end
|
||||
expect(File.exists?("simple.o")).to be_truthy
|
||||
expect(File.exists?("other.o")).to be_truthy
|
||||
expect(`./simple`).to eq "This is a simple C++ program\n"
|
||||
end
|
||||
|
||||
it "supports multiple values for CSUFFIX" do
|
||||
test_dir("build_dir")
|
||||
FileUtils.mv("src/one/one.c", "src/one/one.yargh")
|
||||
Rscons::Environment.new do |env|
|
||||
env["CSUFFIX"] = %w[.yargh .c]
|
||||
env["CFLAGS"] += %w[-x c]
|
||||
env["CPPPATH"] += Dir["src/**/"]
|
||||
env.Program("build_dir", Dir["src/**/*.{c,yargh}"])
|
||||
end
|
||||
expect(File.exists?("src/one/one.o")).to be_truthy
|
||||
expect(File.exists?("src/two/two.o")).to be_truthy
|
||||
expect(`./build_dir`).to eq "Hello from two()\n"
|
||||
end
|
||||
|
||||
it "supports multiple values for OBJSUFFIX" do
|
||||
test_dir("two_sources")
|
||||
env = Rscons::Environment.new() do |env|
|
||||
env["OBJSUFFIX"] = %w[.oooo .ooo]
|
||||
env.Object("one.oooo", "one.c", "CPPFLAGS" => ["-DONE"])
|
||||
env.Object("two.ooo", "two.c")
|
||||
env.Program("two_sources", %w[one.oooo two.ooo])
|
||||
end
|
||||
expect(File.exists?("two_sources#{env["PROGSUFFIX"]}")).to be_truthy
|
||||
expect(`./two_sources`).to eq "This is a C program with two sources.\n"
|
||||
end
|
||||
|
||||
it "supports multiple values for LIBSUFFIX" do
|
||||
test_dir("two_sources")
|
||||
env = Rscons::Environment.new() do |env|
|
||||
env["LIBSUFFIX"] = %w[.aaaa .aaa]
|
||||
env.Library("one.aaaa", "one.c", "CPPFLAGS" => ["-DONE"])
|
||||
env.Library("two.aaa", "two.c")
|
||||
env.Program("two_sources", %w[one.aaaa two.aaa])
|
||||
end
|
||||
expect(File.exists?("two_sources#{env["PROGSUFFIX"]}")).to be_truthy
|
||||
expect(`./two_sources`).to eq "This is a C program with two sources.\n"
|
||||
end
|
||||
|
||||
it "supports multiple values for ASSUFFIX" do
|
||||
test_dir("two_sources")
|
||||
env = Rscons::Environment.new() do |env|
|
||||
env["ASSUFFIX"] = %w[.ssss .sss]
|
||||
env["CFLAGS"] += %w[-S]
|
||||
env.Object("one.ssss", "one.c", "CPPFLAGS" => ["-DONE"])
|
||||
env.Object("two.sss", "two.c")
|
||||
env.Program("two_sources", %w[one.ssss two.sss], "ASFLAGS" => env["ASFLAGS"] + %w[-x assembler])
|
||||
end
|
||||
expect(lines).to eq([
|
||||
"CC one.ssss",
|
||||
"CC two.sss",
|
||||
"AS one.o",
|
||||
"AS two.o",
|
||||
"LD two_sources#{env["PROGSUFFIX"]}",
|
||||
])
|
||||
expect(File.exists?("two_sources#{env["PROGSUFFIX"]}")).to be_truthy
|
||||
expect(`./two_sources`).to eq "This is a C program with two sources.\n"
|
||||
end
|
||||
|
||||
end
|
||||
Reference in new issue
Block a user