Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 1665 lines (1345 sloc) 44.108 kb
#!/usr/bin/env ruby
if ENV["RUBYLIB"]
STDERR.puts "ERROR: Please unset RUBYLIB to configure Rubinius"
exit 1
end
require 'rbconfig'
require 'tempfile'
require 'fileutils'
require 'stringio'
root = File.expand_path File.dirname(__FILE__)
require File.join(root, "kernel", "delta", "options")
class Configure
def initialize(root)
@log = Logger.new "configure.log"
@defines = []
@config = File.join(root, "config.rb")
@host = `sh -c ./rakelib/config.guess`.chomp
/([^-]+)-([^-]+)-(.*)/ =~ @host
@cpu, @vendor, @os = $1, $2, $3
@little_endian = false
@sizeof = {}
# TODO: For better cross-compiling support, it may be necessary to
# use the feature facility to check for a define in the compiler.
@windows = (@host =~ /mingw|mswin/) != nil
@darwin = (@host =~ /darwin/) != nil
@bsd = (@host =~ /bsd/) != nil
@linux = (@host =~ /linux/) != nil
# Set up system commands to run in cmd.exe on Windows.
if @windows
alias :old_system :system
alias :old_backquote :`
alias :system :msys_system
alias :` :msys_backquote
end
# Compiler / build settings
@cc = ENV['CC'] || 'gcc'
@cxx = ENV['CXX'] || 'g++'
@rake = ENV['RAKE'] || 'rake'
@tar = ENV['TAR'] || (@windows ? 'bsdtar' : 'tar')
@perl = ENV['PERL'] || 'perl'
@install = false
@default_version = "18"
@version_list = ["18", "19"]
@supported_versions = ["18", "19", "20"]
@build_ruby = nil
# LLVM settings
@use_llvm = true
@llvm = :no
@llvm_path = nil
@llvm_configure = nil
@llvm_skip_system = false
@llvm_skip_prebuilt = false
@llvm_prebuilt_name = nil
@llvm_system_name = get_system_name
@llvm_version = "3.0"
@llvm_api_version = 300
@llvm_source = "llvm-3.0.tgz"
@llvm_source_dir = "llvm-3.0.src"
@llvm_source_url = "http://llvm.org/releases/3.0/llvm-3.0.tar.gz"
@llvm_asset_path = "http://asset.rubini.us/prebuilt"
@llvm_source_build = false
if @host == "i686-pc-linux-gnu" || @host == "x86_64-unknown-linux-gnu"
check_tool_version @cc, '-dumpversion', [4, 1]
check_tool_version 'bison', '--version', [2, 3]
@gcc_major = `#{@cc} -dumpversion`.strip.split(".")[0,2].join(".")
@llvm_generic_prebuilt = "llvm-#{@llvm_version}-#{@host}-#{@gcc_major}.tar.bz2"
else
@llvm_generic_prebuilt = "llvm-#{@llvm_version}-#{@host}.tar.bz2"
end
@llvm_parent_path = File.join(root, "vendor")
@llvm_default = File.join(@llvm_parent_path, "llvm")
@llvm_prebuilt_path = File.join(@llvm_parent_path, "prebuilt")
@llvm_include_path = File.join(@llvm_default, "include")
# System settings
@libc = nil
@x86_32 = false
@x86_64 = false
@fibers = false
@include_dirs = []
@lib_dirs = []
# File system paths
@bindir = root + "/bin"
@include18dir = root + "/vm/capi/18/include"
@include19dir = root + "/vm/capi/19/include"
@include20dir = root + "/vm/capi/19/include"
@libdir = root
@runtime = @libdir + "/runtime"
@kernel_path = @libdir + "/kernel"
@lib_path = @libdir + "/lib"
@mandir = root + "/man"
@gemsdir = root + "/gems"
# Some simple defaults for when running directly out of the build dir
@sitedir = @lib_path + "/site"
@vendordir = @lib_path + "/vendor"
@program_name = "rbx"
# Library configuration
@rb_readline = false
@vendor_zlib = false
@libyaml = false
# Essential settings (modify these for creating releases)
@libversion = "2.0"
@version = "#{@libversion}.0dev"
@release_date = "yyyy-mm-dd"
@config_version = 156
# TODO: add conditionals for platforms
if RbConfig::CONFIG["build_os"] =~ /darwin/
@ldshared = "#{@cc} -bundle -undefined suppress -flat_namespace"
else
@ldshared = "#{@cc} -shared"
end
import_env
end
# Set up system commands to run in cmd.exe on Windows. Either Windows
# or MRI on Windows has issues with subprocesses where the invocation
# of the subprocess will return before the subprocess has finished.
# This manifests in configure when uncompressing LLVM source returns
# but attempting to move the directory fails sporadically with an access
# exception. Adding the, essentially no-op, 'sleep 0' resolves this.
def msys_system(cmd)
old_system %[cmd.exe /C "#{cmd} && sleep 0"]
end
def msys_backquote(cmd)
old_backquote %[cmd.exe /C "#{cmd}"]
end
def import_env
@user_cflags = ENV['CFLAGS']
@user_cppflags = ENV['CPPFLAGS']
@user_ldflags = ENV['LDFLAGS']
end
def expand(path)
File.expand_path(path)
end
def options
o = Rubinius::Options.new "Usage: configure [options]", 30
o.left_align
o.doc " Configure settings"
o.on "--log-file", "NAME", "Write log to file NAME" do |name|
old_log = @log.path
@log = Logger.new name, false
@log.replace old_log
end
o.on "--rake", "NAME", "Use NAME as 'rake' during build" do |name|
@rake = name
end
o.on "--tar", "NAME", "Use NAME as 'tar'" do |name|
@tar = name
end
o.on "--perl", "NAME", "Use NAME as 'perl' during build" do |name|
@perl = name
end
o.doc "\n Language version settings"
o.on "--default-version", "VERSION", "Enable Ruby VERSION as the default" do |v|
version = normalize_versions v
if version.size > 1
failure "Only one version can be default, given: #{version.inspect}."
end
@default_version = version.first
unless @version_list.include? @default_version
failure "Requested default version #{@default_version} is not enabled."
end
end
o.on "--enable-version", "VERSION", "Enable Ruby VERSION support (eg 18,19)" do |v|
@version_list = normalize_versions v
@default_version = @version_list.first if @version_list.size == 1
end
o.doc "\n Compiler settings"
o.on "--cc", "COMPILER", "Compiler to use for C code (eg gcc, clang)" do |cc|
@cc = cc
end
o.on "--cxx", "COMPILER", "Compiler to use for C++ code (eg g++, clang++)" do |cxx|
@cxx = cxx
end
o.doc "\n LLVM settings"
o.on "--disable-llvm", "Don't build with LLVM" do
@use_llvm = false
end
o.on "--enable-llvm", "Enable llvm (default)" do
@use_llvm = true
end
o.on "--skip-system", "Don't consider a system LLVM installation" do
@llvm_skip_system = true
end
o.on "--skip-prebuilt", "Don't try to use a prebuilt version of LLVM" do
@llvm_skip_prebuilt = true
end
o.on "--system-name", "NAME", "Name of OS (eg fedora-8, ubuntu-10.04)" do |name|
@llvm_system_name = name
end
o.on "--prebuilt-name", "NAME", "Full name of LLVM prebuilt archive" do |name|
@llvm_prebuilt_name = name
end
o.on "--llvm-path", "PATH", "File system path to the directory containing LLVM" do |dir|
@llvm_path = dir
end
o.on "--llvm-config", "PROGRAM", "File system path to the llvm-config program" do |program|
@llvm_configure = program
end
o.on "--update-prebuilt", "Update prebuilt LLVM packages from the internet" do
update_prebuilt @llvm_generic_prebuilt, true
end
o.doc "\n System settings"
o.on "--with-include-dir", "DIR", "Add DIR to the default include search paths" do |dir|
@include_dirs << dir
end
o.on "--with-lib-dir", "DIR", "Add DIR to the default library search paths" do |dir|
@lib_dirs << dir
end
o.on "--with-opt-dir", "DIR", "Add DIR/include and DIR/lib to include and library search paths" do |dir|
@include_dirs << "#{dir}/include"
@lib_dirs << "#{dir}/lib"
end
o.on "--libc", "NAME", "Use NAME as the libc for FFI" do |name|
@libc = name
end
o.doc "\n File system paths for installing Rubinius"
o.on "-P", "--prefix", "PATH", "Install Rubinius in subdirectories of PATH" do |dir|
@install = true
dir = File.expand_path dir
if !ENV['RELEASE'] and File.directory? dir and dir !~ /(rubinius|rbx).*\/?$/
old = dir
dir += "/rubinius/#{@libversion}"
@log.write "The directory #{old} already exists, installing to #{dir}"
end
@bindir = dir + "/bin"
@include18dir = dir + "/18/include"
@include19dir = dir + "/19/include"
@include20dir = dir + "/19/include"
@libdir = dir
@runtime = @libdir + "/runtime"
@kernel_path = @libdir + "/kernel"
@lib_path = @libdir + "/lib"
@mandir = dir + "/man"
@gemsdir = dir + "/gems"
@sitedir = dir + "/site"
@vendordir = dir + "/vendor"
end
o.on "-B", "--bindir", "PATH", "Install Rubinius executable in PATH" do |dir|
@install = true
@bindir = expand dir
end
o.on "-I", "--includedir", "PATH", "Install Rubinius C-API include files in PATH" do |dir|
@install = true
path = expand dir
@include18dir = path + "/18"
@include19dir = path + "/19"
@include20dir = path + "/20"
end
o.on "-L", "--libdir", "PATH", "Install Ruby library in PATH" do |dir|
@install = true
@libdir = expand(dir) + "/rubinius/#{@libversion}"
@runtime = @libdir + "/runtime"
@kernel_path = @libdir + "/kernel"
@lib_path = @libdir + "/lib"
@sitedir = @libdir + "/site"
@vendordir = @libdir + "/vendor"
end
o.on "-M", "--mandir", "PATH", "Install man pages in PATH" do |dir|
@install = true
@mandir = expand dir
end
o.on "-G", "--gemsdir", "PATH", "Install gems in PATH" do |dir|
@install = true
@gemsdir = expand dir
end
o.on "--sitedir", "PATH", "Install site-specific Ruby code in PATH" do |dir|
@install = true
@sitedir = expand dir
end
o.on "--vendordir", "PATH", "Install vendor-specific Ruby code in PATH" do |dir|
@install = true
@vendordir = expand dir
end
o.doc "\n Optional features"
@options = o
@features = {}
default_on = RUBY_PLATFORM !~ /openbsd/i
feature "execinfo", default_on
feature "C-readline", true
feature "ruby-readline", false
feature "vendor-zlib", !!@windows
feature "alloc-tracking", false
feature "fibers", true
o.doc "\n Help!"
o.on "--show", "Print the current configuration and exit" do
print_debug
exit 0
end
o.on "-V", "--verbose", "Print additional info" do
@verbose = true
end
o.help
o.doc ""
end
def feature(name, on_by_default=true)
@features[name] = on_by_default
@options.on "--with-#{name}", "Enable #{name}" do
@features[name] = true
end
@options.on "--without-#{name}", "Disable #{name}" do
@features[name] = false
end
end
def parse(ary)
@options.parse ary
end
def normalize_versions(str)
versions = str.gsub(/[^\d,]/, "").split(',')
versions.each do |ver|
unless @supported_versions.include? ver
failure <<-EOM
Unsupported language version requested: #{ver}. Options are #{@supported_versions.join(", ")}
EOM
end
end
versions
end
require 'digest/md5'
def md5_checksum(md5_path, full_path)
return Digest::MD5.file(full_path).hexdigest == File.read(md5_path).strip.split(" ").first
end
require 'net/http'
def download(url, full_path)
begin
if ENV['http_proxy']
protocol, userinfo, host, port = URI::split(ENV['http_proxy'])
proxy_user, proxy_pass = userinfo.split(/:/) if userinfo
http = Net::HTTP::Proxy(host, port, proxy_user, proxy_pass)
else
http = Net::HTTP
end
@log.write " Downloading #{File.basename(full_path)}..."
http.get_response(URI(url)) do |res|
case res
when Net::HTTPNotFound
@log.write " Not found."
return false
when Net::HTTPClientError
@log.write " ERROR: #{res.inspect}"
return false
end
size = 0
total = res.header['Content-Length'].to_i
File.open full_path, "wb" do |f|
res.read_body do |chunk|
f << chunk
size += chunk.size
print "\r [ %d%% (%d of %d) ]" % [(size * 100) / total, size, total]
end
end
@log.write ": done!"
end
rescue Exception => e
File.unlink full_path if File.exists?(full_path)
@log.write " ERROR: #{e.message}"
return false
end
return true
end
# Downloads a pre-built LLVM library for a platform if the file exists. If
# an MD5 checksum file exists for the library, the checksum of the library
# is compared and the update fails if it does not match. If no MD5 checksum
# file exists, the library is used without check.
def update_prebuilt(file, warn)
full_path = File.join @llvm_prebuilt_path, file
md5_path = "#{full_path}.md5"
dir = File.dirname full_path
Dir.mkdir dir unless File.exists? dir
url = File.join @llvm_asset_path, file
unless File.exists? full_path
download url, full_path
unless File.exists? full_path
@log.write "ERROR. No #{file} available on server." if warn
return false
end
end
md5_url = "#{url}.md5"
download md5_url, md5_path
if File.exists? md5_path
unless md5_checksum md5_path, full_path
@log.write "ERROR. #{file} was corrupted or MD5 checksum is outdated."
return false
else
@log.write " MD5 checksum for prebuilt LLVM verified."
end
else
@log.write " No MD5 checksum for #{file} available on server."
@log.write " Using LLVM library without checksum validation."
end
@log.write " Prebuilt packages updated."
end
def verify_llvm_source
return false unless File.exists? @llvm_default
if File.exists?(@llvm_include_path)
@llvm = :svn
return true
else
@log.write " Code doesn't appear to be proper LLVM tree!"
return false
end
end
def setup_source
@log.print " Checking for existing LLVM source tree:"
# Check if source already exists
if verify_llvm_source
@log.write " found!"
return true
else
@log.write " not found."
end
url = @llvm_source_url
path = File.join @llvm_prebuilt_path, @llvm_source
unless File.exists?(path)
@log.write " Downloading #{url}..."
return false unless download(url, path)
end
if File.exists?(path)
@log.print " Unpacking LLVM source: "
Dir.chdir @llvm_parent_path do
system "#{@tar} xzf #{path}"
FileUtils.mv @llvm_source_dir, "llvm"
end
@log.write "done!"
if verify_llvm_source
@log.write " Code appears to be a proper tree."
@llvm_source_build = true
return true
end
end
end
def prebuilt_files
files = [@llvm_generic_prebuilt]
# If we have a system name, try to find a prebuilt specifically
# for this system first.
if @llvm_system_name
files.unshift "llvm-#{@llvm_version}-#{@host}-#{@llvm_system_name}.tar.bz2"
end
# Try one for just the darwin major version (which increases for each
# minor OS X version. ie. 10.5 == 9.x.x, 10.6 == 10.x.x)
if m = /darwin(\d+)\.(\d+)\.(\d+)/.match(@os)
# Try this last
files.push "llvm-#{@llvm_version}-#{@cpu}-#{@vendor}-darwin#{m[1]}.tar.bz2"
end
# If the user specified a name, try that before anything.
files.unshift @llvm_prebuilt_name if @llvm_prebuilt_name
files
end
def setup_prebuilt
@log.write " Checking for prebuilt LLVM package..."
prebuilt_files.each do |file|
path = File.join @llvm_prebuilt_path, file
update_prebuilt file, false unless File.exists?(path)
if File.exists?(path)
@log.print " Unpacking prebuilt LLVM: #{file}: "
dir = File.join @llvm_parent_path, "llvm"
FileUtils.mkdir_p dir
Dir.chdir dir do
system "#{@tar} xjf #{path}"
end
@log.write "done!"
@llvm = :prebuilt
return true
end
end
@log.write " Unable to download any LLVM prebuilt"
return false
end
def setup_path
@log.print "Validating '#{@llvm_path}': "
if File.directory? @llvm_path
["Release", "Debug"].each do |which|
sub = File.join(@llvm_path, which, "bin")
if File.directory? sub
@log.write "Ok! Using #{which}"
@llvm_configure = File.join(@llvm_path, which, "bin", "llvm-config")
@llvm = :config
return true
end
end
@log.write "ERROR. Doesn't appear to be built already!"
return false
end
@log.write "ERROR. Path doesn't exist."
return false
end
def remove_default
if File.exists?(File.join(@llvm_default, "Makefile.common"))
failure "ABORT: Unwilling to override custom LLVM tree, please update it manually."
else
@log.write " Removing outdated tree..."
FileUtils.rm_rf(@llvm_default)
end
end
def setup_auto
@log.print " Checking for existing LLVM library tree: "
if File.directory?("#{@llvm_default}/Release")
version = `#{@perl} #{@llvm_default}/Release/bin/llvm-config --version`.strip
if version == "3.0"
# See if this has rtti turned off and reject it.
if `#{@perl} #{@llvm_default}/Release/bin/llvm-config --cxxflags`.index("-fno-rtti")
@log.write "incorrectly configure (rtti is off)"
remove_default
else
@log.write "found!"
if File.exists?(File.join(@llvm_default, "Makefile.common"))
@llvm = :svn
else
@llvm = :prebuilt
end
return
end
else
@log.write "outdated (version #{version})"
remove_default
end
else
@log.write "not found."
end
# If they explicitly said where LLVM is, use that and fail hard.
if @llvm_path
unless setup_path
failure "ABORT: Path '#{@llvm_path}' not a proper LLVM path."
end
return
end
return if !@llvm_skip_system && setup_config
return if !@llvm_skip_prebuilt && setup_prebuilt
return if setup_source
@log.write "WARNING: Unable to configure for LLVM, disabling support."
@use_llvm = false
end
def setup_config
@log.print " Checking for 'llvm-config': "
config = @llvm_configure
if !config
which = ENV['PATH'].split(":").find do |path|
File.exists? File.join(path, "llvm-config")
end
if which
config = File.join(which, "llvm-config")
end
end
if config
version = `#{@perl} #{config} --version`.strip
parts = version.sub(/svn$/, "").split(".").map { |i| i.to_i }
api_version = ("%d%02d" % parts[0..1]).to_i
if `#{@perl} #{config} --cxxflags`.index("-fno-rtti")
@log.write "incorrectly configured llvm (rtti is off)"
elsif api_version != 300
@log.write "only LLVM 3.0 is supported"
else
@log.write "found! (version #{version} - api: #{api_version})"
@llvm_configure = config
@llvm = :config
@llvm_api_version = api_version
return true
end
else
@log.write "not found"
end
false
end
def c_includes
@include_dirs.map do |d|
"-I#{d}"
end.join(" ")
end
def env(which)
ENV[which] || ""
end
def default_link_libs
libs = []
unless @host =~ /haiku/
libs << "m"
end
libs
end
def failure(message=nil)
message ||= "'configure' has failed."
@log.error message
STDERR.puts "\n#{message} Please check configure.log for more details."
exit 1
end
def check_program(run=true, link_libs=[])
begin
basename = "rbx-configure-test"
source = basename + ".cpp"
File.open source, "wb" do |f|
yield f
end
libs = (default_link_libs + link_libs).map { |l| "-l#{l}" }.join(" ")
cmd = "#{@cxx} #{env('CFLAGS')} -lstdc++ #{libs} -o #{basename} #{source} >>#{@log.path} 2>&1"
@log.log cmd
system cmd
return $?.exitstatus unless run
unless $?.exitstatus == 0
failure "Compiling configure test program failed."
end
system expand("./#{basename}")
return $?.exitstatus
ensure
File.delete(*Dir["#{basename}*"])
end
end
def write_have_defines(f)
f.puts
@defines.each { |d| f.puts "#define #{d.ljust(20)} 1" }
end
def write_have_sizeof_defines(f)
f.puts
@sizeof.keys.sort.each { |k| f.puts "#define HAVE_#{k}".ljust(30) + "1" }
end
def write_sizeof_defines(f)
f.puts
@sizeof.keys.sort.each { |k| f.puts "#define SIZEOF_#{k}".ljust(30) + @sizeof[k].to_s }
end
def sizeof_typename(type)
if type =~ /(\*+)$/
name = "#{type[0...-$1.size]}#{"p" * $1.size}"
else
name = type
end
name.gsub(/\W/, "_").upcase
end
def sizeof(type)
@sizeof[sizeof_typename(type)] or failure("Unknown type: '#{type}'.")
end
def detect_sizeof(type, includes=[])
@log.print "Checking sizeof(#{type}): "
size = check_program do |f|
src = includes.map { |include| "#include <#{include}>" }.join("\n")
src += <<-EOP
#include <stddef.h>
int main() { return sizeof(#{type}); }
EOP
f.puts src
@log.log src
end
@sizeof[sizeof_typename(type)] = size
@log.write "#{size} bytes"
end
def detect_endian
@log.print "Checking platform endianness: "
status = check_program do |f|
src = "int main() { int one = 1; return (*((char*)&one)) == 1 ? 0 : 1; }"
f.puts src
@log.log src
end
@little_endian = (status == 0)
@log.write @little_endian ? "little endian" : "big endian"
end
def detect_tr1_hash
@log.print "Checking tr1/hash definition: "
status = check_program(false) do |f|
src = <<-EOP
#include <stdint.h>
#include <tr1/unordered_map>
typedef std::tr1::unordered_map<uint64_t, void*> X;
int main() { X x; return 0; }
EOP
f.puts src
@log.log src
end
@tr1_hash = (status == 0)
@log.write @tr1_hash ? "found" : "not found"
end
def detect_x86
print "Checking for x86_32: "
if sizeof("long") == 4
status = check_program do |f|
src = <<-EOP
int main() {
#if defined(i386) || defined(__i386__) || defined(__i386)
return 1;
#else
return 0;
#endif
}
EOP
f.puts src
@log.log src
end
@x86_32 = (status == 1)
end
puts @x86_32 ? "yes" : "no"
return if @x86_32
print "Checking for x86_64: "
status = check_program do |f|
src = <<-EOP
int main() {
#if defined(__x86_64) || defined(__x86_64__)
return 1;
#else
return 0;
#endif
}
EOP
f.puts src
@log.log src
end
@x86_64 = (status == 1)
puts @x86_64 ? "yes" : "no"
end
def detect_curses
@log.print "Checking curses library: "
src = <<-EOP
#include <curses.h>
#include <term.h>
int main() { return tgetnum(""); }
EOP
["curses", "ncurses", "termcap"].each do |lib|
status = check_program(false, [lib]) do |f|
f.puts src
@log.log src
end
if status == 0
@curses = lib
break
end
end
@log.write @curses ? @curses : "not found"
end
def detect_include_dirs
@include_dirs = @include_dirs.select {|p| File.directory? p }
end
def detect_lib_dirs
@lib_dirs = @lib_dirs.select {|p| File.directory? p }
end
def has_struct_member(struct, member, includes = [])
compile_check "struct #{struct} has member #{member}" do |src|
includes.each do |i|
src.puts "#include <#{i}>"
end
src.puts "int main() { struct #{struct} st; st.#{member}; }"
end
end
def has_global(name, includes=[])
compile_check "global '#{name}'" do |src|
includes.each do |i|
src.puts "#include <#{i}>"
end
src.puts "int main() { #{name}; }"
end
end
def has_header(name)
compile_check "header '#{name}'" do |src|
src.puts "#include <#{name}>"
src.puts "int main() {return 0;}"
end
end
def has_function(name, includes=[])
compile_check "function '#{name}'" do |src|
includes.each do |i|
src.puts "#include <#{i}>"
end
src.puts "int main() { void* ptr = &#{name}; }"
end
end
def compile_check(logpart, &block)
@log.print "Checking for #{logpart}: "
source = StringIO.new
yield source
file = Tempfile.new("rbx-test")
source.rewind
string = source.read
file.puts string
file.close
@log.log string
cmd = "#{@cxx} -S -o - -x c #{c_includes} #{env('CFLAGS')} #{file.path} >>#{@log.path} 2>&1"
@log.log cmd
system cmd
status = ($?.exitstatus == 0)
file.unlink
@log.write(status ? "found!" : "not found")
status
end
def detect_features
if @features["execinfo"] and has_function("backtrace", ["execinfo.h"])
@defines << "HAS_EXECINFO"
end
if @features["alloc-tracking"]
@defines << "RBX_ALLOC_TRACKING"
end
if @features["ruby-readline"]
@rb_readline = true
else
if @features["C-readline"] and
(has_function("readline", ["stdio.h", "stdlib.h", "readline/readline.h"]) or
has_function("readline", ["stdio.h", "stdlib.h", "editline/readline.h"]))
@rb_readline = false
else
@rb_readline = true
end
end
if @features["fibers"]
@fibers = true if @x86_32 or @x86_64
end
@vendor_zlib = true if @features["vendor-zlib"]
@defines << "HAVE_SPT_REUSEARGV" if @linux || @darwin || @bsd
end
def detect_functions
if has_function("yaml_parser_initialize", ["yaml.h"])
@libyaml = true
end
if has_function("clock_gettime", ["time.h"])
@defines << "HAVE_CLOCK_GETTIME"
end
if has_function("nl_langinfo", ["langinfo.h"])
@defines << "HAVE_NL_LANGINFO"
end
if has_function("setproctitle", ["sys/types.h", "unistd.h"])
@defines << "HAVE_SETPROCTITLE"
end
if has_function("posix_fadvise", ["fcntl.h"])
@defines << "HAVE_POSIX_FADVISE"
end
end
def detect_structures
if has_struct_member("tm", "tm_gmtoff", ["time.h"])
@defines << "HAVE_TM_GMTOFF"
end
if has_struct_member("tm", "tm_zone", ["time.h"])
@defines << "HAVE_TM_ZONE"
end
end
def detect_globals
if has_global("timezone", ["time.h"])
@defines << "HAVE_TIMEZONE"
end
if has_global("tzname", ["time.h"])
@defines << "HAVE_TZNAME"
end
if has_global("daylight", ["time.h"])
@defines << "HAVE_DAYLIGHT"
end
end
def detect_headers
if has_header("alloca.h")
@defines << "HAVE_ALLOCA_H"
end
if has_header("string.h")
@defines << "HAVE_STRING_H"
end
if has_header("sys/time.h")
@defines << "HAVE_SYS_TIME_H"
end
if has_header("sys/times.h")
@defines << "HAVE_SYS_TIMES_H"
end
if has_header("sys/types.h")
@defines << "HAVE_SYS_TYPES_H"
end
if has_header("unistd.h")
@defines << "HAVE_UNISTD_H"
end
if has_header("stdarg.h")
@defines << "HAVE_STDARG_H"
end
if has_header("sys/pstat.h")
@defines << "HAVE_SYS_PSTAT_H"
end
end
def process
if @use_llvm
@log.write "Configuring LLVM..."
setup_auto
else
@log.write "WARNING: LLVM disabled."
end
@log.write ""
["/usr/local", "/opt/local"].each do |dir|
@include_dirs << "#{dir}/include"
@lib_dirs << "#{dir}/lib"
end
detect_include_dirs
detect_lib_dirs
detect_sizeof("short")
detect_sizeof("int")
detect_sizeof("void*")
detect_sizeof("size_t")
detect_sizeof("long")
detect_sizeof("long long")
detect_sizeof("float")
detect_sizeof("double")
detect_sizeof("off_t", ["unistd.h"])
detect_sizeof("time_t", ["time.h"])
detect_libc_name
detect_endian
detect_tr1_hash
detect_x86
detect_features
detect_functions
detect_structures
detect_globals
detect_headers
detect_curses
end
def which_ruby
if Object.const_defined?(:RUBY_ENGINE)
@which_ruby = RUBY_ENGINE.to_sym
else
@which_ruby = :ruby
end
end
# Records the full path to the ruby executable that runs this configure
# script. That path will be made available to the rest of the build system
# so the same version of ruby is invoked as needed.
def build_ruby
unless @build_ruby
bin = RbConfig::CONFIG["RUBY_INSTALL_NAME"] || RbConfig::CONFIG["ruby_install_name"]
bin += (RbConfig::CONFIG['EXEEXT'] || RbConfig::CONFIG['exeext'] || '')
@build_ruby = File.join(RbConfig::CONFIG['bindir'], bin)
end
@build_ruby
end
def get_system_name
return unless @os =~ /linux/
return unless File.exists? "/etc/issue"
data = IO.readlines("/etc/issue").first
data =~ /([^ ]+)[^\d\.]*([\d\.]*)/
name = $1.downcase
version = $2
if name == "debian" and File.exists? "/etc/debian_version"
version = IO.read("/etc/debian_version").split.first.gsub(/\W/, "-")
end
return "#{name}-#{version}"
end
def check_tool_version(tool_name, opts, version, regexp=/(?=\d)(\d+).(\d+).?(\d+)?/)
@log.print "Checking #{tool_name}:"
output = `#{tool_name} #{opts}`
if $?.exitstatus == 0
v = output.scan(regexp)[0].map { |x| x.to_i }
unless (v <=> version) >= 0
failure " Expected #{tool_name} version >= #{version.join('.')}, found #{v.join('.')}"
end
@log.write " found"
else
failure "#{tool_name} not found."
end
end
def detect_libc_name
return if @libc
@log.print "Checking for libc version: "
case
when @windows
@libc = "msvcrt.dll"
when @darwin
@libc = "libc.dylib"
else
begin
ldd_output = `ldd #{build_ruby}`
@libc = ldd_output[/libc\.so\.[0-9]+/]
rescue
# Don't abort if the command is not found
end
unless $?.success? and @libc
failure "libc not found. Use the --libc configure option."
end
end
@log.write "#{@libc} found!"
end
def write_config
unless @use_llvm
@llvm = :no
@llvm_configure = ""
end
# Write the config file used by the build system and rbconfig.rb.
File.open @config, "wb" do |f|
# TODO: Make this the actual data structure that is written out.
f.puts <<-EOC
module Rubinius
BUILD_CONFIG = {
:which_ruby => :#{which_ruby},
:build_ruby => "#{build_ruby}",
:build_rake => "#{@rake}",
:build_perl => "#{@perl}",
:llvm => :#{@llvm},
:llvm_configure => "#{@llvm_configure}",
:cc => "#{@cc}",
:cxx => "#{@cxx}",
:user_cflags => "#{@user_cflags}",
:user_cppflags => "#{@user_cppflags}",
:user_ldflags => "#{@user_ldflags}",
:include_dirs => #{@include_dirs.inspect},
:lib_dirs => #{@lib_dirs.inspect},
:defines => #{@defines.inspect},
:curses => #{@curses.inspect},
:host => "#{@host}",
:cpu => "#{@cpu}",
:vendor => "#{@vendor}",
:os => "#{@os}",
:little_endian => #{@little_endian},
:sizeof_long => #{sizeof("long")},
:x86_32 => #{@x86_32},
:x86_64 => #{@x86_64},
:fibers => #{@fibers},
:bindir => "#{@bindir}",
:libdir => "#{@libdir}",
:runtime => "#{@runtime}",
:kernel_path => "#{@kernel_path}",
:lib_path => "#{@lib_path}",
:include18dir => "#{@include18dir}",
:include19dir => "#{@include19dir}",
:include20dir => "#{@include20dir}",
:mandir => "#{@mandir}",
:gemsdir => "#{@gemsdir}",
:sitedir => "#{@sitedir}",
:vendordir => "#{@vendordir}",
:program_name => "#{@program_name}",
:version => "#{@version}",
:libversion => "#{@libversion}",
:release_date => "#{@release_date}",
:config_version => #{@config_version},
:windows => #{@windows},
:darwin => #{@darwin},
:bsd => #{@bsd},
:linux => #{@linux},
:version_list => #{@version_list.inspect},
:default_version => "#{@default_version}",
:vendor_zlib => #{@vendor_zlib},
:readline => :#{@rb_readline ? :rb_readline : :c_readline},
:libyaml => #{@libyaml}
}
end
EOC
end
Dir.mkdir "lib/rubinius" unless File.directory? "lib/rubinius"
FileUtils.cp @config, "lib/rubinius/build_config.rb"
# Write the config file used to build the C++ VM.
Dir.mkdir "vm/gen" unless File.directory? "vm/gen"
vm_config_h = "vm/gen/config.h"
File.open vm_config_h, "wb" do |f|
f.puts <<-EOC
#define RBX_HOST "#{@host}"
#define RBX_CPU "#{@cpu}"
#define RBX_VENDOR "#{@vendor}"
#define RBX_OS "#{@os}"
#define RBX_BIN_PATH "#{@bindir}"
#define RBX_GEMS_PATH "#{@gemsdir}"
#define RBX_RUNTIME "#{@runtime}"
#define RBX_KERNEL_PATH "#{@kernel_path}"
#define RBX_LIB_PATH "#{@lib_path}"
#define RBX_HDR18_PATH "#{@include18dir}"
#define RBX_HDR19_PATH "#{@include19dir}"
#define RBX_HDR20_PATH "#{@include20dir}"
#define RBX_SITE_PATH "#{@sitedir}"
#define RBX_VENDOR_PATH "#{@vendordir}"
#define RBX_VERSION "#{@version}"
#define RBX_LIB_VERSION "#{@libversion}"
#define RBX_LDSHARED "#{@ldshared}"
#define RBX_RELEASE_DATE "#{@release_date}"
#define RBX_SIZEOF_LONG #{sizeof("long")}
#define RBX_LLVM_API_VER #{@llvm_api_version}
#define RBX_LIBC "#{@libc}"
EOC
if @vendor_zlib
f.puts %[#define RBX_ZLIB_PATH "#{@lib_path}/zlib/"]
else
f.puts %[#define RBX_ZLIB_PATH ""]
end
@supported_versions.each do |ver|
f.puts "#define RBX_DEFAULT_#{ver} #{ver == @default_version}"
end
@version_list.each do |ver|
f.puts "#define RBX_ENABLED_#{ver} 1"
end
if @little_endian
f.puts "#define RBX_LITTLE_ENDIAN 1"
end
if @tr1_hash
f.puts "#define RBX_HAVE_TR1_HASH 1"
end
[:windows, :darwin, :bsd, :linux].each do |platform|
if instance_variable_get(:"@#{platform}")
f.puts "#define RBX_#{platform.to_s.upcase} 1"
end
end
if @fibers
f.puts "#define RBX_FIBER_ENABLED 1"
end
write_have_defines f
end
FileUtils.cp vm_config_h, "vm/capi/18/include/rbx_config.h"
FileUtils.cp vm_config_h, "vm/capi/19/include/rbx_config.h"
# Write the config file for vendor/oniguruma.
File.open "vendor/oniguruma/config.h", "wb" do |f|
f.puts <<-EOC
/* This file is generated by the Rubinius build system. Your edits
* will be lost. See the configure script.
*/
EOC
write_have_defines f
write_have_sizeof_defines f
write_sizeof_defines f
end
# Write the config file used in the C-API.
config_h = "vm/capi/18/include/config.h"
File.open config_h, "wb" do |f|
f.puts <<-EOC
/* This file is generated by the build system. Your edits
* will be lost. See the configure script.
*/
#ifndef NORETURN
#define NORETURN(x) __attribute__ ((noreturn)) x
#endif
EOC
write_have_sizeof_defines f
write_sizeof_defines f
if @windows
f.puts "#define RBX_WINDOWS 1"
end
end
FileUtils.cp config_h, "vm/capi/19/include/ruby/config.h"
# Write definitions for the MRI Object-Oriented Pointer (OOP) definitions.
mri_oop_h = "vm/capi/18/include/mri_oop.h"
File.open mri_oop_h, "wb" do |f|
f.puts <<-EOO
#ifndef RBX_CAPI_MRI_OOP_H
#define RBX_CAPI_MRI_OOP_H
/* This file is generated by the build system. Your edits
* will be lost. See the configure script.
*/
/*
* In MRI, VALUE represents an object.
*
* In Rubinius, this is a Handle.
*/
#define VALUE intptr_t
/*
* In MRI, ID represents an interned string, i.e. a Symbol.
*
* In Rubinius, this is a raw Symbol.
*/
#define ID intptr_t
/*
* The C-API uses handles to refer to all Ruby objects rather than raw
* pointers to objects. There are four categories of objects:
*
* 1. References (e.g. instances of Array, String, Hash, etc.)
* 2. Fixnums
* 3. Symbols
* 4. "Booleans" (i.e. Qfalse, Qtrue, Qnil, Qundef)
*
* The handles are tagged to distinguish the categories of objects.
*
* The tagging scheme allows passing Symbols and Fixnums straight through
* without changing their values. This ensures that if a C extension
* assigns a global ID with the value of a Symbol, any subsequent handle
* requested for that symbol (e.g. from rb_intern()) will have the same
* value. Passing Fixnums through means that all the Fixnum conversions
* do not have to be reimplemented for the C-API.
*
* The tags break down as follows (@see vm/oop.hpp for more details):
*
* 00 0 0000 Qfalse
* xx x xxx1 Fixnum
* xx x x110 Symbol
*
* 01 0 0010 Qtrue
* 10 0 0010 Qnil
* 11 0 0010 Qundef
*
* In other words, any bit pattern ending in 1 is a Fixnum, ending in 110
* is a Symbol, ending in 0010 is a C-API "boolean" and Qfalse is 0.
*
* NOTE: The Qfalse value is defined to be 0 because it is 0 in MRI and
* extensions written for MRI have (absolutely wrongly, infuriatingly,
* but-what-can-you-do-now) relied on that assumption in boolean contexts.
* Rather than fighting a myriad subtle bugs, we just go along with it.
*/
/* The false object. */
#define Qfalse ((VALUE)0x00)
/* The true object. */
#define Qtrue ((VALUE)0x22)
/* The nil object. */
#define Qnil ((VALUE)0x42)
/* The undef object. NEVER EXPOSE THIS TO USER CODE. EVER. */
#define Qundef ((VALUE)0x62)
#define FALSE_P(v) ((VALUE)(v) == Qfalse)
#define TRUE_P(v) ((VALUE)(v) == Qtrue)
#define NIL_P(v) ((VALUE)(v) == Qnil)
#define UNDEF_P(v) ((VALUE)(v) == Qundef)
#undef TAG_REF
#undef TAG_REF_MASK
#define TAG_REF 0x0
#define TAG_REF_MASK 0x3
#undef TAG_FIXNUM
#undef TAG_FIXNUM_SHIFT
#undef TAG_FIXNUM_MASK
#define TAG_FIXNUM 0x1
#define TAG_FIXNUM_SHIFT 0x1
#define TAG_FIXNUM_MASK 0x1
#undef TAG_SYMBOL
#undef TAG_SYMBOL_MASK
#define TAG_SYMBOL 0x6
#define TAG_SYMBOL_MASK 0x7
#define REFERENCE_P(v) ((v) && (((VALUE)(v) & TAG_REF_MASK) == TAG_REF))
#define IMMEDIATE_P(x) (!REFERENCE_P(x))
#define FIXNUM_P(v) (((VALUE)(v) & TAG_FIXNUM_MASK) == TAG_FIXNUM)
#define SYMBOL_P(v) (((VALUE)(v) & TAG_SYMBOL_MASK) == TAG_SYMBOL)
#define CAPI_TAG_FIXNUM(v) ((VALUE)(((VALUE)(v) << TAG_FIXNUM_SHIFT) | TAG_FIXNUM))
#define FIXNUM_WIDTH ((8 * sizeof(native_int)) - TAG_FIXNUM_SHIFT - 1)
#define FIXNUM_MAX (((native_int)1 << FIXNUM_WIDTH) - 1)
#define FIXNUM_MIN (-(FIXNUM_MAX))
#endif
EOO
end
FileUtils.cp mri_oop_h, "vm/capi/19/include/ruby/mri_oop.h"
# Write a require file depending on which Readline library we use.
File.open "lib/readline.rb", "wb" do |f|
if @rb_readline
f.puts "require 'rb-readline/readline'"
else
f.puts "require 'c-readline'"
end
end
end
def print_debug
puts "\nUsing the following configuration to build"
puts "------------------------------------------"
cat("config.rb")
puts "\nSetting the following defines for the VM"
puts "----------------------------------------"
cat("vm/gen/config.h")
end
def cat(file)
puts IO.read(relative_file(file))
end
def relative_file(name)
File.expand_path("../#{name}", __FILE__)
end
def check_force_clean
if Rubinius::BUILD_CONFIG[:config_version] != @config_version
@log.write "\nDetected old configuration settings, forcing a clean build"
system("#{build_ruby} -S #{@rake} clean")
end
end
def run
unless which_ruby == :ruby or which_ruby == :rbx
failure "Sorry, building Rubinius requires MRI or Rubinius."
end
if File.exists? @config
load @config
verify_config = true
end
options
parse ARGV
if File.join(@bindir, @program_name) == build_ruby
@log.error "\nYou are attempting to build using the instance of Rubinius that you are building.\n\n"
@log.error "To resolve this issue:"
if ENV['PATH'] =~ /#{@bindir}/
@log.error " * Remove '#{@bindir}' from your PATH."
end
failure " * Use a Ruby executable other than '#{build_ruby}' to build."
end
process
write_config
check_force_clean if verify_config
print_debug if @verbose
if @llvm_source_build
files = prebuilt_files.map { |f| File.basename f, ".tar.bz2" }.join("\n ")
@log.write <<-EOM
------------------------------------------------------------------
Unable to find an existing binary build of LLVM for your platform.
Please notify the Rubinius team at the #rubinius channel on
irc.freenode.net and provide the following system information:
prebuilts:
#{files}
------------------------------------------------------------------
EOM
end
if @install
@log.write "\nConfigured. Run 'rake install' to install Rubinius."
else
@log.write <<-EOM
Configured. Run 'rake' to build and run VM tests and rubyspecs.
After building, you may add '#{@bindir}' to your PATH or run commands directly from that directory. Available commands are:
#{@program_name}, ruby, rake, gem, irb, rdoc, ri
EOM
end
end
# Handles user output and logging while running configure.
class Logger
attr_reader :path
# Creates an instance of Logger writing to +file+.
def initialize(file, init=true)
@path = File.expand_path("../#{file}", __FILE__)
if init
File.open(@path, "wb") { }
log "Configuring Rubinius..."
end
end
# Copies the contents of +other+ into this logger's file.
def replace(other)
output do |f|
f.puts File.read(other)
end
end
# Writes +message+ to the logging file but not to the screen.
def log(message, error=false)
output do |f|
stamp = "#{timestamp}#{'*** ERROR' if error}"
if multiline?(message)
f.puts "#{stamp} ---"
f.puts message
f.puts "---"
else
f.puts "#{stamp} #{message}"
end
end
end
# Writes a normal message to STDOUT and logs to the file.
def write(message)
log message
STDOUT.puts message
end
# Writes a normal message to STDOUT with #print and logs to file.
def print(message)
log message
STDOUT.print message
end
# Writes an error message to STDERR and logs to the file with
# error decorations. This should only be used for errors that
# affect configure itself.
def error(message)
log message, true
STDERR.puts message
end
# Yields an IO for writing log messages.
def output
File.open @path, "a" do |f|
yield f
end
end
# Returns a formatted times suitable for logging.
def timestamp
Time.now.strftime "[%Y-%m-%d %H:%M:%S]"
end
# Returns true if the message has more than one line.
def multiline?(message)
message.index("\n") != nil
end
end
end
STDOUT.sync = true
Configure.new(root).run
Jump to Line
Something went wrong with that request. Please try again.