rscons 0.0.14 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -1
- data/README.md +128 -11
- data/{Rakefile → Rakefile.rb} +8 -3
- data/build_tests/d/main.d +6 -0
- data/lib/rscons/builders/library.rb +2 -2
- data/lib/rscons/builders/object.rb +27 -28
- data/lib/rscons/builders/program.rb +17 -19
- data/lib/rscons/cache.rb +9 -9
- data/lib/rscons/environment.rb +52 -65
- data/lib/rscons/varset.rb +7 -11
- data/lib/rscons/version.rb +1 -1
- data/spec/build_tests_spec.rb +153 -52
- data/spec/rscons/cache_spec.rb +204 -0
- data/spec/rscons/environment_spec.rb +257 -6
- data/spec/rscons/varset_spec.rb +16 -11
- data/spec/rscons_spec.rb +26 -0
- data/spec/spec_helper.rb +3 -1
- metadata +10 -14
- data/build_tests/build_dir/build.rb +0 -5
- data/build_tests/build_dir/tweaker_build.rb +0 -12
- data/build_tests/clone_env/build.rb +0 -11
- data/build_tests/custom_builder/build.rb +0 -15
- data/build_tests/header/build.rb +0 -3
- data/build_tests/library/build.rb +0 -4
- data/build_tests/simple/build.rb +0 -4
- data/build_tests/simple_cc/build.rb +0 -4
- data/build_tests/two_sources/build.rb +0 -4
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
Software construction library inspired by SCons and implemented in Ruby
|
4
4
|
|
5
|
+
[![Gem Version](https://badge.fury.io/rb/rscons.png)](http://badge.fury.io/rb/rscons)
|
6
|
+
|
5
7
|
## Installation
|
6
8
|
|
7
9
|
Add this line to your application's Gemfile:
|
8
10
|
|
9
|
-
gem
|
11
|
+
gem "rscons"
|
10
12
|
|
11
13
|
And then execute:
|
12
14
|
|
@@ -18,20 +20,135 @@ Or install it yourself as:
|
|
18
20
|
|
19
21
|
## Usage
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
-
|
23
|
+
Rscons is a Ruby library.
|
24
|
+
It can be called from a standalone Ruby script or it can be used with rake and
|
25
|
+
called from your Rakefile.
|
26
|
+
|
27
|
+
### Example: Building a C Program
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
RScons::Environment.new do |env|
|
31
|
+
env["CFLAGS"] << "-Wall"
|
32
|
+
env.Program("program", Dir["**/*.c"])
|
33
|
+
end
|
34
|
+
```
|
35
|
+
|
36
|
+
### Example: Building a D Program
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
RScons::Environment.new do |env|
|
40
|
+
env["DFLAGS"] << "-Wall"
|
41
|
+
env.Program("program", Dir["**/*.d"])
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
### Example: Cloning an Environment
|
24
46
|
|
25
|
-
|
26
|
-
|
27
|
-
|
47
|
+
```ruby
|
48
|
+
main_env = RScons::Environment.new do |env|
|
49
|
+
# Store object files from sources under "src" in "build/main"
|
50
|
+
env.build_dir("src", "build/main")
|
51
|
+
env["CFLAGS"] = ["-DSOME_DEFINE", "-O3"]
|
52
|
+
env["LIBS"] = ["SDL"]
|
53
|
+
env.Program("program", Dir["src/**/*.cc"])
|
54
|
+
end
|
55
|
+
|
56
|
+
debug_env = main_env.clone do |env|
|
57
|
+
# Store object files from sources under "src" in "build/debug"
|
58
|
+
env.build_dir("src", "build/debug")
|
59
|
+
env["CFLAGS"] -= ["-O3"]
|
60
|
+
env["CFLAGS"] += ["-g", "-O0"]
|
61
|
+
env.Program("program-debug", Dir["src/**/*.cc"])
|
62
|
+
end
|
63
|
+
```
|
64
|
+
|
65
|
+
### Example: Custom Builder
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class GenerateFoo < Rscons::Builder
|
69
|
+
def run(target, sources, cache, env, vars)
|
70
|
+
File.open(target, "w") do |fh|
|
71
|
+
fh.puts <<EOF
|
72
|
+
#define GENERATED 42
|
73
|
+
EOF
|
28
74
|
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
Rscons::Environment.new do |env|
|
79
|
+
env.GenerateFoo("foo.h", [])
|
80
|
+
env.Program("a.out", Dir["*.c"])
|
81
|
+
end
|
82
|
+
```
|
29
83
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
84
|
+
### Example: Using different compilation flags for some sources
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
Rscons::Environment.new do |env|
|
88
|
+
env["CFLAGS"] = ["-O3", "-Wall", "-DDEFINE"]
|
89
|
+
env.add_build_hook do |build_op|
|
90
|
+
if build_op[:target] =~ %r{build/third-party}
|
91
|
+
build_op[:vars]["CFLAGS"] -= ["-Wall"]
|
34
92
|
end
|
93
|
+
end
|
94
|
+
env.build_dir("src", "build")
|
95
|
+
env.Program("program", Dir["**/*.cc"])
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
### Example: Creating a static library
|
100
|
+
|
101
|
+
```ruby
|
102
|
+
Rscons::Environment.new do |env|
|
103
|
+
env.Library("mylib.a", Dir["src/**/*.c"])
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
107
|
+
## Details
|
108
|
+
|
109
|
+
### Default Builders
|
110
|
+
|
111
|
+
Rscons ships with a number of default builders:
|
112
|
+
|
113
|
+
* Library, which collects object files into a static library archive file
|
114
|
+
* Object, which compiles source files to produce an object file
|
115
|
+
* Program, which links object files to produce an executable
|
116
|
+
|
117
|
+
If you want to create an Environment that does not contain any (or select)
|
118
|
+
builders, you can use the `exclude_builders` key to the Environment constructor.
|
119
|
+
|
120
|
+
### Managing Environments
|
121
|
+
|
122
|
+
An Rscons::Environment consists of:
|
123
|
+
|
124
|
+
* a collection of construction variables
|
125
|
+
* a collection of builders
|
126
|
+
* a mapping of build directories
|
127
|
+
* a collection of targets to build
|
128
|
+
* a collection of build hooks
|
129
|
+
|
130
|
+
When cloning an environment, the construction variables, builders, and build
|
131
|
+
directories are cloned, but the new environment does not inherit any of the
|
132
|
+
targets or build hooks from the source environment.
|
133
|
+
|
134
|
+
Cloned environments contain "deep copies" of construction variables.
|
135
|
+
For example, in:
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
base_env = Rscons::Environment.new
|
139
|
+
base_env["CPPPATH"] = ["one", "two"]
|
140
|
+
cloned_env = base_env.clone
|
141
|
+
cloned_env["CPPPATH"] << "three"
|
142
|
+
```
|
143
|
+
|
144
|
+
`base_env["CPPPATH"]` will not include "three".
|
145
|
+
|
146
|
+
### Construction Variables
|
147
|
+
|
148
|
+
The default construction variables that Rscons uses are named using uppercase
|
149
|
+
strings.
|
150
|
+
Rscons options are lowercase symbols.
|
151
|
+
Lowercase strings are reserved as user-defined construction variables.
|
35
152
|
|
36
153
|
## Contributing
|
37
154
|
|
data/{Rakefile → Rakefile.rb}
RENAMED
@@ -7,11 +7,8 @@ end
|
|
7
7
|
|
8
8
|
require "bundler/gem_tasks"
|
9
9
|
require "rspec/core/rake_task"
|
10
|
-
require "rake/clean"
|
11
10
|
require "yard"
|
12
11
|
|
13
|
-
CLEAN.include 'build_tests_run'
|
14
|
-
|
15
12
|
RSpec::Core::RakeTask.new(:spec)
|
16
13
|
|
17
14
|
YARD::Rake::YardocTask.new do |yard|
|
@@ -19,3 +16,11 @@ YARD::Rake::YardocTask.new do |yard|
|
|
19
16
|
end
|
20
17
|
|
21
18
|
task :default => :spec
|
19
|
+
|
20
|
+
task :clean do
|
21
|
+
FileUtils.rm_rf(["build_test_run", "doc", "coverage"])
|
22
|
+
end
|
23
|
+
|
24
|
+
task :clobber => :clean do
|
25
|
+
FileUtils.rm_rf(["pkg"])
|
26
|
+
end
|
@@ -8,7 +8,7 @@ module Rscons
|
|
8
8
|
'AR' => 'ar',
|
9
9
|
'LIBSUFFIX' => '.a',
|
10
10
|
'ARFLAGS' => [],
|
11
|
-
'
|
11
|
+
'ARCMD' => ['${AR}', 'rcs', '${ARFLAGS}', '${_TARGET}', '${_SOURCES}']
|
12
12
|
}
|
13
13
|
end
|
14
14
|
|
@@ -20,7 +20,7 @@ module Rscons
|
|
20
20
|
'_TARGET' => target,
|
21
21
|
'_SOURCES' => objects,
|
22
22
|
})
|
23
|
-
command = env.build_command(env['
|
23
|
+
command = env.build_command(env['ARCMD'], vars)
|
24
24
|
standard_build("AR #{target}", target, command, objects, env, cache)
|
25
25
|
end
|
26
26
|
end
|
@@ -2,17 +2,24 @@ module Rscons
|
|
2
2
|
# A default RScons builder which knows how to produce an object file from
|
3
3
|
# various types of source files.
|
4
4
|
class Object < Builder
|
5
|
+
KNOWN_SUFFIXES = {
|
6
|
+
"AS" => "ASSUFFIX",
|
7
|
+
"CC" => "CSUFFIX",
|
8
|
+
"CXX" => "CXXSUFFIX",
|
9
|
+
"DC" => "DSUFFIX",
|
10
|
+
}
|
11
|
+
|
5
12
|
def default_variables(env)
|
6
13
|
{
|
7
14
|
'OBJSUFFIX' => '.o',
|
8
15
|
|
9
|
-
'AS' => '$CC',
|
16
|
+
'AS' => '${CC}',
|
10
17
|
'ASFLAGS' => [],
|
11
18
|
'ASSUFFIX' => '.S',
|
12
|
-
'ASPPPATH' => '$CPPPATH',
|
13
|
-
'ASPPFLAGS' => '$CPPFLAGS',
|
14
|
-
'ASDEPGEN' => ['-MMD', '-MF', '$_DEPFILE'],
|
15
|
-
'
|
19
|
+
'ASPPPATH' => '${CPPPATH}',
|
20
|
+
'ASPPFLAGS' => '${CPPFLAGS}',
|
21
|
+
'ASDEPGEN' => ['-MMD', '-MF', '${_DEPFILE}'],
|
22
|
+
'ASCMD' => ['${AS}', '-c', '-o', '${_TARGET}', '${ASDEPGEN}', '-I${ASPPPATH}', '${ASPPFLAGS}', '${ASFLAGS}', '${_SOURCES}'],
|
16
23
|
|
17
24
|
'CPPFLAGS' => [],
|
18
25
|
'CPPPATH' => [],
|
@@ -20,29 +27,27 @@ module Rscons
|
|
20
27
|
'CC' => 'gcc',
|
21
28
|
'CFLAGS' => [],
|
22
29
|
'CSUFFIX' => '.c',
|
23
|
-
'CCDEPGEN' => ['-MMD', '-MF', '$_DEPFILE'],
|
24
|
-
'
|
30
|
+
'CCDEPGEN' => ['-MMD', '-MF', '${_DEPFILE}'],
|
31
|
+
'CCCMD' => ['${CC}', '-c', '-o', '${_TARGET}', '${CCDEPGEN}', '-I${CPPPATH}', '${CPPFLAGS}', '${CFLAGS}', '${_SOURCES}'],
|
25
32
|
|
26
33
|
'CXX' => 'g++',
|
27
34
|
'CXXFLAGS' => [],
|
28
35
|
'CXXSUFFIX' => '.cc',
|
29
|
-
'CXXDEPGEN' => ['-MMD', '-MF', '$_DEPFILE'],
|
30
|
-
'
|
36
|
+
'CXXDEPGEN' => ['-MMD', '-MF', '${_DEPFILE}'],
|
37
|
+
'CXXCMD' =>['${CXX}', '-c', '-o', '${_TARGET}', '${CXXDEPGEN}', '-I${CPPPATH}', '${CPPFLAGS}', '${CXXFLAGS}', '${_SOURCES}'],
|
31
38
|
|
32
39
|
'DC' => 'gdc',
|
33
40
|
'DFLAGS' => [],
|
34
41
|
'DSUFFIX' => '.d',
|
35
42
|
'D_IMPORT_PATH' => [],
|
36
|
-
'
|
43
|
+
'DCCMD' => ['${DC}', '-c', '-o', '${_TARGET}', '-I${D_IMPORT_PATH}', '${DFLAGS}', '${_SOURCES}'],
|
37
44
|
}
|
38
45
|
end
|
39
46
|
|
40
47
|
def produces?(target, source, env)
|
41
|
-
target.has_suffix?(env['OBJSUFFIX']) and
|
42
|
-
source.has_suffix?(env[
|
43
|
-
|
44
|
-
source.has_suffix?(env['CXXSUFFIX']) or
|
45
|
-
source.has_suffix?(env['DSUFFIX']))
|
48
|
+
target.has_suffix?(env['OBJSUFFIX']) and KNOWN_SUFFIXES.find do |compiler, suffix_var|
|
49
|
+
source.has_suffix?(env[suffix_var])
|
50
|
+
end
|
46
51
|
end
|
47
52
|
|
48
53
|
def run(target, sources, cache, env, vars = {})
|
@@ -51,25 +56,19 @@ module Rscons
|
|
51
56
|
'_SOURCES' => sources,
|
52
57
|
'_DEPFILE' => target.set_suffix('.mf'),
|
53
58
|
})
|
54
|
-
com_prefix =
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
elsif sources.first.has_suffix?(env['DSUFFIX'])
|
61
|
-
'DC'
|
62
|
-
else
|
63
|
-
raise "Error: unknown input file type: #{sources.first.inspect}"
|
64
|
-
end
|
65
|
-
command = env.build_command(env["#{com_prefix}COM"], vars)
|
59
|
+
com_prefix = KNOWN_SUFFIXES.find do |compiler, suffix_var|
|
60
|
+
sources.first.has_suffix?(env[suffix_var])
|
61
|
+
end.tap do |v|
|
62
|
+
v.nil? and raise "Error: unknown input file type: #{sources.first.inspect}"
|
63
|
+
end.first
|
64
|
+
command = env.build_command(env["#{com_prefix}CMD"], vars)
|
66
65
|
unless cache.up_to_date?(target, command, sources)
|
67
66
|
cache.mkdir_p(File.dirname(target))
|
68
67
|
FileUtils.rm_f(target)
|
69
68
|
return false unless env.execute("#{com_prefix} #{target}", command)
|
70
69
|
deps = sources
|
71
70
|
if File.exists?(vars['_DEPFILE'])
|
72
|
-
deps +=
|
71
|
+
deps += Environment.parse_makefile_deps(vars['_DEPFILE'], target)
|
73
72
|
FileUtils.rm_f(vars['_DEPFILE'])
|
74
73
|
end
|
75
74
|
cache.register_build(target, command, deps.uniq)
|
@@ -10,31 +10,29 @@ module Rscons
|
|
10
10
|
'LDFLAGS' => [],
|
11
11
|
'LIBPATH' => [],
|
12
12
|
'LIBS' => [],
|
13
|
-
'
|
13
|
+
'LDCMD' => ['${LD}', '-o', '${_TARGET}', '${LDFLAGS}', '${_SOURCES}', '-L${LIBPATH}', '-l${LIBS}']
|
14
14
|
}
|
15
15
|
end
|
16
16
|
|
17
17
|
def run(target, sources, cache, env, vars = {})
|
18
18
|
# build sources to linkable objects
|
19
19
|
objects = env.build_sources(sources, [env['OBJSUFFIX'], env['LIBSUFFIX']].flatten, cache, vars)
|
20
|
-
if
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
standard_build("LD #{target}", target, command, objects, env, cache)
|
37
|
-
end
|
20
|
+
ld = if env["LD"]
|
21
|
+
env["LD"]
|
22
|
+
elsif sources.find {|s| s.has_suffix?(env["DSUFFIX"])}
|
23
|
+
env["DC"]
|
24
|
+
elsif sources.find {|s| s.has_suffix?(env["CXXSUFFIX"])}
|
25
|
+
env["CXX"]
|
26
|
+
else
|
27
|
+
env["CC"]
|
28
|
+
end
|
29
|
+
vars = vars.merge({
|
30
|
+
'_TARGET' => target,
|
31
|
+
'_SOURCES' => objects,
|
32
|
+
'LD' => ld,
|
33
|
+
})
|
34
|
+
command = env.build_command(env['LDCMD'], vars)
|
35
|
+
standard_build("LD #{target}", target, command, objects, env, cache)
|
38
36
|
end
|
39
37
|
end
|
40
38
|
end
|
data/lib/rscons/cache.rb
CHANGED
@@ -67,12 +67,12 @@ module Rscons
|
|
67
67
|
end
|
68
68
|
@cache[:targets] ||= {}
|
69
69
|
@cache[:directories] ||= {}
|
70
|
-
@cache[:version] ||= VERSION
|
71
70
|
@lookup_checksums = {}
|
72
71
|
end
|
73
72
|
|
74
73
|
# Write the cache to disk to be loaded next time.
|
75
74
|
def write
|
75
|
+
@cache[:version] = VERSION
|
76
76
|
File.open(CACHE_FILE, 'w') do |fh|
|
77
77
|
fh.puts(YAML.dump(@cache))
|
78
78
|
end
|
@@ -119,9 +119,11 @@ module Rscons
|
|
119
119
|
end
|
120
120
|
|
121
121
|
# all cached dependencies must have their checksums match
|
122
|
-
@cache[:targets][target][:deps].
|
123
|
-
dep_cache[:checksum] == lookup_checksum(dep_cache[:fname])
|
124
|
-
end
|
122
|
+
@cache[:targets][target][:deps].each do |dep_cache|
|
123
|
+
return false unless dep_cache[:checksum] == lookup_checksum(dep_cache[:fname])
|
124
|
+
end
|
125
|
+
|
126
|
+
true
|
125
127
|
end
|
126
128
|
|
127
129
|
# Store cache information about a target built by a builder
|
@@ -150,13 +152,11 @@ module Rscons
|
|
150
152
|
# removal upon a "clean" operation.
|
151
153
|
def mkdir_p(path)
|
152
154
|
parts = path.split(/[\\\/]/)
|
153
|
-
(0..parts.size).each do |i|
|
155
|
+
(0..parts.size-1).each do |i|
|
154
156
|
subpath = File.join(*parts[0, i + 1]).encode(__ENCODING__)
|
155
157
|
unless File.exists?(subpath)
|
156
158
|
FileUtils.mkdir(subpath)
|
157
|
-
|
158
|
-
@cache[:directories][subpath] = true
|
159
|
-
end
|
159
|
+
@cache[:directories][subpath] = true
|
160
160
|
end
|
161
161
|
end
|
162
162
|
end
|
@@ -179,7 +179,7 @@ module Rscons
|
|
179
179
|
# Calculate and return a file's checksum
|
180
180
|
# @param file [String] The file name.
|
181
181
|
def calculate_checksum(file)
|
182
|
-
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file,
|
182
|
+
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: 'rb')).encode(__ENCODING__) rescue ''
|
183
183
|
end
|
184
184
|
end
|
185
185
|
end
|
data/lib/rscons/environment.rb
CHANGED
@@ -6,7 +6,7 @@ module Rscons
|
|
6
6
|
# contains a collection of construction variables, options, builders, and
|
7
7
|
# rules for building targets.
|
8
8
|
class Environment
|
9
|
-
#
|
9
|
+
# Hash of +{"builder_name" => builder_object}+ pairs.
|
10
10
|
attr_reader :builders
|
11
11
|
|
12
12
|
# Create an Environment object.
|
@@ -22,7 +22,7 @@ module Rscons
|
|
22
22
|
@targets = {}
|
23
23
|
@builders = {}
|
24
24
|
@build_dirs = []
|
25
|
-
@
|
25
|
+
@build_hooks = []
|
26
26
|
@varset[:exclude_builders] ||= []
|
27
27
|
unless @varset[:exclude_builders] == :all
|
28
28
|
exclude_builders = Set.new(@varset[:exclude_builders] || [])
|
@@ -32,10 +32,7 @@ module Rscons
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
36
|
-
add_builder(builder)
|
37
|
-
end
|
38
|
-
@varset[:echo] ||= :command
|
35
|
+
@varset[:echo] ||= :short
|
39
36
|
|
40
37
|
if block_given?
|
41
38
|
yield self
|
@@ -46,7 +43,7 @@ module Rscons
|
|
46
43
|
# Make a copy of the Environment object.
|
47
44
|
# The cloned environment will contain a copy of all environment options,
|
48
45
|
# construction variables, builders, and build directories. It will not
|
49
|
-
# contain a copy of the targets or
|
46
|
+
# contain a copy of the targets or build hooks.
|
50
47
|
# If a block is given, the Environment object is yielded to the block and
|
51
48
|
# when the block returns, the {#process} method is automatically called.
|
52
49
|
def clone(variables = {})
|
@@ -75,9 +72,9 @@ module Rscons
|
|
75
72
|
end
|
76
73
|
end
|
77
74
|
|
78
|
-
# Add a
|
79
|
-
def
|
80
|
-
@
|
75
|
+
# Add a build hook to the Environment.
|
76
|
+
def add_build_hook(&block)
|
77
|
+
@build_hooks << block
|
81
78
|
end
|
82
79
|
|
83
80
|
# Specify a build directory for this Environment.
|
@@ -89,8 +86,6 @@ module Rscons
|
|
89
86
|
|
90
87
|
# Return the file name to be built from source_fname with suffix suffix.
|
91
88
|
# This method takes into account the Environment's build directories.
|
92
|
-
# It also creates any parent directories needed to be able to open and
|
93
|
-
# write to the output file.
|
94
89
|
def get_build_fname(source_fname, suffix)
|
95
90
|
build_fname = source_fname.set_suffix(suffix).gsub('\\', '/')
|
96
91
|
@build_dirs.each do |src_dir, obj_dir|
|
@@ -122,41 +117,33 @@ module Rscons
|
|
122
117
|
@varset.send(:append, *args)
|
123
118
|
end
|
124
119
|
|
125
|
-
# Return a list of target file names
|
126
|
-
def targets
|
127
|
-
@targets.keys
|
128
|
-
end
|
129
|
-
|
130
|
-
# Return a list of sources needed to build target target.
|
131
|
-
def target_sources(target)
|
132
|
-
@targets[target][:source] rescue nil
|
133
|
-
end
|
134
|
-
|
135
120
|
# Build all target specified in the Environment.
|
136
121
|
# When a block is passed to Environment.new, this method is automatically
|
137
122
|
# called after the block returns.
|
138
123
|
def process
|
139
124
|
cache = Cache.new
|
140
|
-
targets_processed =
|
125
|
+
targets_processed = {}
|
141
126
|
process_target = proc do |target|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
127
|
+
targets_processed[target] ||= begin
|
128
|
+
@targets[target][:source].each do |src|
|
129
|
+
if @targets.include?(src) and not targets_processed.include?(src)
|
130
|
+
process_target.call(src)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
result = run_builder(@targets[target][:builder],
|
134
|
+
target,
|
135
|
+
@targets[target][:source],
|
136
|
+
cache,
|
137
|
+
@targets[target][:vars] || {})
|
138
|
+
unless result
|
139
|
+
cache.write
|
140
|
+
raise BuildError.new("Failed to build #{target}")
|
141
|
+
end
|
142
|
+
result
|
152
143
|
end
|
153
144
|
end
|
154
145
|
@targets.each do |target, info|
|
155
|
-
|
156
|
-
unless process_target.call(target)
|
157
|
-
cache.write
|
158
|
-
raise BuildError.new("Failed to build #{target}")
|
159
|
-
end
|
146
|
+
process_target.call(target)
|
160
147
|
end
|
161
148
|
cache.write
|
162
149
|
end
|
@@ -177,7 +164,7 @@ module Rscons
|
|
177
164
|
# @param short_desc [String] Message to print if the Environment's :echo
|
178
165
|
# mode is set to :short
|
179
166
|
# @param command [Array] The command to execute.
|
180
|
-
# @param options [Hash] Optional options to pass to
|
167
|
+
# @param options [Hash] Optional options to pass to Kernel#system.
|
181
168
|
def execute(short_desc, command, options = {})
|
182
169
|
print_command = proc do
|
183
170
|
puts command.map { |c| c =~ /\s/ ? "'#{c}'" : c }.join(' ')
|
@@ -214,30 +201,6 @@ module Rscons
|
|
214
201
|
end
|
215
202
|
end
|
216
203
|
|
217
|
-
# Parse dependencies for a given target from a Makefile.
|
218
|
-
# This method is used internally by RScons builders.
|
219
|
-
# @param mf_fname [String] File name of the Makefile to read.
|
220
|
-
# @param target [String] Name of the target to gather dependencies for.
|
221
|
-
def parse_makefile_deps(mf_fname, target)
|
222
|
-
deps = []
|
223
|
-
buildup = ''
|
224
|
-
File.read(mf_fname).each_line do |line|
|
225
|
-
if line =~ /^(.*)\\\s*$/
|
226
|
-
buildup += ' ' + $1
|
227
|
-
else
|
228
|
-
buildup += ' ' + line
|
229
|
-
if buildup =~ /^(.*): (.*)$/
|
230
|
-
mf_target, mf_deps = $1.strip, $2
|
231
|
-
if mf_target == target
|
232
|
-
deps += mf_deps.split(' ').map(&:strip)
|
233
|
-
end
|
234
|
-
end
|
235
|
-
buildup = ''
|
236
|
-
end
|
237
|
-
end
|
238
|
-
deps
|
239
|
-
end
|
240
|
-
|
241
204
|
# Build a list of source files into files containing one of the suffixes
|
242
205
|
# given by suffixes.
|
243
206
|
# This method is used internally by RScons builders.
|
@@ -275,16 +238,40 @@ module Rscons
|
|
275
238
|
# Return the result of the builder's run() method.
|
276
239
|
def run_builder(builder, target, sources, cache, vars)
|
277
240
|
vars = @varset.merge(vars)
|
278
|
-
@
|
241
|
+
@build_hooks.each do |build_hook_block|
|
279
242
|
build_operation = {
|
280
243
|
builder: builder,
|
281
244
|
target: target,
|
282
245
|
sources: sources,
|
283
246
|
vars: vars,
|
284
247
|
}
|
285
|
-
|
248
|
+
build_hook_block.call(build_operation)
|
286
249
|
end
|
287
250
|
builder.run(target, sources, cache, self, vars)
|
288
251
|
end
|
252
|
+
|
253
|
+
# Parse dependencies for a given target from a Makefile.
|
254
|
+
# This method is used internally by RScons builders.
|
255
|
+
# @param mf_fname [String] File name of the Makefile to read.
|
256
|
+
# @param target [String] Name of the target to gather dependencies for.
|
257
|
+
def self.parse_makefile_deps(mf_fname, target)
|
258
|
+
deps = []
|
259
|
+
buildup = ''
|
260
|
+
File.read(mf_fname).each_line do |line|
|
261
|
+
if line =~ /^(.*)\\\s*$/
|
262
|
+
buildup += ' ' + $1
|
263
|
+
else
|
264
|
+
buildup += ' ' + line
|
265
|
+
if buildup =~ /^(.*): (.*)$/
|
266
|
+
mf_target, mf_deps = $1.strip, $2
|
267
|
+
if mf_target == target
|
268
|
+
deps += mf_deps.split(' ').map(&:strip)
|
269
|
+
end
|
270
|
+
end
|
271
|
+
buildup = ''
|
272
|
+
end
|
273
|
+
end
|
274
|
+
deps
|
275
|
+
end
|
289
276
|
end
|
290
277
|
end
|