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 CHANGED
@@ -15,4 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
- build_tests_run
18
+ build_test_run
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 'rscons'
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
- RScons::Environment.new do |env|
22
- env.Program('program', Dir['*.c'])
23
- end
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
- main_env = RScons::Environment.new do |env|
26
- env.build_dir('src', 'build/main')
27
- env.Program('program', Dir['src/**/*.cc'])
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
- debug_env = main_env.clone do |env|
31
- env.build_dir('src', 'build/debug')
32
- env['CFLAGS'] = ['-g', '-O0']
33
- env.Program('program-debug', Dir['src/**/*.cc'])
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
 
@@ -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
@@ -0,0 +1,6 @@
1
+ import std.stdio;
2
+
3
+ void main()
4
+ {
5
+ writeln("Hello from D!");
6
+ }
@@ -8,7 +8,7 @@ module Rscons
8
8
  'AR' => 'ar',
9
9
  'LIBSUFFIX' => '.a',
10
10
  'ARFLAGS' => [],
11
- 'ARCOM' => ['$AR', 'rcs', '$ARFLAGS', '$_TARGET', '$_SOURCES']
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['ARCOM'], vars)
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
- 'ASCOM' => ['$AS', '-c', '-o', '$_TARGET', '$ASDEPGEN', '-I$[ASPPPATH]', '$ASPPFLAGS', '$ASFLAGS', '$_SOURCES'],
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
- 'CCCOM' => ['$CC', '-c', '-o', '$_TARGET', '$CCDEPGEN', '-I$[CPPPATH]', '$CPPFLAGS', '$CFLAGS', '$_SOURCES'],
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
- 'CXXCOM' =>['$CXX', '-c', '-o', '$_TARGET', '$CXXDEPGEN', '-I$[CPPPATH]', '$CPPFLAGS', '$CXXFLAGS', '$_SOURCES'],
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
- 'DCCOM' => ['$DC', '-c', '-o', '$_TARGET', '-I$[D_IMPORT_PATH]', '$DFLAGS', '$_SOURCES'],
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['ASSUFFIX']) or
43
- source.has_suffix?(env['CSUFFIX']) or
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 = if sources.first.has_suffix?(env['ASSUFFIX'])
55
- 'AS'
56
- elsif sources.first.has_suffix?(env['CSUFFIX'])
57
- 'CC'
58
- elsif sources.first.has_suffix?(env['CXXSUFFIX'])
59
- 'CXX'
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 += env.parse_makefile_deps(vars['_DEPFILE'], target)
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
- 'LDCOM' => ['$LD', '-o', '$_TARGET', '$LDFLAGS', '$_SOURCES', '-L$[LIBPATH]', '-l$[LIBS]']
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 objects
21
- ld = if env["LD"]
22
- env["LD"]
23
- elsif sources.find {|s| s.has_suffix?(env["DSUFFIX"])}
24
- env["DC"]
25
- elsif sources.find {|s| s.has_suffix?(env["CXXSUFFIX"])}
26
- env["CXX"]
27
- else
28
- env["CC"]
29
- end
30
- vars = vars.merge({
31
- '_TARGET' => target,
32
- '_SOURCES' => objects,
33
- 'LD' => ld,
34
- })
35
- command = env.build_command(env['LDCOM'], vars)
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
@@ -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].map do |dep_cache|
123
- dep_cache[:checksum] == lookup_checksum(dep_cache[:fname])
124
- end.all?
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
- unless @cache[:directories].include?(subpath)
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, {mode: 'rb'})).encode(__ENCODING__) rescue ''
182
+ @lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: 'rb')).encode(__ENCODING__) rescue ''
183
183
  end
184
184
  end
185
185
  end
@@ -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
- # [Hash] of {"builder_name" => builder_object} pairs.
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
- @tweakers = []
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
- (@varset[:builders] || []).each do |builder|
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 tweakers.
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 tweaker block to the Environment.
79
- def add_tweaker(&block)
80
- @tweakers << block
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 = Set.new
125
+ targets_processed = {}
141
126
  process_target = proc do |target|
142
- if @targets[target][:source].map do |src|
143
- targets_processed.include?(src) or not @targets.include?(src) or process_target.call(src)
144
- end.all?
145
- run_builder(@targets[target][:builder],
146
- target,
147
- @targets[target][:source],
148
- cache,
149
- @targets[target][:vars] || {})
150
- else
151
- false
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
- next if targets_processed.include?(target)
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 {Kernel#system}.
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
- @tweakers.each do |tweaker_block|
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
- tweaker_block.call(build_operation)
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