rub 0.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 +7 -0
- data/lib/rub/c.rb +276 -0
- data/lib/rub/d.rb +252 -0
- data/lib/rub/dirs.rb +30 -0
- data/lib/rub/help.rb +178 -0
- data/lib/rub/init.rb +91 -0
- data/lib/rub/l.rb +40 -0
- data/lib/rub/l/c.rb +476 -0
- data/lib/rub/l/c/compiler/clang.rb +94 -0
- data/lib/rub/l/c/compiler/gcc.rb +94 -0
- data/lib/rub/l/ld.rb +254 -0
- data/lib/rub/l/ld/linker/clang.rb +89 -0
- data/lib/rub/l/ld/linker/gcc.rb +89 -0
- data/lib/rub/l/ld/linker/ld.rb +91 -0
- data/lib/rub/l/template.rb +92 -0
- data/lib/rub/l/test.rb +256 -0
- data/lib/rub/l/util.rb +163 -0
- data/lib/rub/r.rb +42 -0
- data/lib/rub/r/command.rb +293 -0
- data/lib/rub/r/env.rb +71 -0
- data/lib/rub/r/i/commandline.rb +192 -0
- data/lib/rub/r/i/runner.rb +78 -0
- data/lib/rub/r/persist.rb +71 -0
- data/lib/rub/r/target.rb +250 -0
- data/lib/rub/r/targetgenerator.rb +80 -0
- data/lib/rub/r/tool.rb +159 -0
- data/lib/rub/r/version-git.rb +62 -0
- data/lib/rub/r/version.rb +145 -0
- metadata +127 -0
data/lib/rub/r/env.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
require 'pathname'
|
26
|
+
|
27
|
+
# Environment Information
|
28
|
+
module R::Env
|
29
|
+
# @!attribute [r] self.cmd_dir
|
30
|
+
# @return [Pathname] The directory from which rub was executed.
|
31
|
+
cattr_accessor :cmd_dir
|
32
|
+
|
33
|
+
# @!attribute [r] self.global_cache
|
34
|
+
# @return [Pathname] The global cache directory.
|
35
|
+
cattr_reader :global_cache
|
36
|
+
|
37
|
+
@cmd_dir = Pathname.pwd
|
38
|
+
|
39
|
+
# @private
|
40
|
+
def self.find_src_dir
|
41
|
+
d = @cmd_dir
|
42
|
+
while not (d+'root.rub').exist?
|
43
|
+
d = d.parent
|
44
|
+
|
45
|
+
if d.root?
|
46
|
+
$stderr.puts('root.rub not found. Make sure you are in the source directory.')
|
47
|
+
Sysexits.exit :usage
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
d.parent + (d.basename.to_s+'/') # Ensure this ends in a '/'
|
52
|
+
end
|
53
|
+
private_class_method :find_src_dir
|
54
|
+
|
55
|
+
# @return [Pathname] The directory from which rub was executed.
|
56
|
+
def self.src_dir
|
57
|
+
@src_dir ||= find_src_dir
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Pathname] The build output directory.
|
61
|
+
def self.out_dir
|
62
|
+
@out_dir ||= src_dir + 'build/'
|
63
|
+
end
|
64
|
+
|
65
|
+
@global_cache = XDG[:cache_home].to_path + 'rub/'
|
66
|
+
|
67
|
+
# @return [Pathname] The project cache directory.
|
68
|
+
def self.project_cache
|
69
|
+
out_dir + "cache/"
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
require 'getoptlong'
|
26
|
+
|
27
|
+
# Command line parsing and handling.
|
28
|
+
module R::I::CommandLine
|
29
|
+
help = lambda do
|
30
|
+
puts <<EOS
|
31
|
+
#{R::Version.info_string}
|
32
|
+
|
33
|
+
Usage: #{$0} [options] [target...]
|
34
|
+
|
35
|
+
Targets:
|
36
|
+
Specify the targets to build. If none are specified ':all' is assumed.
|
37
|
+
|
38
|
+
Options:
|
39
|
+
-o --out <dir>
|
40
|
+
Sets the Rub build directory. This defaults to 'build/'. This is
|
41
|
+
merely a scratch location and none of the files in this directory should
|
42
|
+
be used outside of Rub. You may want to put this on fast storage (maybe
|
43
|
+
in RAM) to speed up complex builds.
|
44
|
+
-D, --define <key>[=<value>]
|
45
|
+
Define a configuration option. The key is everything up to the first
|
46
|
+
'=' and the value is everything after. If the character before the '=' is '+'
|
47
|
+
or '^' it is treated as a '-A' or '-P' respectivly. If there is no '=' it
|
48
|
+
is treated as a flag and it is set. Latter '-D' options overwrite earlier
|
49
|
+
ones.
|
50
|
+
-D, --define <key>+=<value>
|
51
|
+
-A, --append <key>[+=<value>]
|
52
|
+
-A, --append <key>[=<value>]
|
53
|
+
Append a configuration option to a list. If the current value is not
|
54
|
+
a list it is overwritten. The key and value specification is the same
|
55
|
+
as for '-D' except that a '+' is not nessary and is assumed.
|
56
|
+
-D, --define <key>^=<value>
|
57
|
+
-P, --prepend <key>[^=<value>]
|
58
|
+
-P, --prepend <key>[=<value>]
|
59
|
+
Prepend a configuration option to a list. If the current value is not
|
60
|
+
a list it is overwritten. The key and value specification is the same
|
61
|
+
as for '-D' except that a '^' is not nessary and is assumed.
|
62
|
+
-S, --script <script>
|
63
|
+
Run a script. This script should only set define options as all of Rub
|
64
|
+
may not be initilized yet. The script is executed in order with other
|
65
|
+
'--script', '-D' and '-P' options.
|
66
|
+
--explicit-scripts
|
67
|
+
Only run scripts specified on the command line. This prevents system
|
68
|
+
and user defaults from being used. Use with caution because it could
|
69
|
+
cause a build to fail if the provided definitions don't contain enough
|
70
|
+
information.
|
71
|
+
--no-cache
|
72
|
+
Disable caching. All state from previous runs will be discarded. Caching
|
73
|
+
will still be performed inside a single run.
|
74
|
+
--doc
|
75
|
+
Generate documentation of installed libraries. All additional parameters will
|
76
|
+
be passed to yardoc.
|
77
|
+
-V, --version
|
78
|
+
Print the version and exit.
|
79
|
+
--version-number
|
80
|
+
Print just the version number.
|
81
|
+
--version-describe
|
82
|
+
Print a short description of the version you are running.
|
83
|
+
--version-verbose
|
84
|
+
Print lots of information about the code you are running.
|
85
|
+
--version-version-commit
|
86
|
+
Print the version, and if not a release commit, the current commit.
|
87
|
+
-h, --help
|
88
|
+
Print this help text and exit.
|
89
|
+
EOS
|
90
|
+
exit
|
91
|
+
end
|
92
|
+
|
93
|
+
class << self
|
94
|
+
attr_reader :cache
|
95
|
+
end
|
96
|
+
@cache = true
|
97
|
+
|
98
|
+
opts = GetoptLong.new(
|
99
|
+
['--out', '-o', GetoptLong::REQUIRED_ARGUMENT ],
|
100
|
+
['-D', '--define', GetoptLong::REQUIRED_ARGUMENT ],
|
101
|
+
['-A', '--append', GetoptLong::REQUIRED_ARGUMENT ],
|
102
|
+
['-P', '--prepend', GetoptLong::REQUIRED_ARGUMENT ],
|
103
|
+
['-S', '--script', GetoptLong::REQUIRED_ARGUMENT ],
|
104
|
+
['--explicit-scripts', GetoptLong::NO_ARGUMENT ],
|
105
|
+
['--no-cache', GetoptLong::NO_ARGUMENT ],
|
106
|
+
['--doc', GetoptLong::NO_ARGUMENT ],
|
107
|
+
['--help', '-h', GetoptLong::NO_ARGUMENT ],
|
108
|
+
['--version', '-V', '-v', GetoptLong::NO_ARGUMENT ],
|
109
|
+
['--version-number', GetoptLong::NO_ARGUMENT ],
|
110
|
+
['--version-describe', GetoptLong::NO_ARGUMENT ],
|
111
|
+
['--version-verbose', GetoptLong::NO_ARGUMENT ],
|
112
|
+
['--version-version-commit', GetoptLong::NO_ARGUMENT ],
|
113
|
+
)
|
114
|
+
|
115
|
+
scripts = [];
|
116
|
+
sysscripts = XDG[:config].paths.map do |d|
|
117
|
+
[:file, d+'rub/config.rub']
|
118
|
+
end.keep_if { |t, n| n.exist? }
|
119
|
+
|
120
|
+
opts.each do |opt, arg|
|
121
|
+
case opt
|
122
|
+
when '--out'
|
123
|
+
Rub::Env.out_dir = Rub::Env.cmd_dir + arg
|
124
|
+
when '-D'
|
125
|
+
scripts.push [:define, arg]
|
126
|
+
when '-A'
|
127
|
+
scripts.push [:append, arg]
|
128
|
+
when '-P'
|
129
|
+
scripts.push [:prepend, arg]
|
130
|
+
when '-S'
|
131
|
+
scripts.push [:file, Pathname(arg)]
|
132
|
+
when '--explicit-scripts'
|
133
|
+
sysscripts = []
|
134
|
+
when '--no-cache'
|
135
|
+
@cache = false
|
136
|
+
when '--doc'
|
137
|
+
lib = Pathname.new(__FILE__).realpath.parent.parent.parent.parent
|
138
|
+
base = lib.parent
|
139
|
+
|
140
|
+
source = lib+'**/*.rb'
|
141
|
+
readme = [
|
142
|
+
base+'share/doc/'+R::Version.slug+'README.md', # Installed path.
|
143
|
+
base+'README.md' # Dev path.
|
144
|
+
].find{|r| r.exist? }
|
145
|
+
pp readme
|
146
|
+
|
147
|
+
exec(
|
148
|
+
'yardoc',
|
149
|
+
'--default-return', 'void',
|
150
|
+
*ARGV,
|
151
|
+
'-r', readme.to_s,
|
152
|
+
source.to_s
|
153
|
+
)
|
154
|
+
when '--help'
|
155
|
+
help.call
|
156
|
+
when '--version'
|
157
|
+
puts R::Version.info_string
|
158
|
+
exit 0
|
159
|
+
when '--version-number'
|
160
|
+
puts R::Version.number_string
|
161
|
+
exit 0
|
162
|
+
when '--version-describe'
|
163
|
+
puts R::Version.string
|
164
|
+
exit 0
|
165
|
+
when '--version-verbose'
|
166
|
+
puts R::Version.verbose
|
167
|
+
exit 0
|
168
|
+
when '--version-version-commit'
|
169
|
+
puts R::Version.version_commit
|
170
|
+
exit 0
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
sysscripts.concat(scripts).each do | t, a |
|
175
|
+
case t
|
176
|
+
when :file
|
177
|
+
if not a.exist?
|
178
|
+
$stderr.puts "Can't load defines from \"#{a}\" because it doesn't exist!"
|
179
|
+
Sysexits.exit :noinput
|
180
|
+
end
|
181
|
+
|
182
|
+
load a
|
183
|
+
when :define
|
184
|
+
D.define(a)
|
185
|
+
when :append
|
186
|
+
D.append(a)
|
187
|
+
when :prepend
|
188
|
+
D.prepend(a)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
# Functions for running build scripts.
|
26
|
+
module R::I::Runner
|
27
|
+
@@loaded = {}
|
28
|
+
|
29
|
+
# Execute a file.
|
30
|
+
#
|
31
|
+
# Runs a script if it hasn't been run already.
|
32
|
+
#
|
33
|
+
# @param f [Pathname] The file to run.
|
34
|
+
# @return [void]
|
35
|
+
def self.do_file(f)
|
36
|
+
if @@loaded[f]
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
if not f.exist?
|
41
|
+
$stderr.puts "\"#{f}\" is not readable!"
|
42
|
+
Sysexits.exit :noinput
|
43
|
+
end
|
44
|
+
|
45
|
+
@@loaded[f] = true
|
46
|
+
|
47
|
+
Dir.chdir f.dirname do
|
48
|
+
load f.to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module C
|
54
|
+
# Add a directory to the build.
|
55
|
+
#
|
56
|
+
# This will run the "dir.rub" file in that directory synchronously. Any
|
57
|
+
# values that that directory defines will be available when this call
|
58
|
+
# returns.
|
59
|
+
#
|
60
|
+
# This function only runs scripts once, if the script has already run this
|
61
|
+
# function will return success without running the script, and as the script
|
62
|
+
# has already been run the exported values should be available.
|
63
|
+
def self.add_dir(dir)
|
64
|
+
dir = C.path(dir)
|
65
|
+
|
66
|
+
if not dir.directory?
|
67
|
+
raise "\"#{dir}\" is not a directory!"
|
68
|
+
end
|
69
|
+
|
70
|
+
dir += 'dir.rub'
|
71
|
+
if not dir.exist?
|
72
|
+
raise "\"#{dir}\" does not exist!"
|
73
|
+
end
|
74
|
+
dir = dir.realpath
|
75
|
+
|
76
|
+
R::I::Runner.do_file(dir)
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
module R
|
26
|
+
# @!attribute [r] self.ppersistant
|
27
|
+
# @return [Hash] The project cache.
|
28
|
+
cattr_reader :ppersistant
|
29
|
+
|
30
|
+
# @!attribute [r] self.spersistant
|
31
|
+
# @return [Hash] The system cache.
|
32
|
+
cattr_reader :spersistant
|
33
|
+
|
34
|
+
ppersistfile = R::Env.project_cache + "persistant.marshal"
|
35
|
+
if ppersistfile.exist? && R::I::CommandLine.cache
|
36
|
+
@ppersistant = Marshal.load(File.new(ppersistfile, 'r').read)
|
37
|
+
else
|
38
|
+
@ppersistant = {}
|
39
|
+
end
|
40
|
+
|
41
|
+
END {
|
42
|
+
File.new(ppersistfile, 'w').write(Marshal.dump(@ppersistant))
|
43
|
+
}
|
44
|
+
|
45
|
+
spersistfile = R::Env.global_cache + "persistant.marshal"
|
46
|
+
if spersistfile.exist? && R::I::CommandLine.cache
|
47
|
+
@spersistant = Marshal.load(spersistfile.read)
|
48
|
+
else
|
49
|
+
@spersistant = {}
|
50
|
+
end
|
51
|
+
|
52
|
+
END {
|
53
|
+
spersistfile.open('w').write(Marshal.dump(@spersistant))
|
54
|
+
}
|
55
|
+
|
56
|
+
# Clear the system cache.
|
57
|
+
def self.clear_system_cache
|
58
|
+
@spersistant.clear
|
59
|
+
end
|
60
|
+
# Clear the project cache.
|
61
|
+
def self.clear_project_cache
|
62
|
+
@ppersistant.clear
|
63
|
+
end
|
64
|
+
# Clear all caches.
|
65
|
+
def self.clear_cache
|
66
|
+
clear_system_cache
|
67
|
+
clear_project_cache
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
data/lib/rub/r/target.rb
ADDED
@@ -0,0 +1,250 @@
|
|
1
|
+
# Copyright 2013 Kevin Cox
|
2
|
+
|
3
|
+
################################################################################
|
4
|
+
# #
|
5
|
+
# This software is provided 'as-is', without any express or implied #
|
6
|
+
# warranty. In no event will the authors be held liable for any damages #
|
7
|
+
# arising from the use of this software. #
|
8
|
+
# #
|
9
|
+
# Permission is granted to anyone to use this software for any purpose, #
|
10
|
+
# including commercial applications, and to alter it and redistribute it #
|
11
|
+
# freely, subject to the following restrictions: #
|
12
|
+
# #
|
13
|
+
# 1. The origin of this software must not be misrepresented; you must not #
|
14
|
+
# claim that you wrote the original software. If you use this software in #
|
15
|
+
# a product, an acknowledgment in the product documentation would be #
|
16
|
+
# appreciated but is not required. #
|
17
|
+
# #
|
18
|
+
# 2. Altered source versions must be plainly marked as such, and must not be #
|
19
|
+
# misrepresented as being the original software. #
|
20
|
+
# #
|
21
|
+
# 3. This notice may not be removed or altered from any source distribution. #
|
22
|
+
# #
|
23
|
+
################################################################################
|
24
|
+
|
25
|
+
module R
|
26
|
+
# All targets.
|
27
|
+
#
|
28
|
+
# This should only be used for debugging. Use {find_target}, {get_target}
|
29
|
+
# and {set_target} instead.
|
30
|
+
#
|
31
|
+
# @return [Hash{Pathname,Symbol=>Target}]
|
32
|
+
cattr_reader :targets
|
33
|
+
|
34
|
+
@targets = {}
|
35
|
+
@sources = {}
|
36
|
+
|
37
|
+
# Find a target.
|
38
|
+
#
|
39
|
+
# Returns a target for +path+ or nil.
|
40
|
+
#
|
41
|
+
# @param path [Pathname,String] The path of the target.
|
42
|
+
# @return [Target,nil] The target.
|
43
|
+
def self.find_target(path)
|
44
|
+
path = C.path(path)
|
45
|
+
@targets[path] || @sources[path]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Get a target.
|
49
|
+
#
|
50
|
+
# This function get's an existing target if it exists or returns a new
|
51
|
+
# source target if there is no existing target to build it.
|
52
|
+
#
|
53
|
+
# @param path [Pathname,String] The path of the target.
|
54
|
+
# @return [Target,TargetSource]
|
55
|
+
def self.get_target(path)
|
56
|
+
path = C.path(path)
|
57
|
+
|
58
|
+
find_target(path) or @sources[path] ||= TargetSource.new(path)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set a target to a path.
|
62
|
+
#
|
63
|
+
# This function registers +target+ as a way to build +path+.
|
64
|
+
#
|
65
|
+
# @param path [Pathname,String] The path that is build by the target.
|
66
|
+
# @param target [Target] The target that builds +path+.
|
67
|
+
# @return [void]
|
68
|
+
#
|
69
|
+
# @see Target#register.
|
70
|
+
def self.set_target(path, target)
|
71
|
+
if find_target(path)
|
72
|
+
$stderr.puts "Warning: #{path} can be built two ways."
|
73
|
+
end
|
74
|
+
@targets[C.path(path)] = target
|
75
|
+
end
|
76
|
+
|
77
|
+
# The base target class.
|
78
|
+
#
|
79
|
+
# It has simple building logic and a way to register targets. All
|
80
|
+
# targets should inherit from this class.
|
81
|
+
class Target
|
82
|
+
# Inputs
|
83
|
+
#
|
84
|
+
# @return [Set<Pathname>] The inputs this target depends on.
|
85
|
+
def input
|
86
|
+
Set.new
|
87
|
+
end
|
88
|
+
|
89
|
+
# Outputs
|
90
|
+
#
|
91
|
+
# @return [Set<Pathname>] The outputs this target creates.
|
92
|
+
def output
|
93
|
+
Set.new
|
94
|
+
end
|
95
|
+
|
96
|
+
# Description.
|
97
|
+
#
|
98
|
+
# Shown for :help.
|
99
|
+
# @return [String,nil]
|
100
|
+
def description
|
101
|
+
nil
|
102
|
+
end
|
103
|
+
|
104
|
+
# Register this target.
|
105
|
+
#
|
106
|
+
# Registers this target as building it's {#output}s.
|
107
|
+
#
|
108
|
+
# @return [void]
|
109
|
+
def register
|
110
|
+
output.each do |d|
|
111
|
+
R.set_target(d, self)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Is this target up to date?
|
116
|
+
def clean?
|
117
|
+
false
|
118
|
+
end
|
119
|
+
|
120
|
+
# Return a hash of this target.
|
121
|
+
#
|
122
|
+
# This hash should represent a unique build environment and change if
|
123
|
+
# anything in that environment does. This includes, but is not limited
|
124
|
+
# to:
|
125
|
+
# - Input files.
|
126
|
+
# - Output files.
|
127
|
+
# - Build commands.
|
128
|
+
#
|
129
|
+
# @return [String] the hash.
|
130
|
+
def hash_input
|
131
|
+
Digest::SHA1.digest(
|
132
|
+
(
|
133
|
+
input.map{|i| R::get_target(i).hash_output(i) }
|
134
|
+
).join
|
135
|
+
)
|
136
|
+
end
|
137
|
+
|
138
|
+
@@symbolcounter = rand(2**160) # Shouldn't repeat very often.
|
139
|
+
def hash_output(t)
|
140
|
+
if t.is_a? Symbol
|
141
|
+
@@symbolcounter++
|
142
|
+
"symbol-#{@@symbolcounter.to_s(16)}" # Never clean.
|
143
|
+
else
|
144
|
+
Digest::SHA1.file(t).to_s
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def hash_outputs(t = output)
|
149
|
+
Digest::SHA1.digest(t.map{|o| hash_output(o)}.join)
|
150
|
+
end
|
151
|
+
|
152
|
+
def hash_self
|
153
|
+
Digest::SHA1.digest(hash_input+hash_outputs)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Build the inputs.
|
157
|
+
def build_dependancies
|
158
|
+
input.each{|i| R::get_target(i).build }
|
159
|
+
end
|
160
|
+
private :build_dependancies
|
161
|
+
|
162
|
+
# Build this target.
|
163
|
+
#
|
164
|
+
# This should be overridden if {#build} itself is not overridden.
|
165
|
+
|
166
|
+
# @return [void]
|
167
|
+
def build_self
|
168
|
+
raise "#build_self not implemented in #{self.class}."
|
169
|
+
end
|
170
|
+
private :build_self
|
171
|
+
|
172
|
+
# Build.
|
173
|
+
#
|
174
|
+
# This is a simple build method. It calls {#build_dependancies} then
|
175
|
+
# {#build_self}. Either or both of these methods can be overwritten to
|
176
|
+
# customize the build or this function can be overwritten to have more
|
177
|
+
# control.
|
178
|
+
#
|
179
|
+
# @return [void]
|
180
|
+
def build
|
181
|
+
build_dependancies
|
182
|
+
build_self
|
183
|
+
|
184
|
+
nil
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# Target with additional functionality.
|
189
|
+
class TargetSmart < Target
|
190
|
+
attr_reader :input, :output
|
191
|
+
|
192
|
+
def initialize
|
193
|
+
@input = Set.new
|
194
|
+
@output = Set.new
|
195
|
+
end
|
196
|
+
|
197
|
+
# Mark target as clean.
|
198
|
+
#
|
199
|
+
# @return [void]
|
200
|
+
def clean
|
201
|
+
output.all?{|f| !f.is_a?(Symbol) and f.exist?} or return
|
202
|
+
|
203
|
+
R::ppersistant["Rub.TargetSmart.#{@output.sort.join('\0')}"] = hash_self
|
204
|
+
end
|
205
|
+
|
206
|
+
# Is this target clean?
|
207
|
+
#
|
208
|
+
# @return [true,false] True if this target is up-to-date.
|
209
|
+
def clean?
|
210
|
+
output.each do |f|
|
211
|
+
f.is_a?(Symbol) and return false # Tags are never clean.
|
212
|
+
f.exist? or return false # Output missing, rebuild.
|
213
|
+
end
|
214
|
+
|
215
|
+
R::ppersistant["Rub.TargetSmart.#{@output.sort.join('\0')}"] == hash_self
|
216
|
+
end
|
217
|
+
|
218
|
+
def build
|
219
|
+
build_dependancies
|
220
|
+
|
221
|
+
clean? and return
|
222
|
+
|
223
|
+
build_self
|
224
|
+
|
225
|
+
clean
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# A target for existing sources.
|
230
|
+
class TargetSource < Target
|
231
|
+
attr_reader :output
|
232
|
+
|
233
|
+
def initialize(p)
|
234
|
+
@src = p
|
235
|
+
@output = Set[p]
|
236
|
+
end
|
237
|
+
|
238
|
+
def hash_output(f)
|
239
|
+
@hashcache ||= Digest::SHA1.file(f).to_s
|
240
|
+
end
|
241
|
+
|
242
|
+
def build
|
243
|
+
if not @src.exist?
|
244
|
+
#p self
|
245
|
+
$stderr.puts "Error: source file #{@src} does not exist!"
|
246
|
+
Sysexits.exit :noinput
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|