forked from rubinius/rubinius
/
kernel.rake
253 lines (203 loc) · 6.81 KB
/
kernel.rake
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
# All the tasks to manage building the Rubinius kernel--which is essentially
# the Ruby core library plus Rubinius-specific files. The kernel bootstraps
# a Ruby environment to the point that user code can be loaded and executed.
#
# The basic rule is that any generated file should be specified as a file
# task, not hidden inside some arbitrary task. Generated files are created by
# rule (e.g. the rule for compiling a .rb file into a .rbc file) or by a block
# attached to the file task for that particular file.
#
# The only tasks should be those names needed by the user to invoke specific
# parts of the build (including the top-level build task for generating the
# entire kernel).
# drake does not allow invoke to be called inside tasks
def kernel_clean
rm_f Dir["**/*.rbc",
"**/.*.rbc",
"kernel/**/signature.rb",
"spec/capi/ext/*.{o,sig,#{$dlext}}",
"runtime/**/load_order.txt",
"runtime/platform.conf"],
:verbose => $verbose
end
require 'kernel/bootstrap/iseq.rb'
# So that the compiler can try and use the config
module Rubinius
Config = { 'eval.cache' => false }
end
# TODO: Build this functionality into the compiler
class KernelCompiler
def self.compile(version, file, output, line, transforms)
compiler = Rubinius::Compiler.new :file, :compiled_file
parser = compiler.parser
parser.root Rubinius::AST::Script
writer = compiler.writer
# Not ready to enable them yet
case version
when "18"
parser.processor Rubinius::Melbourne
writer.version = 18
when "19"
parser.processor Rubinius::Melbourne19
writer.version = 19
when "20"
parser.processor Rubinius::Melbourne20
writer.version = 20
end
if transforms.kind_of? Array
transforms.each { |t| parser.enable_category t }
else
parser.enable_category transforms
end
parser.input file, line
writer = compiler.writer
writer.name = output
compiler.run
end
end
# The rule for compiling all kernel Ruby files
rule ".rbc" do |t|
source = t.prerequisites.first
version = t.name.match(%r[^runtime/(\d+)])[1]
puts "RBC #{version.split(//).join('.')} #{source}"
KernelCompiler.compile version, source, t.name, 1, [:default, :kernel]
end
# Collection of all files in the kernel runtime. Modified by
# various tasks below.
runtime = FileList["runtime/platform.conf"]
# Names of subdirectories of the language directories.
dir_names = %w[
bootstrap
platform
common
delta
]
# Generate file tasks for all kernel and load_order files.
def file_task(re, runtime, signature, version, rb, rbc)
rbc ||= rb.sub(re, "runtime/#{version}") + "c"
file rbc => [rb, signature]
runtime << rbc
end
def kernel_file_task(runtime, signature, version, rb, rbc=nil)
file_task(/^kernel/, runtime, signature, version, rb, rbc)
end
def compiler_file_task(runtime, signature, version, rb, rbc=nil)
file_task(/^lib/, runtime, signature, version, rb, rbc)
end
# Compile all compiler files during build stage
opcodes = "lib/compiler/opcodes.rb"
compiler_files = FileList[
"lib/compiler.rb",
"lib/compiler/**/*.rb",
opcodes,
"lib/compiler/generator_methods.rb",
"lib/melbourne.rb",
"lib/melbourne/**/*.rb"
]
parser_files = FileList[
"lib/ext/melbourne/**/*.{c,h}pp",
"lib/ext/melbourne/grammar18.y",
"lib/ext/melbourne/grammar19.y",
"lib/ext/melbourne/lex.c.tab"
]
# Generate a sha1 of all parser and compiler files to use as
# as signature in the .rbc files.
compiler_signature = "kernel/signature.rb"
file compiler_signature => compiler_files + parser_files do |t|
require 'digest/sha1'
digest = Digest::SHA1.new
(compiler_files + parser_files).each do |name|
File.open name, "r" do |file|
while chunk = file.read(1024)
digest << chunk
end
end
end
# Collapse the digest to a 64bit quantity
hd = digest.hexdigest
signature_hash = hd[0, 16].to_i(16) ^ hd[16,16].to_i(16) ^ hd[32,8].to_i(16)
File.open compiler_signature, "wb" do |file|
file.puts "# This file is generated by rakelib/kernel.rake. The signature"
file.puts "# is used to ensure that only current .rbc files are loaded."
file.puts "#"
file.puts "Rubinius::Signature = #{signature_hash}"
end
end
# Index files for loading a particular version of the kernel.
BUILD_CONFIG[:version_list].each do |ver|
directory(runtime_base_dir = "runtime/#{ver}")
runtime << runtime_base_dir
runtime_index = "#{runtime_base_dir}/index"
runtime << runtime_index
file runtime_index => runtime_base_dir do |t|
File.open t.name, "wb" do |file|
file.puts dir_names
end
end
signature = "runtime/#{ver}/signature"
file signature => compiler_signature do |t|
File.open t.name, "wb" do |file|
puts "GEN #{t.name}"
file.puts Rubinius::Signature
end
end
runtime << signature
# All the kernel files
dir_names.each do |dir|
directory(runtime_dir = "runtime/#{ver}/#{dir}")
runtime << runtime_dir
load_order = "runtime/#{ver}/#{dir}/load_order.txt"
runtime << load_order
kernel_load_order = "kernel/#{dir}/load_order#{ver}.txt"
file load_order => kernel_load_order do |t|
cp t.prerequisites.first, t.name, :verbose => $verbose
end
kernel_dir = "kernel/#{dir}/"
runtime_dir = "runtime/#{ver}/#{dir}/"
IO.foreach kernel_load_order do |name|
rbc = runtime_dir + name.chomp!
rb = kernel_dir + name.chop
kernel_file_task runtime, compiler_signature, ver, rb, rbc
end
end
[ compiler_signature,
"kernel/alpha.rb",
"kernel/loader.rb"
].each do |name|
kernel_file_task runtime, compiler_signature, ver, name
end
compiler_files.map { |f| File.dirname f }.uniq.each do |dir|
directory dir
end
compiler_files.each do |name|
compiler_file_task runtime, compiler_signature, ver, name
end
end
namespace :compiler do
signature_path = File.expand_path("../../kernel/signature", __FILE__)
path = File.expand_path("../../lib", __FILE__)
Rubinius::COMPILER_PATH = path
Rubinius::PARSER_PATH = "#{path}/melbourne"
Rubinius::PARSER_EXT_PATH = "#{path}/ext/melbourne/build/melbourne20"
melbourne = "lib/ext/melbourne/build/melbourne.#{$dlext}"
file melbourne => "extensions:melbourne_build"
task :load => [compiler_signature, melbourne] + compiler_files do
if BUILD_CONFIG[:which_ruby] == :ruby
require "#{Rubinius::COMPILER_PATH}/mri_bridge"
elsif BUILD_CONFIG[:which_ruby] == :rbx && RUBY_VERSION < "1.9"
require "#{Rubinius::COMPILER_PATH}/rbx_bridge"
end
require "#{Rubinius::COMPILER_PATH}/compiler"
require signature_path
end
end
desc "Build all kernel files (alias for kernel:build)"
task :kernel => 'kernel:build'
namespace :kernel do
desc "Build all kernel files"
task :build => ['compiler:load'] + runtime
desc "Delete all .rbc files"
task :clean do
kernel_clean
end
end