rscons 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|