rscons 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +8 -8
- data/README.md +112 -10
- data/lib/rscons.rb +8 -2
- data/lib/rscons/builders/cfile.rb +40 -0
- data/lib/rscons/builders/disassemble.rb +25 -0
- data/lib/rscons/builders/library.rb +1 -1
- data/lib/rscons/builders/preprocess.rb +25 -0
- data/lib/rscons/builders/program.rb +1 -1
- data/lib/rscons/cache.rb +96 -80
- data/lib/rscons/environment.rb +63 -32
- data/lib/rscons/varset.rb +75 -18
- data/lib/rscons/version.rb +1 -1
- data/spec/build_tests_spec.rb +56 -0
- data/spec/rscons/builders/cfile_spec.rb +23 -0
- data/spec/rscons/cache_spec.rb +85 -68
- data/spec/rscons/environment_spec.rb +23 -6
- data/spec/rscons/varset_spec.rb +63 -17
- data/spec/rscons_spec.rb +2 -2
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NWMyYzkzNjU2MTQ1MmRiOTFkMjhlMzVlMjYzM2Q0MTJkOWRjMWM5Yw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
M2QyYmEwN2U2MGUyNGJkYjI4ODVjYWU5MzUyNWRiZTEzMWYxNDE3Mw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MzkyZDE0ZjQ2M2NlNTdmMTZiNzNmNDIwMjUwMmEwZjI1N2Y5Mjg3YTU0YjYy
|
10
|
+
MWQwYjgwOGM2MGY3NjA0ZjlmZGM5ZThhN2UyZWM1OGIwMzk5MjQ2YzFhZjA1
|
11
|
+
N2FhMWI2ZjY2Njk1YjkwOWUwNGI5MjQ4MGU2N2U2NjM5NDlkYWM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YWRmNzc3OGU0NmE3ZTUzOWZkYmM5MjQ5OGU0ZTA2MWM2MmRlNzAyMzRiZTQx
|
14
|
+
YTc2NjRjYmZmYjU0MjA2ZmUyNmY5ZGI4OTZjN2Q5MzcyYzQ1ZWQ3Njg5MTc3
|
15
|
+
ZmVlY2NiZmViYmQyOWFmM2Q3MWEzMWY5ZTRkMjQ4ODYwNGM1ZmY=
|
data/README.md
CHANGED
@@ -12,7 +12,7 @@ Add this line to your application's Gemfile:
|
|
12
12
|
|
13
13
|
And then execute:
|
14
14
|
|
15
|
-
$ bundle
|
15
|
+
$ bundle install
|
16
16
|
|
17
17
|
Or install it yourself as:
|
18
18
|
|
@@ -176,11 +176,14 @@ subset of build targets or source files.
|
|
176
176
|
The `build_op` parameter to the build hook block is a Hash describing the
|
177
177
|
build operation with the following keys:
|
178
178
|
* `:builder` - `Builder` instance in use
|
179
|
+
* `:env` - `Environment` calling the build hook; note that this may be
|
180
|
+
different from the Environment that the build hook was added to in the case
|
181
|
+
that the original Environment was cloned with build hooks!
|
179
182
|
* `:target` - `String` name of the target file
|
180
183
|
* `:sources` - `Array` of the source files
|
181
|
-
* `:vars` - `Rscons::VarSet` containing the construction variables to use
|
182
|
-
The build hook can overwrite entries in `build_op[:vars]` to alter the
|
183
|
-
construction variables in use for this specific build operation.
|
184
|
+
* `:vars` - `Rscons::VarSet` containing the construction variables to use.
|
185
|
+
The build hook can overwrite entries in `build_op[:vars]` to alter the
|
186
|
+
construction variables in use for this specific build operation.
|
184
187
|
|
185
188
|
### Example: Creating a static library
|
186
189
|
|
@@ -190,19 +193,96 @@ Rscons::Environment.new do |env|
|
|
190
193
|
end
|
191
194
|
```
|
192
195
|
|
196
|
+
### Example: Creating a C++ parser source from a Yacc/Bison input file
|
197
|
+
|
198
|
+
```ruby
|
199
|
+
Rscons::Environment.new do |env|
|
200
|
+
env.CFile("#{env.build_root}/parser.tab.cc", "parser.yy")
|
201
|
+
end
|
202
|
+
```
|
203
|
+
|
193
204
|
## Details
|
194
205
|
|
195
|
-
###
|
206
|
+
### Builders
|
196
207
|
|
197
|
-
Rscons ships with a number of
|
208
|
+
Rscons ships with a number of builders:
|
198
209
|
|
210
|
+
* CFile, which builds a C or C++ source file from a lex or yacc input file
|
211
|
+
* Disassemble, which disassembles an object file to a disassembly listing
|
199
212
|
* Library, which collects object files into a static library archive file
|
200
213
|
* Object, which compiles source files to produce an object file
|
214
|
+
* Preprocess, which invokes the C/C++ preprocessor on a source file
|
201
215
|
* Program, which links object files to produce an executable
|
202
216
|
|
203
217
|
If you want to create an Environment that does not contain any builders,
|
204
218
|
you can use the `exclude_builders` key to the Environment constructor.
|
205
219
|
|
220
|
+
#### CFile
|
221
|
+
|
222
|
+
```ruby
|
223
|
+
env.CFile(target, source)
|
224
|
+
# Example
|
225
|
+
env.CFile("parser.c", "parser.y")
|
226
|
+
```
|
227
|
+
|
228
|
+
The CFile builder will generate a C or C++ source file from a lex (.l, .ll)
|
229
|
+
or yacc (.y, .yy) input file.
|
230
|
+
|
231
|
+
#### Disassemble
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
env.Disassemble(target, source)
|
235
|
+
# Example
|
236
|
+
env.Disassemble("module.dis", "module.o")
|
237
|
+
```
|
238
|
+
|
239
|
+
The Disassemble builder generates a disassembly listing using objdump from
|
240
|
+
and object file.
|
241
|
+
|
242
|
+
#### Library
|
243
|
+
|
244
|
+
```ruby
|
245
|
+
env.Library(target, sources)
|
246
|
+
# Example
|
247
|
+
env.Library("lib.a", Dir["src/**/*.c"])
|
248
|
+
```
|
249
|
+
|
250
|
+
The Library builder creates a static library archive from the given source
|
251
|
+
files.
|
252
|
+
|
253
|
+
#### Object
|
254
|
+
|
255
|
+
```ruby
|
256
|
+
env.Object(target, sources)
|
257
|
+
# Example
|
258
|
+
env.Object("module.o", "module.c")
|
259
|
+
```
|
260
|
+
|
261
|
+
The Object builder compiles the given sources to an object file.
|
262
|
+
|
263
|
+
#### Preprocess
|
264
|
+
|
265
|
+
```ruby
|
266
|
+
env.Preprocess(target, source)
|
267
|
+
# Example
|
268
|
+
env.Preprocess("module-preprocessed.cc", "module.cc")
|
269
|
+
```
|
270
|
+
|
271
|
+
The Preprocess builder invokes either ${CC} or ${CXX} (depending on if the
|
272
|
+
source contains an extension in ${CXXSUFFIX} or not) and writes the
|
273
|
+
preprocessed output to the target file.
|
274
|
+
|
275
|
+
#### Program
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
env.Program(target, sources)
|
279
|
+
# Example
|
280
|
+
env.Program("myprog", Dir["src/**/*.cc"])
|
281
|
+
```
|
282
|
+
|
283
|
+
The Program builder compiles and links the given sources to an executable file.
|
284
|
+
Object files or source files can be given as `sources`.
|
285
|
+
|
206
286
|
### Managing Environments
|
207
287
|
|
208
288
|
An Rscons::Environment consists of:
|
@@ -214,10 +294,17 @@ An Rscons::Environment consists of:
|
|
214
294
|
* a collection of targets to build
|
215
295
|
* a collection of build hooks
|
216
296
|
|
217
|
-
When cloning an environment, the construction variables and builders
|
218
|
-
cloned, but the new environment does not inherit any of the targets, build
|
297
|
+
When cloning an environment, by default the construction variables and builders
|
298
|
+
are cloned, but the new environment does not inherit any of the targets, build
|
219
299
|
hooks, build directories, or the build root from the source environment.
|
220
300
|
|
301
|
+
The set of environment attributes that are cloned is controllable via the
|
302
|
+
`:clone` option to the `#clone` method.
|
303
|
+
For example, `env.clone(clone: :all)` will include construction variables,
|
304
|
+
builders, build hooks, build directories, and the build root.
|
305
|
+
|
306
|
+
The set of pending targets is never cloned.
|
307
|
+
|
221
308
|
Cloned environments contain "deep copies" of construction variables.
|
222
309
|
For example, in:
|
223
310
|
|
@@ -233,8 +320,7 @@ cloned_env["CPPPATH"] << "three"
|
|
233
320
|
### Construction Variable Naming
|
234
321
|
|
235
322
|
* uppercase strings - the default construction variables that Rscons uses
|
236
|
-
* lowercase
|
237
|
-
* lowercase strings - reserved as user-defined construction variables
|
323
|
+
* symbols, lowercase strings - reserved as user-defined construction variables
|
238
324
|
|
239
325
|
### API documentation
|
240
326
|
|
@@ -243,6 +329,22 @@ http://rubydoc.info/github/holtrop/rscons/frames.
|
|
243
329
|
|
244
330
|
## Release Notes
|
245
331
|
|
332
|
+
### v1.4.0
|
333
|
+
|
334
|
+
- add CFile builder
|
335
|
+
- add Disassemble builder
|
336
|
+
- add Preprocess builder
|
337
|
+
- pass the Environment object to build hooks in the :env key of the build_op parameter
|
338
|
+
- expand target/source paths beginning with "^/" to be relative to the Environment's build root
|
339
|
+
- many performance improvements, including:
|
340
|
+
- use JSON instead of YAML for the cache to improve loading speed (Issue #7)
|
341
|
+
- store a hash of the build command instead of the full command contents in the cache
|
342
|
+
- implement copy-on-write semantics for construction variables when cloning Environments
|
343
|
+
- only load the cache once instead of on each Environment#process
|
344
|
+
- only write the cache when something has changed
|
345
|
+
- fix Cache#mkdir_p to handle relative paths (Issue #5)
|
346
|
+
- flush the cache to disk if a builder raises an exception (Issue #4)
|
347
|
+
|
246
348
|
### v1.3.0
|
247
349
|
|
248
350
|
- change Environment#execute() options parameter to accept the following options keys:
|
data/lib/rscons.rb
CHANGED
@@ -5,15 +5,21 @@ require_relative "rscons/varset"
|
|
5
5
|
require_relative "rscons/version"
|
6
6
|
|
7
7
|
# default builders
|
8
|
+
require_relative "rscons/builders/cfile"
|
9
|
+
require_relative "rscons/builders/disassemble"
|
8
10
|
require_relative "rscons/builders/library"
|
9
11
|
require_relative "rscons/builders/object"
|
12
|
+
require_relative "rscons/builders/preprocess"
|
10
13
|
require_relative "rscons/builders/program"
|
11
14
|
|
12
15
|
# Namespace module for rscons classes
|
13
16
|
module Rscons
|
14
17
|
DEFAULT_BUILDERS = [
|
18
|
+
:CFile,
|
19
|
+
:Disassemble,
|
15
20
|
:Library,
|
16
21
|
:Object,
|
22
|
+
:Preprocess,
|
17
23
|
:Program,
|
18
24
|
]
|
19
25
|
|
@@ -21,7 +27,7 @@ module Rscons
|
|
21
27
|
|
22
28
|
# Remove all generated files
|
23
29
|
def self.clean
|
24
|
-
cache = Cache.
|
30
|
+
cache = Cache.instance
|
25
31
|
# remove all built files
|
26
32
|
cache.targets.each do |target|
|
27
33
|
FileUtils.rm_f(target)
|
@@ -33,7 +39,7 @@ module Rscons
|
|
33
39
|
Dir.rmdir(directory) rescue nil
|
34
40
|
end
|
35
41
|
end
|
36
|
-
|
42
|
+
cache.clear
|
37
43
|
end
|
38
44
|
|
39
45
|
# Return whether the given path is an absolute filesystem path or not
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Rscons
|
2
|
+
module Builders
|
3
|
+
# Build a C or C++ source file given a lex (.l, .ll) or yacc (.y, .yy)
|
4
|
+
# input file.
|
5
|
+
#
|
6
|
+
# Examples::
|
7
|
+
# env.CFile("parser.tab.cc", "parser.yy")
|
8
|
+
# env.CFile("lex.yy.cc", "parser.ll")
|
9
|
+
class CFile < Builder
|
10
|
+
def default_variables(env)
|
11
|
+
{
|
12
|
+
"YACC" => "bison",
|
13
|
+
"YACC_FLAGS" => ["-d"],
|
14
|
+
"YACC_CMD" => ["${YACC}", "${YACC_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"],
|
15
|
+
"LEX" => "flex",
|
16
|
+
"LEX_FLAGS" => [],
|
17
|
+
"LEX_CMD" => ["${LEX}", "${LEX_FLAGS}", "-o", "${_TARGET}", "${_SOURCES}"],
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def run(target, sources, cache, env, vars)
|
22
|
+
vars = vars.merge({
|
23
|
+
"_TARGET" => target,
|
24
|
+
"_SOURCES" => sources,
|
25
|
+
})
|
26
|
+
cmd =
|
27
|
+
case
|
28
|
+
when sources.first.end_with?(".l", ".ll")
|
29
|
+
"LEX"
|
30
|
+
when sources.first.end_with?(".y", ".yy")
|
31
|
+
"YACC"
|
32
|
+
else
|
33
|
+
raise "Unknown source file #{sources.first.inspect} for CFile builder"
|
34
|
+
end
|
35
|
+
command = env.build_command(env["#{cmd}_CMD"], vars)
|
36
|
+
standard_build("#{cmd} #{target}", target, command, sources, env, cache)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rscons
|
2
|
+
module Builders
|
3
|
+
# The Disassemble builder produces a disassembly listing of a source file.
|
4
|
+
class Disassemble < Builder
|
5
|
+
def default_variables(env)
|
6
|
+
{
|
7
|
+
"OBJDUMP" => "objdump",
|
8
|
+
"DISASM_CMD" => ["${OBJDUMP}", "${DISASM_FLAGS}", "${_SOURCES}"],
|
9
|
+
"DISASM_FLAGS" => ["--disassemble", "--source"],
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def run(target, sources, cache, env, vars)
|
14
|
+
vars = vars.merge("_SOURCES" => sources)
|
15
|
+
command = env.build_command(env["DISASM_CMD"], vars)
|
16
|
+
unless cache.up_to_date?(target, command, sources, env)
|
17
|
+
cache.mkdir_p(File.dirname(target))
|
18
|
+
return false unless env.execute("Disassemble #{target}", command, options: {out: target})
|
19
|
+
cache.register_build(target, command, sources, env)
|
20
|
+
end
|
21
|
+
target
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rscons
|
2
|
+
module Builders
|
3
|
+
# The Preprocess builder invokes the C preprocessor
|
4
|
+
class Preprocess < Builder
|
5
|
+
def default_variables(env)
|
6
|
+
{
|
7
|
+
"CPP_CMD" => ["${_PREPROCESS_CC}", "-E", "-o", "${_TARGET}", "-I${CPPPATH}", "${CPPFLAGS}", "${CFLAGS}", "${_SOURCES}"],
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
def run(target, sources, cache, env, vars)
|
12
|
+
pp_cc = if sources.find {|s| s.end_with?(*env["CXXSUFFIX"])}
|
13
|
+
env["CXX"]
|
14
|
+
else
|
15
|
+
env["CC"]
|
16
|
+
end
|
17
|
+
vars = vars.merge("_PREPROCESS_CC" => pp_cc,
|
18
|
+
"_TARGET" => target,
|
19
|
+
"_SOURCES" => sources)
|
20
|
+
command = env.build_command(env["CPP_CMD"], vars)
|
21
|
+
standard_build("Preprocess #{target}", target, command, sources, env, cache)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/rscons/cache.rb
CHANGED
@@ -1,88 +1,87 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "digest/md5"
|
2
|
+
require "fileutils"
|
3
|
+
require "json"
|
4
|
+
require "set"
|
5
|
+
require "singleton"
|
6
|
+
require "rscons/version"
|
6
7
|
|
7
8
|
module Rscons
|
8
9
|
# The Cache class keeps track of file checksums, build target commands and
|
9
|
-
# dependencies in a
|
10
|
+
# dependencies in a JSON file which persists from one invocation to the next.
|
10
11
|
# Example cache:
|
11
12
|
# {
|
12
|
-
# version
|
13
|
-
# targets
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
13
|
+
# "version" => "1.2.3",
|
14
|
+
# "targets" => {
|
15
|
+
# "program" => {
|
16
|
+
# "checksum" => "A1B2C3D4",
|
17
|
+
# "command" => "13543518FE",
|
18
|
+
# "deps" => [
|
18
19
|
# {
|
19
|
-
#
|
20
|
-
#
|
20
|
+
# "fname" => "program.o",
|
21
|
+
# "checksum" => "87654321",
|
21
22
|
# },
|
22
23
|
# ],
|
23
|
-
#
|
24
|
+
# "user_deps" => [
|
24
25
|
# {
|
25
|
-
#
|
26
|
-
#
|
26
|
+
# "fname" => "lscript.ld",
|
27
|
+
# "checksum" => "77551133",
|
27
28
|
# },
|
28
29
|
# ],
|
29
30
|
# },
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
31
|
+
# "program.o" => {
|
32
|
+
# "checksum" => "87654321",
|
33
|
+
# "command" => "98765ABCD",
|
34
|
+
# "deps" => [
|
34
35
|
# {
|
35
|
-
#
|
36
|
-
#
|
36
|
+
# "fname" => "program.c",
|
37
|
+
# "checksum" => "456789ABC",
|
37
38
|
# },
|
38
39
|
# {
|
39
|
-
#
|
40
|
-
#
|
40
|
+
# "fname" => "program.h",
|
41
|
+
# "checksum" => "7979764643",
|
41
42
|
# },
|
42
43
|
# ],
|
43
|
-
#
|
44
|
+
# "user_deps" => [],
|
44
45
|
# }
|
45
46
|
# },
|
46
|
-
# directories
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
47
|
+
# "directories" => {
|
48
|
+
# "build" => true,
|
49
|
+
# "build/one" => true,
|
50
|
+
# "build/two" => true,
|
50
51
|
# },
|
51
52
|
# }
|
52
53
|
class Cache
|
53
|
-
|
54
|
+
include Singleton
|
54
55
|
|
55
56
|
# Name of the file to store cache information in
|
56
|
-
CACHE_FILE =
|
57
|
+
CACHE_FILE = ".rsconscache"
|
57
58
|
|
58
|
-
|
59
|
+
# Create a Cache object and load in the previous contents from the cache
|
60
|
+
# file.
|
61
|
+
def initialize
|
62
|
+
initialize!
|
63
|
+
end
|
59
64
|
|
60
|
-
# Remove the cache file
|
61
|
-
def
|
65
|
+
# Remove the cache file.
|
66
|
+
def clear
|
62
67
|
FileUtils.rm_f(CACHE_FILE)
|
68
|
+
initialize!
|
63
69
|
end
|
64
70
|
|
65
|
-
|
66
|
-
|
67
|
-
# Create a Cache object and load in the previous contents from the cache
|
68
|
-
# file.
|
69
|
-
def initialize
|
70
|
-
@cache = YAML.load(File.read(CACHE_FILE)) rescue {}
|
71
|
-
unless @cache.is_a?(Hash)
|
72
|
-
$stderr.puts "Warning: #{CACHE_FILE} was corrupt. Contents:\n#{@cache.inspect}"
|
73
|
-
@cache = {}
|
74
|
-
end
|
75
|
-
@cache[:targets] ||= {}
|
76
|
-
@cache[:directories] ||= {}
|
71
|
+
# Clear the cached file checksums.
|
72
|
+
def clear_checksum_cache!
|
77
73
|
@lookup_checksums = {}
|
78
74
|
end
|
79
75
|
|
80
76
|
# Write the cache to disk to be loaded next time.
|
81
77
|
def write
|
82
|
-
@cache[
|
83
|
-
|
84
|
-
|
78
|
+
if @dirty || (@cache["version"] != VERSION)
|
79
|
+
@cache["version"] = VERSION
|
80
|
+
File.open(CACHE_FILE, "w") do |fh|
|
81
|
+
fh.puts(JSON.dump(@cache))
|
82
|
+
end
|
85
83
|
end
|
84
|
+
@dirty = false
|
86
85
|
end
|
87
86
|
|
88
87
|
# Check if target(s) are up to date
|
@@ -90,11 +89,12 @@ module Rscons
|
|
90
89
|
# @param command [String, Array] The command used to build the target.
|
91
90
|
# @param deps [Array] List of the target's dependency files.
|
92
91
|
# @param env [Environment] The Rscons::Environment.
|
93
|
-
# @param options [Hash] Optional options.
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
# @return
|
92
|
+
# @param options [Hash] Optional options.
|
93
|
+
# @option options [Boolean] :strict_deps
|
94
|
+
# Only consider a target up to date if its list of dependencies is
|
95
|
+
# exactly equal (including order) to the cached list of dependencies
|
96
|
+
# @return [Boolean]
|
97
|
+
# True value if the targets are all up to date, meaning that,
|
98
98
|
# for each target:
|
99
99
|
# - the target exists on disk
|
100
100
|
# - the cache has information for the target
|
@@ -111,16 +111,16 @@ module Rscons
|
|
111
111
|
return false unless File.exists?(target)
|
112
112
|
|
113
113
|
# target must be registered in the cache
|
114
|
-
return false unless @cache[
|
114
|
+
return false unless @cache["targets"].has_key?(target)
|
115
115
|
|
116
116
|
# target must have the same checksum as when it was built last
|
117
|
-
return false unless @cache[
|
117
|
+
return false unless @cache["targets"][target]["checksum"] == lookup_checksum(target)
|
118
118
|
|
119
119
|
# command used to build target must be identical
|
120
|
-
return false unless @cache[
|
120
|
+
return false unless @cache["targets"][target]["command"] == Digest::MD5.hexdigest(command.inspect)
|
121
121
|
|
122
|
-
cached_deps = @cache[
|
123
|
-
cached_deps_fnames = cached_deps.map { |dc| dc[
|
122
|
+
cached_deps = @cache["targets"][target]["deps"] || []
|
123
|
+
cached_deps_fnames = cached_deps.map { |dc| dc["fname"] }
|
124
124
|
if options[:strict_deps]
|
125
125
|
# depedencies passed in must exactly equal those in the cache
|
126
126
|
return false unless deps == cached_deps_fnames
|
@@ -131,13 +131,13 @@ module Rscons
|
|
131
131
|
|
132
132
|
# set of user dependencies must match
|
133
133
|
user_deps = env.get_user_deps(target) || []
|
134
|
-
cached_user_deps = @cache[
|
135
|
-
cached_user_deps_fnames = cached_user_deps.map { |dc| dc[
|
134
|
+
cached_user_deps = @cache["targets"][target]["user_deps"] || []
|
135
|
+
cached_user_deps_fnames = cached_user_deps.map { |dc| dc["fname"] }
|
136
136
|
return false unless user_deps == cached_user_deps_fnames
|
137
137
|
|
138
138
|
# all cached dependencies must have their checksums match
|
139
139
|
(cached_deps + cached_user_deps).each do |dep_cache|
|
140
|
-
return false unless dep_cache[
|
140
|
+
return false unless dep_cache["checksum"] == lookup_checksum(dep_cache["fname"])
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
@@ -148,54 +148,70 @@ module Rscons
|
|
148
148
|
# @param targets [String, Array] The name of the target(s) built.
|
149
149
|
# @param command [String, Array] The command used to build the target.
|
150
150
|
# @param deps [Array] List of dependencies for the target.
|
151
|
-
# @param env [Environment] The Rscons::Environment.
|
151
|
+
# @param env [Environment] The {Rscons::Environment}.
|
152
152
|
def register_build(targets, command, deps, env)
|
153
153
|
Array(targets).each do |target|
|
154
|
-
@cache[
|
155
|
-
command
|
156
|
-
checksum
|
157
|
-
deps
|
154
|
+
@cache["targets"][target] = {
|
155
|
+
"command" => Digest::MD5.hexdigest(command.inspect),
|
156
|
+
"checksum" => calculate_checksum(target),
|
157
|
+
"deps" => deps.map do |dep|
|
158
158
|
{
|
159
|
-
fname
|
160
|
-
checksum
|
159
|
+
"fname" => dep,
|
160
|
+
"checksum" => lookup_checksum(dep),
|
161
161
|
}
|
162
162
|
end,
|
163
|
-
user_deps
|
163
|
+
"user_deps" => (env.get_user_deps(target) || []).map do |dep|
|
164
164
|
{
|
165
|
-
fname
|
166
|
-
checksum
|
165
|
+
"fname" => dep,
|
166
|
+
"checksum" => lookup_checksum(dep),
|
167
167
|
}
|
168
168
|
end,
|
169
169
|
}
|
170
|
+
@dirty = true
|
170
171
|
end
|
171
172
|
end
|
172
173
|
|
173
174
|
# Return a list of targets that have been built
|
174
175
|
def targets
|
175
|
-
@cache[
|
176
|
+
@cache["targets"].keys
|
176
177
|
end
|
177
178
|
|
178
179
|
# Make any needed directories and record the ones that are created for
|
179
180
|
# removal upon a "clean" operation.
|
180
181
|
def mkdir_p(path)
|
181
182
|
parts = path.split(/[\\\/]/)
|
182
|
-
|
183
|
-
|
183
|
+
parts.each_index do |i|
|
184
|
+
next if parts[i] == ""
|
185
|
+
subpath = File.join(*parts[0, i + 1])
|
184
186
|
unless File.exists?(subpath)
|
185
187
|
FileUtils.mkdir(subpath)
|
186
|
-
@cache[
|
188
|
+
@cache["directories"][subpath] = true
|
189
|
+
@dirty = true
|
187
190
|
end
|
188
191
|
end
|
189
192
|
end
|
190
193
|
|
191
194
|
# Return a list of directories which were created as a part of the build
|
192
195
|
def directories
|
193
|
-
@cache[
|
196
|
+
@cache["directories"].keys
|
194
197
|
end
|
195
198
|
|
196
|
-
# Private Instance Methods
|
197
199
|
private
|
198
200
|
|
201
|
+
# Create a Cache object and load in the previous contents from the cache
|
202
|
+
# file.
|
203
|
+
def initialize!
|
204
|
+
@cache = JSON.load(File.read(CACHE_FILE)) rescue {}
|
205
|
+
unless @cache.is_a?(Hash)
|
206
|
+
$stderr.puts "Warning: #{CACHE_FILE} was corrupt. Contents:\n#{@cache.inspect}"
|
207
|
+
@cache = {}
|
208
|
+
end
|
209
|
+
@cache["targets"] ||= {}
|
210
|
+
@cache["directories"] ||= {}
|
211
|
+
@lookup_checksums = {}
|
212
|
+
@dirty = false
|
213
|
+
end
|
214
|
+
|
199
215
|
# Return a file's checksum, or the previously calculated checksum for
|
200
216
|
# the same file
|
201
217
|
# @param file [String] The file name.
|
@@ -206,7 +222,7 @@ module Rscons
|
|
206
222
|
# Calculate and return a file's checksum
|
207
223
|
# @param file [String] The file name.
|
208
224
|
def calculate_checksum(file)
|
209
|
-
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode:
|
225
|
+
@lookup_checksums[file] = Digest::MD5.hexdigest(File.read(file, mode: "rb")) rescue ""
|
210
226
|
end
|
211
227
|
end
|
212
228
|
end
|