Change soft-fail to use the config, rather than env
[rbx.git] / kernel / core / compile.rb
blob4203a39471ae3024443b9f2e89640e0ce377e943
1 # depends on: module.rb
3 module Rubinius
5   ##
6   # This const controls what the lowest version of compiled methods we can
7   # allow is. This allows us to cut off compability at some point, or just
8   # increment when major changes are made to the compiler.
10   CompiledMethodVersion = 6
12 end
15 # Main entrace point to the Rubinius compiler.  Handles loading and compiling
16 # ruby code.
18 module Compile
20   @compiler = nil
22   DefaultCompiler = "compiler"
24   def self.register_compiler(obj)
25     if $DEBUG
26       $stderr.puts "[Registered #{obj} as system compiler]"
27     end
28     @compiler = obj
29   end
31   def self.find_compiler
32     @compiler = :loading
33     begin
34       loading_rbc_directly do
35         require "#{DefaultCompiler}/init"
36       end
37     rescue Exception => e
38       STDERR.puts "Unable to load default compiler: #{e.message}"
39       puts e.awesome_backtrace.show
40       raise e
41     end
43     if @compiler == :loading
44       raise "Attempted to load DefaultCompiler, but no compiler was registered"
45     end
47     return @compiler
48   end
50   def self.compiler
51     return @compiler if @compiler and @compiler != :loading
52     return find_compiler
53   end
55   def self.version_number
56     # Until the compiler is loaded, load any versions. This
57     # lets us bootstrap the compiler into the system no matter
58     # what version it is. This is important because we don't want
59     # to keep the compiler from loading at all because it might have
60     # older versioned files.
61     return @compiler.version_number if @compiler and @compiler != :loading
62     return 0
63   end
65   def self.compile_file(path, flags=nil)
66     compiler.compile_file(path, flags)
67   end
69   def self.compile_string(string, context=nil, filename="(eval)", line=1)
70     compiler.compile_string(string, context, filename, line)
71   end
73   def self.execute(string)
74     eval(string, TOPLEVEL_BINDING)
75   end
77   # Sets a flag so that the next script to be loaded gets a breakpoint set at
78   # the first instruction
79   def self.debug_script!
80     @debug_script = true
81   end
83   # By calling require in the block passed to this, require will
84   # load rbc if they exist without checking mtime's and such.
85   @load_rbc_directly = false
87   def self.loading_rbc_directly
88     begin
89       @load_rbc_directly = true
90       yield
91     ensure
92       @load_rbc_directly = false
93     end
94   end
96   # Called when we encounter a break keyword that we do not support
97   # TODO - This leaves a moderately lame stack trace entry
98   def self.__unexpected_break__
99     raise LocalJumpError, "unexpected break"
100   end
102   # Internally used by #load and #require. Determines whether to
103   # load the file directly or by prefixing it with the paths in
104   # $LOAD_PATH and then attempts to locate and load the file.
105   def self.unified_load(path, rb, rbc, ext, requiring = nil, options = {:recompile => false})
106     # forces the compiler to be loaded. We need this to get
107     # the proper version_number calculation.
108     #
109     self.compiler unless @compiler
111     # ./ ../ ~/ /
112     if path =~ %r{\A(?:(\.\.?)|(~))?/}
113       if $2    # ~ 
114         rb.slice! '~/' if rb
115         rbc.slice! '~/' if rbc
116         ext.slice! '~/' if ext
117         res = Compile.single_load "#{ENV['HOME']}/", rb, rbc, ext, requiring, options
119       else
120         res = Compile.single_load '', rb, rbc, ext, requiring, options
121       end
123       return res unless res.nil?      # false is valid
125     # Unqualified
126     else
127       $LOAD_PATH.each do |dir|
128         if rbc and dir.suffix? '.rba' and File.file? dir and !options[:recompile]
129           begin
130             _, _, _, _, _, data = Ar.new(dir).extract rbc
131           rescue Ar::Error
132           end
134           cm = if data then
135                  unmarshal_object data, 0
136                else
137                  data = Ar.new(dir).extract rbc
138                  unmarshal_object data, version_number
139                end
141           if cm
142             return false if requiring and $LOADED_FEATURES.include? rb
144             cm.compile
145             cm.hints = { :source => :rba }
146             cm.as_script do |script|
147               script.path = rb
148             end
150             $LOADED_FEATURES << rb if requiring
152             # Add script CM to CompiledMethod.scripts
153             CompiledMethod.scripts[rb] = cm
155             return true
156           end
157           # Fall through
158         end
160         res = Compile.single_load "#{dir}/", rb, rbc, ext, requiring, options
161         return res unless res.nil?      # false is valid
162       end
163     end
165     raise LoadError, "no such file to load -- #{path}"
166   end
168   def self.compile_feature(rb, requiring, &block)
169     $LOADED_FEATURES << rb if requiring
170     begin
171       yield
172     rescue Exception => e
173       $LOADED_FEATURES.delete(rb) if requiring
174       raise e
175     end
176   end
178   # Internally used by #unified_load. This attempts to load the
179   # designated file from a single prefix path.
180   def self.single_load(dir, rb, rbc, ext, requiring, options)
181     # Force compiler loading, required for version calculation
182     self.compiler unless @compiler
184     if rb
185       return false if requiring and $LOADED_FEATURES.include? rb
187       rb_path = "#{dir}#{rb}"
189       if File.file? rb_path
190         rbc_path = "#{dir}#{rbc}"
191         
192         cm = nil
194         # Try to load rbc directly if requested
195         if @load_rbc_directly and File.file?(rbc_path)
196           compile_feature(rb, requiring) do
197             cm = CompiledMethod.load_from_file(rbc_path, version_number)
198             raise LoadError, "Invalid .rbc: #{rbc_path}" unless cm
199           end
201         # Prefer compiled whenever possible
202         elsif !File.file?(rbc_path) or File.mtime(rb_path) > File.mtime(rbc_path) or options[:recompile]
203           if $DEBUG_LOADING
204             if !File.file?(rbc_path)
205               STDERR.puts "[Compiling #{rb_path}: Missing compiled version]"
206             else
207               STDERR.puts "[Compiling #{rb_path}: Newer source file]"
208             end
209           end
211           compile_feature(rb, requiring) do
212             cm = Compile.compile_file(rb_path)
213             raise LoadError, "Unable to compile: #{rb_path}" unless cm
214           end
216           # Store it for the future
217           Marshal.dump_to_file cm, rbc_path, version_number
218         else
219           compile_feature(rb, requiring) do
220             cm = CompiledMethod.load_from_file(rbc_path, version_number)
221             # cm is nil if the file is out of date, version wise.
222             unless cm
223               if $DEBUG_LOADING
224                 STDERR.puts "[Recompling #{rb_path}, old version]"
225               end
227               compile_feature(rb, requiring) do
228                 cm = Compile.compile_file(rb_path)
229                 raise LoadError, "Unable to compile: #{rb_path}" unless cm
230               end
232               Marshal.dump_to_file cm, rbc_path, version_number
233             end
234           end
235         end
237         # Add script CM to CompiledMethod.scripts
238         CompiledMethod.scripts[rb] = cm
240         begin
241           cm.compile
242           cm.hints = { :source => :rb }
243           # Set a breakpoint on the script CompiledMethod if flag is set
244           if @debug_script
245             Debugger.instance.set_breakpoint cm, 0
246             @debug_script = false
247           end
248           cm.as_script do |script|
249             script.path = rb_path
250           end
251         rescue Exception => e
252           $LOADED_FEATURES.delete(rb) if requiring
253           raise e
254         end
256         return true
257       end
258     end
260     if rbc
261       rb = rbc.chomp 'c'
262       return false if requiring and $LOADED_FEATURES.include?(rb)
264       rbc_path = "#{dir}#{rbc}"
266       if File.file? rbc_path and !options[:recompile]
267         compile_feature(rb, requiring) do
268           cm = CompiledMethod.load_from_file(rbc_path, version_number)
269           raise LoadError, "Invalid .rbc: #{rbc_path}" unless cm
270         end
272         begin
273           cm.compile
274           cm.hints = { :source => :rbc }
275           cm.as_script do |script|
276             script.path = rb_path
277           end
278         rescue Exception => e
279           $LOADED_FEATURES.delete(rb) if requiring
280           raise e
281         end
283         return true
284       end
285     end
287     if ext
288       return false if requiring and $LOADED_FEATURES.include? ext
289       
290       ext_path = "#{dir}#{ext}"
291       ext_name = File.basename ext, ".#{Rubinius::LIBSUFFIX}"
293       if File.file? ext_path
294         case Rubinius::VM.load_library(ext_path, ext_name)
295         when true
296           $LOADED_FEATURES << ext if requiring
297           return true
298         when 0 # Absent or invalid
299           return nil
300         when 1 # Valid library, but no entry point
301           raise LoadError, "Invalid extension at '#{ext_path}'. " \
302                            "Did you define Init_#{ext_name}?"
303         end
304       end
305     end
307     nil
308   end
310   def self.load_from_extension(path)
311     path = StringValue(path)
312     # Remap all library extensions behind the scenes, just like MRI
313     path.gsub!(/\.(so|bundle|dll|dylib)$/, ".#{Rubinius::LIBSUFFIX}")
314     if path.suffix? '.rbc'
315       rb, rbc, ext = nil, path, nil
316     elsif path.suffix? '.rb'
317       rb, rbc, ext = path, "#{path}c", nil
318     elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
319       rb, rbc, ext = nil, nil, path
320     else
321       dir, name = File.split(path)
322       name = ".#{name}" unless name[0] == ?.
323       rb, rbc, ext = path, "#{dir}/#{name}.compiled.rbc", nil
324     end
326     Compile.single_load '', rb, rbc, ext, false, {}
327   end
329   def self.unmarshal_object(data, version)
330     Ruby.primitive :unmarshal_object
331   end
333 end       # Compile
335 module Kernel
336   def compile(path, out=nil, flags=nil)
337     out = "#{path}c" unless out
338     cm = Compile.compile_file(path, flags)
339     raise LoadError, "Unable to compile '#{path}'" unless cm
340     Marshal.dump_to_file cm, out, Compile.version_number
341     return out
342   end
343   module_function :compile
345   ##
346   # Loads the given file as executable code and returns true. If
347   # the file cannot be found, cannot be compiled or some other
348   # error occurs, LoadError is raised with an explanation.
349   #
350   # Unlike #require, the file extension if any must be present but
351   # is not restricted to .rb, .rbc or .<platform shared lib ext>.
352   # Any other extensions (or no extension) are assumed to be plain
353   # Ruby files. The only exceptions to this rule are:
354   #
355   # 1.  if given a .rb or no/any-extensioned file and there is a
356   #     compiled version of the same file that is not older than
357   #     the source file (based on File.mtime), the compiled one
358   #     is loaded directly to avoid the compilation overhead.
359   # 2.  if a .rb file is given but it does not exist, the system
360   #     will try to load the corresponding .rbc instead (to allow
361   #     distributing just .rbc files.)
362   #
363   # If the path given starts with ./, ../, ~/ or /, it is treated
364   # as a "qualified" file and will be loaded directly (after path
365   # expansion) instead of matching against $LOAD_PATH. The relative
366   # paths use Dir.pwd.
367   #
368   # If the filename is plain (unqualified) then it is sequentially
369   # prefixed with each path in $LOAD_PATH ($:) to locate the file,
370   # using the first one that exists. If none of the resulting paths
371   # exist, LoadError is raised. Unqualified names may contain path
372   # elements so directories are valid targets and can be used with
373   # $LOAD_PATH.
374   #
375   # A few extra options are supported. If the second parameter is
376   # true, then the module is wrapped inside an anonymous module for
377   # loading to avoid polluting the namespace. This is actually a
378   # shorthand for passing in :wrap => true-ish in the second arg
379   # which may be an option Hash.
380   #
381   # If :recompile in option Hash is true-ish then the file in
382   # question is recompiled each time. If the source file is not
383   # present when recompiling is requested, a LoadError is raised.
384   #
385   # TODO: Support non-UNIX paths.
386   #
387   # TODO: The anonymous module wrapping is not implemented at all.
388   #
389   def load(path, opts = {:wrap => false, :recompile => false})
390     path = StringValue(path)
391     # Remap all library extensions behind the scenes, just like MRI
392     path.gsub!(/\.(so|bundle|dll|dylib)$/, ".#{Rubinius::LIBSUFFIX}")
393     
394     opts = {:wrap => !!opts, :recompile => false} unless Hash === opts
396     if path.suffix? '.rbc'
397       rb, rbc, ext = nil, path, nil
398     elsif path.suffix? '.rb'
399       rb, rbc, ext = path, "#{path}c", nil
400     elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
401       rb, rbc, ext = nil, nil, path
402     else
403       dir, name = File.split(path)
404       name = ".#{name}" unless name[0] == ?.
405       rb, rbc, ext = path, "#{dir}/#{name}.compiled.rbc", nil
406     end
408     Compile.unified_load path, rb, rbc, ext, nil, opts
409   end
410   module_function :load
412   
413   # Attempt to load the given file, returning true if successful.
414   # If the file has already been successfully loaded and exists
415   # in $LOADED_FEATURES, it will not be re-evaluated and false
416   # is returned instead. If the filename cannot be resolved,
417   # a LoadError is raised.
418   #
419   # The file can have one of the following extensions:
420   #
421   # [.rb]                   Plain Ruby source file.
422   # [.rbc]                  Compiled Ruby source file.
423   # [.o, .so, .dylib, .dll] Shared library (platform-specific.)
424   # [<none>]                Filename without extension.
425   #
426   # (.rba files should be loaded using CodeArchive.load_everything.)
427   #
428   # If the file does not have an extension, #require attempts to
429   # match it using .rb, .rbc and .<shared extension> as extensions,
430   # in that order, instead. If foo.rb does not exist but foo.rbc
431   # does, the latter will be loaded even if called with foo.rb.
432   #
433   # If the path given starts with ./, ../, ~/ or /, it is treated
434   # as a "qualified" file and will be loaded directly (after path
435   # expansion) instead of matching against $LOAD_PATH. The relative
436   # paths use Dir.pwd.
437   #
438   # If the filename is plain (unqualified) then it is sequentially
439   # prefixed with each path in $LOAD_PATH ($:) to locate the file,
440   # using the first one that exists. If none of the resulting paths
441   # exist, LoadError is raised. Unqualified names may contain path
442   # elements so directories are valid targets and can be used with
443   # $LOAD_PATH.
444   #
445   # TODO: Support non-UNIX paths.
446   #
447   # TODO: See if we can safely use 1.9 rules with $LOADED_FEATURES,
448   #       i.e. expand paths into it. This should be possible if it
449   #       is completely transparent to the user in all normal cases.
450   #
451   # Each successfully loaded file is added to $LOADED_FEATURES
452   # ($"), using the original unexpanded filename (with the
453   # exception that the file extension is added.)
454   #
455   def require(path)
456     path = StringValue(path)
457     rb, rbc, ext = __split_path__ path
458     Autoload.remove(rb)
459     Compile.unified_load path, rb, rbc, ext, true
460   end
461   module_function :require
463   def __split_path__(path)
464     # Remap all library extensions behind the scenes, just like MRI
465     path.gsub!(/\.(so|bundle|dll|dylib)$/, ".#{Rubinius::LIBSUFFIX}")
467     if path.suffix? '.rbc'
468       rb, rbc, ext = nil, path, nil
469     elsif path.suffix? '.rb'
470       rb, rbc, ext = path, "#{path}c", nil
471     elsif path.suffix? ".#{Rubinius::LIBSUFFIX}"
472       rb, rbc, ext = nil, nil, path
473     else
474       rb, rbc, ext = "#{path}.rb", "#{path}.rbc", "#{path}.#{Rubinius::LIBSUFFIX}"
475     end
476     return rb,rbc,ext
477   end
478   private :__split_path__