Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

255 lines (216 sloc) 6.369 kB
# Make sure File.read will work as expected on any Ruby.
Encoding.default_external = "UTF-8" if defined?(Encoding)
require File.expand_path('../options', __FILE__)
EXTENSIONS = %w{
ripper digest etc readline libyaml fcntl socket zlib bigdecimal openssl json
nkf iconv io
}.sort
class Builder
if defined?(Rake::DSL)
extend Rake::DSL
include Rake::DSL
end
# Runs the given array of +commands+ in parallel. The amount of spawned
# simultaneous jobs is determined by the `jobs' env variable. The default
# value is 1.
#
# When the members of the +commands+ array are in turn arrays of strings,
# then those commands will be executed in consecutive order.
def self.parallel_execute(commands)
commands = commands.dup
Array.new(SIMULTANEOUS_JOBS) do
Thread.new do
while c = commands.shift
Array(c).each { |command| sh(command) }
end
end
end.each { |t| t.join }
end
[:objs, :archs, :cflags, :cxxflags, :objc_cflags, :ldflags, :objsdir,
:objs_cflags, :dldflags].each do |sym|
define_method(sym) { @config.send(sym) }
end
def initialize(config)
self.config = config
end
def config=(c)
if @config != c
@config = c
@obj_sources = {}
@header_paths = {}
FileUtils.mkdir_p(@config.objsdir)
end
end
def build(objs=nil)
objs ||= @config.objs
commands = []
objs.each do |obj|
if should_build?(obj)
s = obj_source(obj)
cc, flags =
case File.extname(s)
when '.c' then [@config.CC, @config.cflags]
when '.cpp' then [@config.CXX, @config.cxxflags]
when '.m' then [@config.CC, @config.objc_cflags]
when '.mm' then [@config.CXX, @config.cxxflags + ' ' + @config.objc_cflags]
end
if f = @config.objs_cflags[obj]
flags += " #{f}"
end
commands << "#{cc} #{flags} -c #{s} -o #{obj_path(obj)}"
end
end
self.class.parallel_execute(commands)
end
def link_executable(name, objs=nil, ldflags=nil)
link(objs, ldflags, "-o #{name}", name)
end
def link_dylib(name, objs=nil, ldflags=nil)
link(objs, ldflags, "#{@config.dldflags} -o #{name}", name)
end
def link_archive(name, objs=nil)
objs ||= @config.objs
if should_link?(name, objs)
rm_f(name)
sh("/usr/bin/ar rcu #{name} #{objs.map { |x| obj_path(x) }.join(' ') }")
sh("/usr/bin/ranlib #{name}")
end
end
private
def obj_path(o)
raise unless @config.objsdir
File.join(@config.objsdir, o + '.o')
end
def link(objs, ldflags, args, name)
objs ||= @config.objs
ldflags ||= @config.ldflags
if should_link?(name, objs)
sh("#{CXX} #{@config.cflags} #{objs.map { |x| obj_path(x) }.join(' ') } #{ldflags} #{args}")
end
end
def should_build?(obj)
if File.exist?(obj_path(obj))
src_time = File.mtime(obj_source(obj))
obj_time = File.mtime(obj_path(obj))
src_time > obj_time \
or dependencies[obj].any? { |f| File.mtime(f) > obj_time }
else
true
end
end
def should_link?(bin, objs)
if File.exist?(bin)
mtime = File.mtime(bin)
objs.any? { |o| File.mtime(obj_path(o)) > mtime }
else
true
end
end
def err(*args)
$stderr.puts args
exit 1
end
def obj_source(obj)
s = @obj_sources[obj]
unless s
s = ['.c', '.cpp', '.m', '.mm'].map { |e| obj + e }.find { |p| File.exist?(p) }
err "cannot locate source file for object `#{obj}'" if s.nil?
@obj_sources[obj] = s
end
s
end
HEADER_DIRS = %w{. include include/ruby}
def header_path(hdr)
p = @header_paths[hdr]
unless p
p = HEADER_DIRS.map { |d| File.join(d, hdr) }.find { |p| File.exist?(p) }
@header_paths[hdr] = p
end
p
end
def locate_headers(cont, src)
txt = File.read(src)
txt.scan(/#\s*include\s+\"([^"]+)\"/).flatten.each do |header|
p = header_path(header)
if p and !cont.include?(p)
cont << p
locate_headers(cont, p)
end
end
end
def dependencies
unless @obj_dependencies
@obj_dependencies = {}
@config.objs.each do |obj|
ary = []
locate_headers(ary, obj_source(obj))
@obj_dependencies[obj] = ary.uniq
end
end
@obj_dependencies
end
class Ext
def self.extension_dirs
EXTENSIONS.map do |name|
Dir.glob(File.join('ext', name, '**/extconf.rb'))
end.flatten.map { |f| File.dirname(f) }
end
def self.build
commands = extension_dirs.map { |dir| new(dir).build_commands }
Builder.parallel_execute(commands)
end
def self.install
extension_dirs.each do |dir|
sh new(dir).install_command
end
end
extend Rake::DSL if defined?(Rake::DSL)
def self.clean
extension_dirs.each do |dir|
new(dir).clean_commands.each { |cmd| sh(cmd) }
end
end
attr_reader :dir
def initialize(dir)
@dir = dir
end
def srcdir
@srcdir ||= File.join(dir.split(File::SEPARATOR).map { |x| '..' })
end
def makefile
@makefile ||= File.join(@dir, 'Makefile')
end
def extconf
File.join(@dir, 'extconf.rb')
end
def create_makefile_command
if !File.exist?(makefile) or File.mtime(extconf) > File.mtime(makefile)
"cd #{dir} && #{srcdir}/miniruby -I#{srcdir} -I#{srcdir}/lib -r rbconfig -e \"RbConfig::CONFIG['libdir'] = '#{srcdir}'; require './extconf.rb'\""
end
end
def build_commands
[create_makefile_command, make_command(:all)].compact
end
def clean_commands
if File.exist?(makefile)
[make_command(:clean), "rm -f #{makefile}"].compact
else
[]
end
end
def install_command
make_command(:install)
end
private
# Possible targets are:
# * all
# * install
# * clean
def make_command(target)
cmd = "cd #{dir} && /usr/bin/make top_srcdir=#{srcdir} ruby=\"#{srcdir}/miniruby -I#{srcdir} -I#{srcdir}/lib\" extout=#{srcdir}/.ext hdrdir=#{srcdir}/include arch_hdrdir=#{srcdir}/include"
cmd << (target == :all ? " libdir=#{srcdir}" : " #{target}")
cmd
end
end
end
$builder = Builder.new(FULL_CONFIG)
Jump to Line
Something went wrong with that request. Please try again.