3 require './rakelib/configure'
4 require './rakelib/release'
5 require './rakelib/build_signature'
19 root = File.expand_path File.dirname(__FILE__)
21 require File.join(root, "core", "options")
25 # Default settings only. All code that may depend on user-selected options
26 # must run after options are processed.
28 @log = Logger.new "configure.log"
30 @command_line = ARGV.dup
31 @log.log "Command line: #{@command_line.join(" ").inspect}"
35 @config = File.join(root, "build/config/config.rb")
38 @host = `sh -c ./build/bin/config.guess`.chomp
46 @little_endian = false
48 @gc_stack_check = false
49 @log_concurrent_update = false
50 @raise_concurrent_update = false
64 @llvm_system_name = get_system_name
67 @llvm_api_version = nil
69 @llvm_shared_objs = nil
108 @capi_includedir = "#{@sourcedir}/machine/include/capi"
110 @bootstrap_gems_dir = nil
112 @vm_release_h = File.join(root, "/machine/release.h")
114 @preserve_prefix = false
116 @program_name = "rbx"
117 @bin_links = ["rbx", "ruby", "rake", "gem", "irb", "rdoc", "ri", "erb"]
118 @use_bin_links = true
120 # List of all gems to pre-install.
121 @gems_list = File.join(root, "gems_list.txt")
122 @gem_files = File.readlines(@gems_list).map { |x| x.chomp }
123 @gem_names = @gem_files.map { |x| /(.*)-\d+\.\d+(\.\d+)?\.gem$/.match(x)[1] }
126 "bundler-1.16.1.gem",
127 "minitest-5.11.1.gem",
131 "rb-readline-0.5.5.gem",
132 "test-unit-3.2.7.gem",
135 # Default cache directory, can be overwritten by the user.
136 @gems_cache = File.expand_path "../build/libraries/cache", __FILE__
138 # Vendored library settings
139 @build_libdir = File.join(root, "/build/libraries")
141 # Ruby compatibility version
142 @ruby_version = "10.0"
143 @ruby_libversion = @ruby_version.split(/\./)[0..1].join.to_i
145 @build_bin = "#{@sourcedir}/build/bin"
148 @release_build = !in_git?
151 # Set up system commands to run in cmd.exe on Windows. Either Windows
152 # or MRI on Windows has issues with subprocesses where the invocation
153 # of the subprocess will return before the subprocess has finished.
154 # This manifests in configure when uncompressing LLVM source returns
155 # but attempting to move the directory fails sporadically with an access
156 # exception. Adding the, essentially no-op, 'sleep 0' resolves this.
158 old_system %[cmd.exe /C "#{cmd} && sleep 0"]
161 def msys_backquote(cmd)
162 old_backquote %[cmd.exe /C "#{cmd}"]
166 File.expand_path(path)
169 def expand_install_dir(dir)
171 if !@preserve_prefix and File.directory?(dir) and dir !~ /(rubinius|rbx).*\/?$/
173 dir += "/rubinius/#{@libversion}"
174 @log.write "The directory #{original} already exists, installing to #{dir}"
180 /([^-]+)-([^-]+)-(.*)/ =~ @host
181 @cpu, @vendor, @os = $1, $2, $3
183 # TODO: For better cross-compiling support, it may be necessary to
184 # use the feature facility to check for a define in the compiler.
185 @windows = (@host =~ /mingw|mswin/) != nil
186 @darwin = (@host =~ /darwin/) != nil
187 @bsd = (@host =~ /bsd/) != nil
188 @linux = (@host =~ /linux/) != nil
191 def set_system_commands
192 # Set up system commands to run in cmd.exe on Windows.
194 alias :old_system :system
195 alias :old_backquote :`
196 alias :system :msys_system
197 alias :` :msys_backquote
201 def set_filesystem_paths
202 @prefixdir = @prefixdir ? expand_install_dir(@prefixdir) : @sourcedir
205 dir = expand_install_dir @appdir
207 @libdir = dir + "/library"
208 @runtimedir = dir + "/runtime"
209 @codedbdir = dir + "/codedb"
210 @coredir = dir + "/core"
211 @sitedir = dir + "/site"
212 @archdir = dir + "/site/#{@cpu}-#{@os}"
213 @encdir = dir + "/site/#{@cpu}-#{@os}/encoding/converter"
214 @vendordir = dir + "/vendor"
217 @bindir = @prefixdir + "/bin" unless @bindir
218 @libdir = @prefixdir + "/library" unless @libdir
219 @runtimedir = @prefixdir + "/runtime" unless @runtimedir
220 @codedbdir = @prefixdir + "/codedb" unless @codedbdir
221 @coredir = @prefixdir + "/core" unless @coredir
222 @sitedir = @prefixdir + "/site" unless @sitedir
223 @archdir = @prefixdir + "/site/#{@cpu}-#{@os}" unless @archdir
224 @encdir = @prefixdir + "/site/#{@cpu}-#{@os}/encoding/converter" unless @encdir
225 @vendordir = @prefixdir + "/vendor" unless @vendordir
226 @mandir = @prefixdir + "/man" unless @mandir
227 @gemsdir = @prefixdir + "/gems" unless @gemsdir
228 @includedir = @prefixdir + "/machine/include/capi" unless @includedir
231 dirs = [@bindir, @libdir, @runtimedir, @codedbdir, @coredir, @sitedir,
232 @archdir, @vendordir, @mandir, @gemsdir, @includedir, @encdir]
234 parts = dirs.map { |d| d.split "/" }
237 total = parts[0].size
242 break unless parts.all? { |p| p[i] == part }
247 @prefixdir = prefix.join "/"
248 size = @prefixdir.size
250 dirs.each { |d| d.replace d[size..-1] }
252 @scriptdir = "#{@sourcedir}/build/scripts"
254 @builddir = "#{@sourcedir}/build/rubinius" unless @builddir
256 stat = File.stat @builddir if File.exist? @builddir
258 if stat and stat.owned? and not @builddir.empty? and @builddir != "/"
259 FileUtils.rm_r @builddir
263 @builddir = File.expand_path "#{@builddir}/#{@prefixdir}"
266 FileUtils.mkdir_p @builddir
268 @bootstrap_gems_dir ||= "#{@sourcedir}/build/libraries/gems"
269 @codetoolsdir = "#{@sourcedir}/build/codetools"
270 @stdlibdir = "#{@sourcedir}/build/stdlib"
274 @include_dirs << "#{dir}/include"
275 @lib_dirs << "#{dir}/lib" << "#{dir}/lib64"
279 @options = Rubinius::Options.new "Usage: configure [options]", 30
283 o.doc " Configure settings"
285 o.on "--log-file", "NAME", "Write log to file NAME" do |name|
287 @log = Logger.new name, false
291 o.on "--make", "NAME", "Use NAME as 'make' during build" do |name|
295 o.on "--rake", "NAME", "Use NAME as 'rake' during build" do |name|
299 o.on "--tar", "NAME", "Use NAME as 'tar'" do |name|
303 o.on "--bzip", "NAME", "Use NAME as 'bzip'" do |name|
307 o.on "--perl", "NAME", "Use NAME as 'perl' during build" do |name|
311 o.on "--gem", "NAME", "Use NAME as 'gem' during build" do |name|
315 o.on "--debug-build", "Disable C++ optimizations and retain debugging symbols" do
319 o.on "--sanitize", "SANITIZER", "Enable the Clang sanitizer: 'memory', 'address', 'undefined'" do |sanitizer|
320 if ["address", "memory", "undefined"].include?(sanitizer)
322 (@system_cxxflags ||= "") << " -fsanitize=#{sanitizer} -fno-omit-frame-pointer -fno-optimize-sibling-calls "
323 @system_cxxflags << " -fsanitize-address-use-after-scope " if sanitizer == "address"
324 @system_cxxflags << " -fsanitize-memory-track-origins " if sanitizer == "memory"
326 (@system_ldflags ||= "") << " -g -fsanitize=#{sanitizer} "
330 o.on "--release-build", "Build from local files instead of accessing the network" do
331 @release_build = true
334 o.on "--no-release-build", "Build from the network instead of local files" do
335 @release_build = false
338 o.on "--gc-stack-check", "Emit stack trace for all threads on pause for GC" do
339 @gc_stack_check = true
342 o.on "--log-concurrent-update", "Log when T2 updates an object created by T1" do
343 @log_concurrent_update = true
346 o.on "--raise-concurrent-update", "Raise a RuntimeError when T2 updates an object created by T1" do
347 @raise_concurrent_update = true
350 o.doc "\n Compiler settings"
352 o.on "--cc", "COMPILER", "Compiler to use for C code (eg clang)" do |cc|
356 o.on "--cxx", "COMPILER", "Compiler to use for C++ code (eg clang++)" do |cxx|
360 o.doc "\n LLVM settings"
362 o.on "--system-name", "NAME", "Name of OS (eg fedora-8, ubuntu-10.04)" do |name|
363 @llvm_system_name = name
366 o.on "--llvm-path", "PATH", "File system path to the directory containing LLVM" do |dir|
370 o.on "--llvm-config", "PROGRAM", "File system path to the llvm-config program" do |program|
371 @llvm_configure = program
374 o.on "--llvm-shared", "Link to shared LLVM library" do
378 o.doc "\n System settings"
380 o.on "--with-include-dir", "DIR", "Add DIR to the default include search paths" do |dir|
381 dir.split(File::PATH_SEPARATOR).each do |d|
386 o.on "--with-lib-dir", "DIR", "Add DIR to the default library search paths" do |dir|
387 dir.split(File::PATH_SEPARATOR).each do |d|
392 o.on "--with-opt-dir", "DIR", "Add DIR/include and DIR/lib to include and library search paths" do |dir|
393 dir.split(File::PATH_SEPARATOR).each do |d|
398 o.on "--libc", "NAME", "Use NAME as the libc for FFI" do |name|
402 o.on "--host", "HOST", "Override guessed platform with HOST specification" do |host|
403 @log.write "------------------------------------------------------"
404 @log.write "\nChanging the platform specification can cause Rubinius"
405 @log.write "to malfunction. The current platform specification is:"
406 @log.write "\n#{@host}"
407 @log.write "\n------------------------------------------------------"
412 o.doc "\n Program names"
414 o.on "--program-name", "NAME", "Build Rubinius executable as NAME" do |name|
418 o.on "--bin-link", "NAME", "Create NAME as binary symlink to program name" do |name|
422 o.on "--no-bin-links", "Do not create any symlinks to program name" do
423 @use_bin_links = false
426 o.doc "\n File system paths for installing Rubinius"
428 o.on "-P", "--prefix", "PATH", "Install Rubinius in subdirectories of PATH" do |dir|
433 o.on "-B", "--bindir", "PATH", "Install Rubinius executable in PATH" do |dir|
437 o.on "-I", "--includedir", "PATH", "Install Rubinius C-API include files in PATH" do |dir|
438 @includedir = expand dir
441 o.on "-A", "--appdir", "PATH", "Install Ruby runtime and libraries in PATH" do |dir|
445 o.on "-L", "--libdir", "PATH", "Install Rubinius shared library in PATH" do |dir|
449 o.on "-M", "--mandir", "PATH", "Install man pages in PATH" do |dir|
453 o.on "-G", "--gemsdir", "PATH", "Install gems in PATH" do |dir|
454 @gemsdir = expand dir
457 o.on "--gems-cache", "PATH", "Cache Gems in PATH during compilation" do |dir|
458 @gems_cache = expand dir
461 o.on "--sitedir", "PATH", "Install site-specific Ruby code in PATH" do |dir|
462 @sitedir = expand dir
465 o.on "--archdir", "PATH", "Install arch-specific native extensions in PATH" do |dir|
466 @archdir = expand dir
469 o.on "--vendordir", "PATH", "Install vendor-specific Ruby code in PATH" do |dir|
470 @vendordir = expand dir
473 o.on "--preserve-prefix", "Use the configure prefix for staging Rubinius to install" do
474 @preserve_prefix = true
477 o.on "--stagingdir", "PATH", "Use PATH to build and prepare all files for install" do |dir|
478 @builddir = expand dir
481 o.doc "\n Optional features"
483 feature "execinfo", true
484 feature "vendor-zlib", false
485 feature "vendor-libsodium", true
486 feature "alloc-tracking", false
487 feature "dtrace", false
488 feature "rpath", false
492 o.on "--show", "Print the current configuration and exit" do
497 o.on "-V", "--verbose", "Print additional info" do
507 def feature(name, default_value=true)
508 @features[name] = ConfigurationToggle.new default_value
510 @options.on "--with-#{name}", "Enable #{name}" do
511 @features[name].configured = true
514 @options.on "--without-#{name}", "Disable #{name}" do
515 @features[name].configured = false
523 def md5_checksum(md5_path, full_path)
524 return Digest::MD5.file(full_path).hexdigest == File.read(md5_path).strip.split(" ").first
527 def download(url, full_path, follows=0)
529 dir = File.dirname full_path
530 Dir.mkdir dir unless File.exist? dir
532 uri = url.kind_of?(URI) ? url : URI(url)
535 protocol, userinfo, p_host, p_port = URI::split(ENV['http_proxy'])
536 p_user, p_pass = userinfo.split(/:/) if userinfo
537 http = Net::HTTP.new(uri.host, uri.port, p_host, p_port, p_user, p_pass)
539 http = Net::HTTP.new(uri.host, uri.port)
541 http.use_ssl = true if uri.scheme == 'https'
542 request = Net::HTTP::Get.new(uri.request_uri)
544 http.request(request) do |res|
546 when Net::HTTPNotFound
547 @log.write " #{url} not found."
549 when Net::HTTPMovedPermanently,
552 Net::HTTPTemporaryRedirect
554 @log.write " ERROR: too many redirects: #{url}"
558 return download URI.parse(res['Location']), full_path, follows + 1
559 when Net::HTTPClientError
560 @log.write " ERROR: #{res.inspect}"
565 total = res.header['Content-Length'].to_i
567 @log.write " Downloading #{File.basename(full_path)}..."
568 File.open full_path, "wb" do |f|
569 res.read_body do |chunk|
572 print "\r [ %d%% (%d of %d) ]" % [(size * 100) / total, size, total]
578 File.unlink full_path if File.exist?(full_path)
580 rescue StandardError => e
581 File.unlink full_path if File.exist?(full_path)
582 @log.write " ERROR: #{e.message}"
590 @log.print " Checking for 'llvm-config': "
592 config = @llvm_configure
594 which = ENV['PATH'].split(":").find do |path|
595 File.exist? File.join(path, "llvm-config")
598 config = File.join(which, "llvm-config")
601 config = macports_llvm_config
603 out = brew "--prefix llvm"
604 config = "#{out}/bin/llvm-config" if $?.success?
610 config_cmd = llvm_config_cmd config
612 version = `#{config_cmd} --version`.strip
614 # Ruby 1.8 returns an empty string
615 failed = true if version.empty?
617 # Ruby 1.9 raises this error
622 parts = version.sub(/svn$/, "").split(".").map { |i| i.to_i }
623 api_version = ("%d%02d" % parts[0..1]).to_i
625 @log.write "only LLVM 3.6+ is supported"
627 @log.write "found! (version #{version} - api: #{api_version})"
629 @llvm_configure = config_cmd
630 @llvm_version = version
631 @llvm_api_version = api_version
642 @log.write "executing #{config_cmd.inspect} failed"
645 @log.write "not found"
648 failure "ABORT: unable to set up LLVM"
651 def setup_llvm_shared
652 @log.print " Checking for LLVM shared libs: "
655 #include <llvm/IR/LLVMContext.h>
656 using namespace llvm;
657 int main() { LLVMContext &Context = getGlobalContext(); }
660 common_args = "`#{@llvm_configure} --cppflags` #{@llvm_cxxflags} #{@llvm_ldflags}".strip.split(/\s+/)
662 "libLLVM-#{@llvm_version}" => ["-lLLVM-#{@llvm_version}"],
663 "#{@llvm_configure} --libs" => `#{@llvm_configure} --libs`.strip.split(/\s+/)
666 shared_configs.each do |desc, objs|
667 status = check_program(false, *(common_args + objs)) do |f|
673 @log.write "found! (using #{desc})"
674 @llvm_shared_objs = objs
679 @log.write "not found"
686 # Starting with LLVM 3.5 the --system-libs option is required in order to
687 # link against libraries such as zlib. Prior to 3.5 this was handled by
689 flags << ' --system-libs'
691 # Generate the actual flags. For whatever reason llvm-config also includes
692 # newlines in the output, so lets get rid of those while we're at it.
693 @llvm_ldflags = `#{@llvm_configure} #{flags}`.strip.gsub("\n", ' ')
700 def default_link_libs
702 unless @host =~ /haiku/
708 def failure(message=nil)
709 @log.error message if message
711 STDERR.puts "\nRunning 'configure' failed. Please check configure.log for more details."
715 def supported_compiler(name)
717 Unable to find #{name} compiler. Support for compilers other than #{name}
718 compiler was deprecated 1 Jun 2016 and has been removed. If your platform does
719 not support #{name} compiler, please email contact@rubinius.com
724 return 'clang' if `clang --version > /dev/null 2>&1` && $?.success?
725 supported_compiler "clang C"
729 return 'clang++' if `clang++ --version > /dev/null 2>&1` && $?.success?
730 supported_compiler "clang++ C++"
734 @cc ||= ENV['CC'] || default_cc
735 @cxx ||= ENV['CXX'] || default_cxx
737 check_tool_version @cc, '-dumpversion', [4, 1]
738 check_tool_version @cxx, '-dumpversion', [4, 1]
740 supported_compiler "clang C" unless @cc =~ /clang|ccc-analyzer/
741 supported_compiler "clang++ C++" unless @cxx =~ /clang\+\+|c\+\+\-analyzer/
743 if File.exist? @build_bin
744 if !File.directory? @build_bin
745 fail "#{@build_bin} already exists and is not a directory"
748 FileUtils.mkdir_p @build_bin
752 cc = "#{@build_bin}/cc"
753 File.symlink `which #{@cc}`.chomp, cc unless File.exist? cc
757 cxx = "#{@build_bin}/c++"
758 File.symlink `which #{@cxx}`.chomp, cxx unless File.exist? cxx
761 @make ||= ENV['MAKE'] || 'make'
762 @rake ||= ENV['RAKE'] || 'rake'
763 @tar ||= ENV['TAR'] || (@windows ? 'bsdtar' : 'tar')
764 @bzip ||= ENV['BZIP'] || 'bzip2'
765 @perl ||= ENV['PERL'] || 'perl'
766 @gem ||= ENV['GEM'] || 'gem'
768 @gcc_major = `#{@cc} -dumpversion`.strip.split(".")[0,2].join(".")
769 if @host == "i686-pc-linux-gnu" || @host == "x86_64-unknown-linux-gnu"
770 @llvm_generic_prebuilt = "llvm-#{@llvm_version}-#{@host}-#{@gcc_major}.tar.bz2"
772 @llvm_generic_prebuilt = "llvm-#{@llvm_version}-#{@host}.tar.bz2"
775 @system_cflags ||= ""
776 (@system_cxxflags ||= "") << "-std=c++14 "
777 @system_cppflags ||= ""
778 @system_incflags ||= ""
779 @system_ldflags ||= ""
781 @user_cflags = ENV['CFLAGS']
782 @user_cxxflags = ENV['CXXFLAGS']
783 @user_cppflags = ENV['CPPFLAGS']
784 @user_incflags = ENV['INCFLAGS']
785 @user_ldflags = ENV['LDFLAGS']
791 @ldsharedxx = "#{@cxx} -shared"
792 @ldshared = "#{@cc} -shared"
794 @include_dirs.each do |d|
795 @system_incflags << "-I#{d} "
797 @lib_dirs.each do |d|
798 @system_ldflags << "-L#{d} "
802 when /mswin/i, /mingw/i, /bccwin32/i
803 # TODO: discovery helpers
804 #check_heads(%w[windows.h winsock.h], true)
805 #check_libs(%w[kernel32 rpcrt4 gdi32], true)
807 unless RUBY_PLATFORM =~ /mingw/
808 @system_cflags << "-EHs -GR"
810 @system_ldflags << "-lws2_32"
811 @features["rpath"].configured = false
813 # GNU CHAIN only supported
814 @ldsharedxx = "#{@cxx} -shared -G -fPIC -lstdc++"
815 @ldshared = "#{@cc} -shared -G -fPIC"
816 @system_cflags << "-fPIC -Wno-strict-aliasing"
817 @system_ldflags << "-lsocket -lnsl -fPIC"
818 @features["rpath"].configured = false
821 @ldsharedxx = "#{@cxx} -shared -fPIC"
822 @ldshared = "#{@cc} -shared -fPIC"
823 @system_cflags << "-fPIC"
824 @system_ldflags << "-lcrypt -pthread -rdynamic"
827 # OpenBSD branch contributed by Guillaume Sellier.
829 # on Unix we need a g++ link, not gcc. On OpenBSD, linking against
830 # libstdc++ have to be explicitly done for shared libs
831 @ldsharedxx = "#{@cxx} -shared -lstdc++ -fPIC"
832 @ldshared = "#{@cc} -shared -fPIC"
833 @system_cflags << "-fPIC"
834 @system_ldflags << "-pthread -rdynamic -Wl,--export-dynamic"
837 @ldsharedxx = "#{@cxx} -shared -lstdc++ -fPIC"
838 @ldshared = "#{@cc} -shared -fPIC"
839 @system_cflags << "-fPIC"
840 @system_ldflags << "-lcrypt -pthread -rdynamic -Wl,--export-dynamic"
843 # on Unix we need a g++ link, not gcc.
844 # Ff line contributed by Daniel Harple.
845 @ldsharedxx = "#{@cxx} -bundle -undefined suppress -flat_namespace"
846 @ldshared = "#{@cc} -bundle -undefined suppress -flat_namespace"
847 @system_cflags << "-fPIC -D_DARWIN_USE_64_BIT_INODE"
848 @features["rpath"].configured = false
850 @system_cflags << "-fPIC"
851 @system_ldflags << "-ldl -lnetwork"
852 @features["rpath"].configured = false
854 @ldsharedxx = "#{@cxx} -shared -Wl,-G -Wl,-brtl"
855 @ldshared = "#{@cc} -shared -Wl,-G -Wl,-brtl"
856 @features["rpath"].configured = false
858 @system_cflags << "-fPIC"
859 @system_ldflags << "-Wl,--export-dynamic -lrt -lcrypt -ldl -lpthread"
861 # on Unix we need a g++ link, not gcc.
862 @system_cflags << "-fPIC"
863 @system_ldflags << "-ldl -lpthread"
866 if @features["rpath"].value
867 @lib_dirs.each do |d|
868 @system_ldflags << " -Wl,-rpath=#{d}"
873 def check_program(run=true, *arguments)
875 basename = "rbx-configure-test"
876 source = basename + ".cpp"
877 File.open source, "wb" do |f|
881 File.open source, "rb" do |f|
885 libs = default_link_libs.map { |l| "-l#{l}" }.join(" ")
886 args = arguments.join(" ")
888 cmd = "#{@cxx} #{@user_cppflags} #{@user_cflags} #{@user_cxxflags} #{@user_incflags} #{@user_ldflags} -o #{basename} #{source} #{@system_cppflags} #{@system_cflags} #{@system_cxxflags} #{@system_incflags} #{@system_ldflags} #{libs} #{args} >>#{@log.path} 2>&1"
891 return $?.exitstatus unless run
893 unless $?.exitstatus == 0
894 @log.log msg = "Compiling configure test program failed."
895 raise RuntimeError, msg
898 system expand("./#{basename}")
901 @log.log "Error in check_program: #{e.class} #{e.message}\n #{e.backtrace.join("\n ")}"
904 FileUtils.rm_r(Dir["#{basename}*"])
908 def write_have_defines(f)
910 @defines.each { |d| f.puts "#define #{d.ljust(20)} 1" }
913 def write_have_sizeof_defines(f)
915 @sizeof.keys.sort.each { |k| f.puts "#define HAVE_#{k}".ljust(30) + "1" }
918 def write_sizeof_defines(f)
920 @sizeof.keys.sort.each { |k| f.puts "#define SIZEOF_#{k}".ljust(30) + @sizeof[k].to_s }
923 def sizeof_typename(type)
925 name = "#{type[0...-$1.size]}#{"p" * $1.size}"
929 name.gsub(/\W/, "_").upcase
933 @sizeof[sizeof_typename(type)] or failure("Unknown type: '#{type}'.")
937 @log.print "Checking sizeof(intptr_t) == sizeof(int64_t): "
939 status = check_program do |f|
943 int main(int argc, char* argv[]) {
944 return sizeof(intptr_t) == sizeof(int64_t);
955 failure "\nRubinius requires that sizeof(intptr_t) == sizeof(int64_t)"
959 def detect_sizeof(type, includes=[])
960 @log.print "Checking sizeof(#{type}): "
962 size = check_program do |f|
963 src = includes.map { |include| "#include <#{include}>\n" }.join
968 int main() { return sizeof(#{type}); }
974 @sizeof[sizeof_typename(type)] = size
976 @log.write "#{size} bytes"
980 @log.print "Checking platform endianness: "
982 status = check_program do |f|
983 src = "int main() { int one = 1; return (*((char*)&one)) == 1 ? 0 : 1; }"
988 @little_endian = (status == 0)
989 @log.write @little_endian ? "little endian" : "big endian"
993 @log.print "Checking for tr1: "
995 status = check_program(false) do |f|
997 #include <tr1/unordered_map>
999 typedef std::tr1::unordered_map<int, void*> X;
1001 int main() { X x; return 0; }
1007 @tr1 = (status == 0)
1008 @log.write @tr1 ? "found" : "not found"
1012 @log.print "Checking for tr1/hash definition: "
1014 status = check_program(false) do |f|
1017 #include <tr1/unordered_map>
1019 typedef std::tr1::unordered_map<uint64_t, void*> X;
1021 int main() { X x; return 0; }
1027 @tr1_hash = (status == 0)
1028 @log.write @tr1_hash ? "found" : "not found"
1032 print "Checking for x86_64: "
1034 status = check_program do |f|
1037 #if defined(__x86_64) || defined(__x86_64__)
1048 @x86_64 = (status == 1)
1050 puts @x86_64 ? "yes" : "no"
1054 print "Checking for aarch64: "
1056 status = check_program do |f|
1059 #if defined(__ARM_ARCH_ISA_A64)
1070 @aarch64 = (status == 1)
1072 puts @aarch64 ? "yes" : "no"
1076 @log.print "Checking curses library: "
1082 int main() { return tgetnum(""); }
1085 ["-lcurses", "-lncurses", "-ltermcap"].each do |lib|
1086 status = check_program(false, lib) do |f|
1102 def detect_build_dirs
1103 ["/usr/local", "/opt/local", "/usr/pkg"].each do |dir|
1107 @include_dirs = @include_dirs.select {|p| File.directory? p }
1108 @lib_dirs = @lib_dirs.select {|p| File.directory? p }
1111 def has_struct_member(struct, member, includes = [])
1112 compile_check "struct #{struct} has member #{member}" do |src|
1113 includes.each do |i|
1114 src.puts "#include <#{i}>"
1117 src.puts "int main() { struct #{struct} st; st.#{member}; }"
1121 def has_global(name, includes=[])
1122 compile_check "global '#{name}'" do |src|
1123 includes.each do |i|
1124 src.puts "#include <#{i}>"
1126 src.puts "int main() { #{name}; }"
1130 def has_header(name)
1131 compile_check "header '#{name}'" do |src|
1132 # Some headers have an implicit dependency on stdio.h. For example,
1133 # readline/readline.h requires it but doesn't actually include it for
1134 # you. Because there could be an infinite amount of headers that require
1135 # stdio.h we'll just always include it.
1136 src.puts "#include <stdio.h>"
1138 src.puts "#include <#{name}>"
1139 src.puts "int main() {return 0;}"
1143 def has_function(name, includes=[], defines = [])
1144 compile_check "function '#{name}'", defines do |src|
1145 includes.each do |i|
1146 src.puts "#include <#{i}>"
1148 src.puts "int main() { void* ptr = (void *) &#{name}; }"
1152 def has_library(name, function, libraries, includes=[])
1153 @log.print "Checking for library: #{name}: "
1155 args = libraries.map { |l| "-l#{l}" }
1157 status = check_program(true, *args) do |src|
1158 includes.each do |i|
1159 src.puts "#include <#{i}>"
1161 src.puts "int main() { void* ptr = (void*)(&#{function}); return 0; }"
1164 success = status == 0
1165 @log.write(success ? "found!" : "not found!")
1170 @log.print "Checking for dtrace: "
1173 basename = "rbx-configure-dtrace-test"
1174 source = basename + ".d"
1175 output = basename + ".h"
1177 File.open source, "wb" do |f|
1178 f.write "provider conftest{ probe m__entry(const char*); };"
1181 cmd = "dtrace -h -o #{output} -s #{source}"
1185 @dtrace = $?.exitstatus == 0
1186 @dtrace_const = !!File.read(output).index("const") if @dtrace
1188 @log.write(@dtrace ? "yes" : "no")
1192 File.delete(*Dir["#{basename}*"])
1196 def compile_check(logpart, defines = [], &block)
1197 @log.print "Checking for #{logpart}: "
1199 source = StringIO.new
1201 file = Tempfile.new("rbx-test")
1204 string = source.read
1211 cmd = "#{@cxx} -S -o - -x c++ #{defines.join(" ")} #{@user_cppflags} #{@user_incflags} #{@user_cxxflags} #{@user_cflags} #{@user_ldflags} #{@system_cppflags} #{@system_incflags} #{@system_cxxflags} #{@system_cflags} #{@system_ldflags} #{file.path} >>#{@log.path} 2>&1"
1215 status = ($?.exitstatus == 0)
1218 @log.write(status ? "found!" : "not found")
1223 if @features["vendor-zlib"].value
1224 # Our vendored zlib uses long as the crc_table type
1225 # If we update vendored zlib in the future, we have to
1226 # review this and make sure we update it properly to
1227 # match the newer version which like will have uint32_t
1229 @include_dirs << "#{@build_libdir}/zlib"
1230 @lib_dirs << "#{@build_libdir}/zlib"
1233 if @features["vendor-libsodium"].value
1234 @include_dirs << "#{@build_libdir}/libsodium/src/libsodium/include"
1235 @lib_dirs << "#{@build_libdir}/libsodium/src/libsodium/.libs/"
1240 # Default on *BSD is no execinfo
1241 if @bsd and @features["execinfo"].configured.nil?
1242 @features["execinfo"].configured = false
1245 if @features["execinfo"].value and has_function("backtrace", ["execinfo.h"])
1246 @defines << "HAS_EXECINFO"
1249 if @features["alloc-tracking"].value
1250 @defines << "RBX_ALLOC_TRACKING"
1253 if @features["dtrace"].value and has_dtrace
1254 @defines << "HAVE_DTRACE"
1257 # Default on Windows is vendor-zlib
1258 if @windows and @features["vendor-zlib"].configured.nil?
1259 @features["vendor-zlib"].configured = true
1262 @defines << "HAVE_SPT_REUSEARGV" if @linux || @darwin || @bsd
1265 def detect_functions
1266 if has_function("clock_gettime", ["time.h"])
1267 @defines << "HAVE_CLOCK_GETTIME"
1270 if has_function("nl_langinfo", ["langinfo.h"])
1271 @defines << "HAVE_NL_LANGINFO"
1274 if has_function("setproctitle", ["sys/types.h", "unistd.h"])
1275 @defines << "HAVE_SETPROCTITLE"
1278 if has_function("posix_fadvise", ["fcntl.h"])
1279 @defines << "HAVE_POSIX_FADVISE"
1282 if has_function("strnlen", ["string.h"])
1283 @defines << "HAVE_STRNLEN"
1286 if has_function("kqueue", ["sys/types.h", "sys/event.h", "sys/time.h"])
1287 @defines << "HAVE_KQUEUE"
1290 if has_function("timerfd_create", ["sys/timerfd.h"])
1291 @defines << "HAVE_TIMERFD"
1294 if has_function("inotify_init", ["sys/inotify.h"])
1295 @defines << "HAVE_INOTIFY"
1298 if has_function("gettid", ["unistd.d", "sys/types.h"])
1299 @defines << "HAVE_GETTID"
1302 if has_struct_member("stat", "st_atim", ["sys/stat.h"])
1303 @defines << "HAVE_STRUCT_STAT_ST_ATIM"
1306 if has_struct_member("stat", "st_atimespec", ["sys/stat.h"])
1307 @defines << "HAVE_STRUCT_STAT_ST_ATIMESPEC"
1310 if has_struct_member("stat", "st_atimensec", ["sys/stat.h"])
1311 @defines << "HAVE_STRUCT_STAT_ST_ATIMENSEC"
1314 if has_struct_member("stat", "st_mtim", ["sys/stat.h"])
1315 @defines << "HAVE_STRUCT_STAT_ST_MTIM"
1318 if has_struct_member("stat", "st_mtimespec", ["sys/stat.h"])
1319 @defines << "HAVE_STRUCT_STAT_ST_MTIMESPEC"
1322 if has_struct_member("stat", "st_mtimensec", ["sys/stat.h"])
1323 @defines << "HAVE_STRUCT_STAT_ST_MTIMENSEC"
1326 if has_struct_member("stat", "st_ctim", ["sys/stat.h"])
1327 @defines << "HAVE_STRUCT_STAT_ST_CTIM"
1330 if has_struct_member("stat", "st_ctimespec", ["sys/stat.h"])
1331 @defines << "HAVE_STRUCT_STAT_ST_CTIMESPEC"
1334 if has_struct_member("stat", "st_ctimensec", ["sys/stat.h"])
1335 @defines << "HAVE_STRUCT_STAT_ST_CTIMENSEC"
1338 if has_struct_member("stat", "st_birthtimespec", ["sys/stat.h"])
1339 @defines << "HAVE_ST_BIRTHTIME"
1342 # glibc has useless lchmod() so we don't try to use lchmod() on linux
1343 if !@linux and has_function("lchmod", ["sys/stat.h", "unistd.h"])
1347 if has_function("lchown", ["sys/stat.h", "unistd.h"])
1351 if has_function("mkfifo", ["sys/stat.h", "sys/types.h"])
1356 def detect_structures
1357 if has_struct_member("tm", "tm_gmtoff", ["time.h"])
1358 @defines << "HAVE_TM_GMTOFF"
1361 if has_struct_member("tm", "tm_zone", ["time.h"])
1362 @defines << "HAVE_TM_ZONE"
1367 if has_global("timezone", ["time.h"])
1368 @defines << "HAVE_TIMEZONE"
1371 if has_global("tzname", ["time.h"])
1372 @defines << "HAVE_TZNAME"
1375 if has_global("daylight", ["time.h"])
1376 @defines << "HAVE_DAYLIGHT"
1381 unless @features["vendor-zlib"].value
1382 unless has_header("zlib.h")
1383 failure "zlib.h is required"
1387 unless @features["vendor-libsodium"].value
1388 unless has_header("sodium.h")
1389 failure "sodium.h is required"
1393 unless has_header("openssl/ssl.h")
1394 failure "openssl/ssl.h is required"
1397 if has_header("alloca.h")
1398 @defines << "HAVE_ALLOCA_H"
1401 if has_header("string.h")
1402 @defines << "HAVE_STRING_H"
1405 if has_header("sys/time.h")
1406 @defines << "HAVE_SYS_TIME_H"
1409 if has_header("sys/times.h")
1410 @defines << "HAVE_SYS_TIMES_H"
1413 if has_header("sys/types.h")
1414 @defines << "HAVE_SYS_TYPES_H"
1417 if has_header("unistd.h")
1418 @defines << "HAVE_UNISTD_H"
1421 if has_header("stdarg.h")
1422 @defines << "HAVE_STDARG_H"
1425 if has_header("sys/pstat.h")
1426 @defines << "HAVE_SYS_PSTAT_H"
1429 if has_header("valgrind/valgrind.h")
1430 @defines << "HAVE_VALGRIND_H"
1434 def strerror_r_returns_char_pointer
1435 status = check_program(false) do |src|
1436 src.puts "#include <string.h>"
1437 src.puts "int main() { char buf[1024]; static_cast<char*>(strerror_r(42, buf, 1024)); }"
1443 @log.print "Checking if function 'strerror_r' returns char*: "
1444 if strerror_r_returns_char_pointer
1445 @defines << "STRERROR_R_CHAR_P"
1453 @log.print "Checking -latomic: "
1455 saved_ldflags = @system_ldflags.dup
1456 @system_ldflags << " -latomic "
1459 status = check_program() do |src|
1464 int main(int argc, char* argv[]) {
1466 printf("%d", (int)i);
1479 @system_ldflags = saved_ldflags
1483 def warn_prefix(dir)
1484 delimiter = "-------------------------%s-----------------------"
1487 @log.write delimiter % " ERROR "
1488 @log.write "The specified prefix '#{dir}' is a regular file."
1489 @log.write "Remove the file or specify a different prefix."
1490 @log.write delimiter % "-------"
1492 elsif File.directory? dir
1493 @log.write delimiter % " WARNING "
1494 @log.write "The specified prefix '#{dir}' already exists."
1495 @log.write "Installing Rubinius into an existing directory may"
1496 @log.write "overwrite existing unrelated files or cause conflicts"
1497 @log.write "between different versions of Rubinius files."
1498 @log.write delimiter % "---------"
1515 detect_sizeof("short")
1516 detect_sizeof("int")
1517 detect_sizeof("void*")
1518 detect_sizeof("intptr_t")
1519 detect_sizeof("uintptr_t")
1520 detect_sizeof("size_t")
1521 detect_sizeof("long")
1522 detect_sizeof("long long")
1523 detect_sizeof("float")
1524 detect_sizeof("double")
1525 detect_sizeof("off_t", ["unistd.h"])
1526 detect_sizeof("time_t", ["time.h"])
1545 # Checks whether the given config file is a Perl script by checking its first
1546 # line for a Perl hashbang.
1547 def llvm_config_cmd(config)
1549 File.open(config, "r") do |f|
1550 first_line = f.readline
1551 if first_line =~ /^#! ?\/usr(\/local)?\/bin\/(env )?perl/
1552 "#{@perl} #{config}"
1557 rescue Errno::ENOENT, ArgumentError
1558 # The file doesn't exist (ENOENT) or it's a binary file (ArgumentError).
1564 return unless @os =~ /linux/
1565 return unless File.exist? "/etc/issue"
1567 data = IO.readlines("/etc/issue").first
1568 data =~ /([^ ]+)[^\d\.]*([\d\.]*)/
1573 if name == "debian" and File.exist? "/etc/debian_version"
1574 version = IO.read("/etc/debian_version").split.first.gsub(/\W/, "-")
1577 return "#{name}-#{version}"
1580 def check_tool_version(tool_name, opts, version, regexp=/(?=\d)(\d+).(\d+).?(\d+)?/)
1581 @log.print "Checking #{tool_name}:"
1583 output = `#{tool_name} #{opts}`
1585 if $?.exitstatus == 0
1586 v = output.scan(regexp)[0].map { |x| x.to_i }
1587 unless (v <=> version) >= 0
1588 failure " Expected #{tool_name} version >= #{version.join('.')}, found #{v.join('.')}"
1592 failure "#{tool_name} not found."
1596 def detect_libc_name
1599 @log.print "Checking for libc version: "
1603 @libc = "msvcrt.dll"
1605 @libc = "libc.dylib"
1608 exe = ENV["SHELL"] || "/bin/sh"
1609 ldd_output = `ldd #{exe}`
1611 @libc = ldd_output[/libc\.so\.[0-9]+/]
1613 # Don't abort if the command is not found
1616 unless $?.success? and @libc
1617 failure "libc not found. Use the --libc configure option."
1621 @log.write "#{@libc} found!"
1624 def write_configure_files
1625 @log.write "\nWriting configuration files..."
1627 @bin_links.delete @program_name
1630 :config_file => @config,
1631 :command_line => @command_line,
1632 :build_make => @make,
1633 :build_rake => @rake,
1634 :build_perl => @perl,
1635 :llvm_path => @llvm_path,
1636 :llvm_system_name => @llvm_system_name,
1637 :llvm_configure => @llvm_configure,
1638 :llvm_version => @llvm_version,
1639 :llvm_api_version => @llvm_api_version,
1640 :llvm_shared => @llvm_shared,
1641 :llvm_shared_objs => @llvm_shared_objs,
1642 :llvm_cxxflags => @llvm_cxxflags,
1643 :llvm_ldflags => @llvm_ldflags,
1652 :ldshared => @ldshared,
1653 :ldsharedxx => @ldsharedxx,
1654 :gcc_major => @gcc_major,
1655 :user_cflags => "#{@user_cflags}",
1656 :user_cxxflags => "#{@user_cxxflags}",
1657 :user_cppflags => "#{@user_cppflags}",
1658 :user_incflags => "#{@user_incflags}",
1659 :user_ldflags => "#{@user_ldflags}",
1660 :system_cflags => "#{@system_cflags}",
1661 :system_cxxflags => "#{@system_cxxflags}",
1662 :system_cppflags => "#{@system_cppflags}",
1663 :system_incflags => "#{@system_incflags}",
1664 :system_ldflags => "#{@system_ldflags}",
1665 :include_dirs => @include_dirs,
1666 :lib_dirs => @lib_dirs,
1667 :defines => @defines,
1673 :little_endian => @little_endian,
1674 :sizeof_short => sizeof("short"),
1675 :sizeof_int => sizeof("int"),
1676 :sizeof_void_ptr => sizeof("void*"),
1677 :sizeof_intptr_t => sizeof("intptr_t"),
1678 :sizeof_uintptr_t => sizeof("uintptr_t"),
1679 :sizeof_size_t => sizeof("size_t"),
1680 :sizeof_long => sizeof("long"),
1681 :sizeof_long_long => sizeof("long long"),
1682 :sizeof_float => sizeof("float"),
1683 :sizeof_double => sizeof("double"),
1684 :sizeof_off_t => sizeof("off_t"),
1685 :sizeof_time_t => sizeof("time_t"),
1687 :aarch64 => @aarch64,
1689 :dtrace_const => @dtrace_const,
1690 :debug_build => @debug_build,
1691 :sourcedir => @sourcedir,
1692 :builddir => @builddir,
1693 :scriptdir => @scriptdir,
1694 :bootstrap_gems_dir => @bootstrap_gems_dir,
1695 :capi_includedir => @capi_includedir,
1696 :build_libdir => @build_libdir,
1697 :build_exe => "#{@builddir}#{@bindir}/#{@program_name}",
1698 :build_bin => @build_bin,
1699 :prefixdir => @prefixdir,
1703 :runtimedir => @runtimedir,
1704 :codedbdir => @codedbdir,
1705 :codetoolsdir => @codetoolsdir,
1706 :stdlibdir => @stdlibdir,
1707 :coredir => @coredir,
1708 :sitedir => @sitedir,
1709 :archdir => @archdir,
1710 :vendordir => @vendordir,
1711 :includedir => @includedir,
1713 :gemsdir => @gemsdir,
1714 :gems_cache => @gems_cache,
1715 :gems_list => @gems_list,
1716 :gem_files => @gem_files,
1717 :installed_gems => @installed_gems,
1718 :program_name => @program_name,
1719 :bin_links => @bin_links,
1720 :use_bin_links => @use_bin_links,
1721 :rpath => @features["rpath"].value,
1722 :windows => @windows,
1726 :vendor_zlib => @features["vendor-zlib"].value,
1727 :vendor_libsodium => @features["vendor-libsodium"].value,
1728 :vm_release_h => @vm_release_h,
1729 :ruby_version => @ruby_version,
1730 :ruby_libversion => @ruby_libversion,
1733 write_config_rb @config, config_settings
1735 FileUtils.cp @config, "#{@sourcedir}/core/build_config.rb"
1737 # Write the config file used to build the C++ VM.
1738 Dir.mkdir "machine/gen" unless File.directory? "machine/gen"
1740 vm_paths_h = "machine/paths.h"
1741 File.open vm_paths_h, "wb" do |f|
1746 #define RBX_PREFIX_PATH "#{@prefixdir}"
1747 #define RBX_BIN_PATH "#{@bindir}"
1748 #define RBX_GEMS_PATH "#{@gemsdir}"
1749 #define RBX_RUNTIME_PATH "#{@runtimedir}"
1750 #define RBX_CODEDB_PATH "#{@codedbdir}"
1751 #define RBX_KERNEL_PATH "#{@coredir}"
1752 #define RBX_CORE_PATH "#{@coredir}"
1753 #define RBX_LIB_PATH "#{@libdir}"
1754 #define RBX_ENC_PATH "#{@encdir}"
1755 #define RBX_HDR_PATH "#{@includedir}"
1756 #define RBX_SITE_PATH "#{@sitedir}"
1757 #define RBX_ARCH_PATH "#{@archdir}"
1758 #define RBX_VENDOR_PATH "#{@vendordir}"
1764 vm_config_h = "machine/config.h"
1765 File.open vm_config_h, "wb" do |f|
1770 #define RBX_PROGRAM_NAME "#{@program_name}"
1771 #define RBX_HOST "#{@host}"
1772 #define RBX_CPU "#{@cpu}"
1773 #define RBX_VENDOR "#{@vendor}"
1774 #define RBX_OS "#{@os}"
1775 #define RBX_RUBY_LIB_VERSION #{@ruby_libversion}
1776 #define RBX_LDSHARED "#{@ldshared}"
1777 #define RBX_LDSHAREDXX "#{@ldsharedxx}"
1778 #define RBX_SIZEOF_LONG #{sizeof("long")}
1779 #define RBX_LLVM_API_VER #{@llvm_api_version}
1780 #define RBX_LIBC "#{@libc}"
1781 #define RBX_HAVE_LCHMOD #{@have_lchmod}
1782 #define RBX_HAVE_LCHOWN #{@have_lchown}
1783 #define RBX_HAVE_MKFIFO #{@have_mkfifo}
1784 #define RBX_DEBUG_BUILD #{@debug_build.inspect}
1788 f.puts "#define RBX_LLVM_VERSION #{@llvm_version.inspect}"
1792 f.puts "#define RBX_LITTLE_ENDIAN 1"
1796 f.puts "#define RBX_HAVE_TR1 1"
1800 f.puts "#define RBX_HAVE_TR1_HASH 1"
1804 f.puts "#define RBX_GC_STACK_CHECK 1"
1807 if @log_concurrent_update
1808 f.puts "#define RBX_LOG_CONCURRENT_UPDATE 1"
1811 if @raise_concurrent_update
1812 f.puts "#define RBX_RAISE_CONCURRENT_UPDATE 1"
1815 [:windows, :darwin, :bsd, :linux].each do |platform|
1816 if instance_variable_get(:"@#{platform}")
1817 f.puts "#define RBX_#{platform.to_s.upcase} 1"
1821 f.puts "#define RBX_DTRACE_CONST #{@dtrace_const ? "const" : ""}"
1823 write_have_defines f
1827 #include "detection.hpp"
1829 #define RBX_STRERROR_BUFSIZE 256
1831 // strerror_r has different signatures on GNU and XSI.
1832 // - The GNU version returns a pointer to a string, which may be the one passed
1833 // to the function as 'buf', or some immutable static string, in which case
1835 // - The XSI version always stores the error message in 'buf' and returns 0 on
1837 // This macro makes sure that the error message is returned either way.
1838 #ifdef STRERROR_R_CHAR_P
1839 #define RBX_STRERROR(errno, buf, size) strerror_r(errno, buf, size)
1841 #define RBX_STRERROR(errno, buf, size) (strerror_r(errno, buf, size), buf)
1844 // Enable this define for some minimal GC debugging
1845 // #define RBX_GC_DEBUG
1847 // Enable for GC stress. This only ensures that the interrupts
1848 // for a GC are set. Use RBX_GC_STRESS_YOUNG and / or RBX_GC_STRESS_MATURE
1849 // to run either the young or mature gen on each possibility
1850 // #define RBX_GC_STRESS
1852 // When stress testing is enabled, forces a young collection every time it
1853 // is possible. This can be useful to flush out bugs because of moving objects.
1854 // #define RBX_GC_STRESS_YOUNG
1856 // When stress testing is enabled, forces a mature collection every time it
1857 // is possible. This can be useful to flush out bugs with reachability etc.
1858 // #define RBX_GC_STRESS_MATURE
1864 # Write the config file for vendor/oniguruma.
1865 File.open "#{@build_libdir}/oniguruma/config.h", "wb" do |f|
1867 /* This file is generated by the Rubinius build system. Your edits
1868 * will be lost. See the configure script.
1872 write_have_defines f
1873 write_have_sizeof_defines f
1874 write_sizeof_defines f
1877 # Write release header file.
1878 write_release @vm_release_h
1880 # Write the rubinius-specific C-API config headers.
1881 vm_capi_header_gen = "#{@capi_includedir}/gen"
1882 FileUtils.mkdir_p vm_capi_header_gen
1883 FileUtils.cp vm_config_h, "#{vm_capi_header_gen}/rbx_config.h"
1884 FileUtils.cp @vm_release_h, "#{vm_capi_header_gen}/rbx_release.h"
1886 # Write the config file used in the C-API.
1887 capi_config_h = "#{@capi_includedir}/ruby/config.h"
1888 FileUtils.mkdir_p File.dirname(capi_config_h)
1889 File.open capi_config_h, "wb" do |f|
1891 /* This file is generated by the build system. Your edits
1892 * will be lost. See the configure script.
1896 #define NORETURN(x) __attribute__ ((noreturn)) x
1900 #define UNREACHABLE __builtin_unreachable()
1905 write_have_defines f
1906 write_have_sizeof_defines f
1907 write_sizeof_defines f
1910 f.puts "#define RBX_WINDOWS 1"
1916 puts "\nUsing the following configuration to build"
1917 puts "------------------------------------------"
1918 cat("build/config/config.rb")
1919 puts "\nSetting the following defines for the VM"
1920 puts "----------------------------------------"
1921 cat("machine/config.h")
1925 puts IO.read(relative_file(file))
1928 def relative_file(name)
1929 File.expand_path("../#{name}", __FILE__)
1932 def check_force_clean
1933 unless verify_build_signature
1934 @log.write "\nDetected old configuration settings, forcing a clean build"
1935 system("#{build_ruby} -S #{@rake} clean")
1940 @log.write "\nFetching gems..."
1943 Dir.chdir @gems_cache do
1944 @gem_files.each do |gem|
1945 next if File.exist? gem
1947 failed = true unless download "https://rubygems.org/gems/#{gem}", "./#{gem}"
1951 failure "Unable to download required gems." if failed
1955 @log.write "\nVerifying gems..."
1959 @gem_files.each do |gem_name|
1960 unless File.file? "#{@gems_cache}/#{gem_name}"
1961 @log.write "unable to find gem #{gem_name}"
1966 failure "Unable to find required gems." if failed
1969 def clean_gems(dir, gems)
1970 unpacked = Dir["#{dir}/*"]
1972 # Remove unpacked gems not specified by these configure settings
1973 unpacked.each do |dir|
1974 d = File.basename dir
1975 unless gems.find { |x| d =~ /^#{x}/ } and
1976 @gem_files.find { |x| d =~ /^#{x[0..-5]}/ }
1982 def unpack_gems(source, destination, list)
1983 FileUtils.mkdir_p destination unless File.directory? destination
1985 Dir.chdir destination do
1987 gem_name = @gem_files.find { |x| x =~ /^#{name}/ }
1988 failure "Unable to find gem to unpack: #{name}" unless gem_name
1990 next if @installed_gems.include? gem_name
1992 unless File.directory? gem_name[0..-5]
1993 system("#{@gem} unpack #{source}/#{gem_name}")
1995 unless $?.exitstatus == 0
1996 failure "Unable to unpack bootstrap gems."
2004 @log.write "\nSetting up gems..."
2006 # Remove unpacked gems not specified by these configure settings
2007 clean_gems @bootstrap_gems_dir, @gem_names
2009 # Unpack gems not found for these configure settings
2010 unpack_gems @gems_cache, @bootstrap_gems_dir, @gem_files
2014 @log.write "\nSetting up CodeDB..."
2016 dir = "#{@builddir}#{@codedbdir}"
2017 codedb_cache = "#{dir}/cache"
2019 unless File.file? codedb_cache
2020 url = "https://rubinius-binaries-rubinius-com.s3.amazonaws.com/codedb/"
2021 cache = "rubinius-codedb-cache"
2022 cache_bzip = "#{cache}.bz2"
2023 cache_digest = "#{cache_bzip}.sha512"
2025 unless File.file? cache_bzip
2026 download "#{url}#{cache_bzip}", cache_bzip
2029 unless File.file? cache_digest
2030 download "#{url}#{cache_digest}", cache_digest
2033 if Digest::SHA512.file(cache_bzip).hexdigest !=
2034 File.read(cache_digest).strip.split(" ").first
2035 failure "CodeDB cache SHA does not match"
2041 @log.write "\nSetting up stdlib..."
2043 stdlib_cache = "rubinius-stdlib-cache"
2044 cache_bzip = "#{stdlib_cache}.bz2"
2045 cache_digest = "#{cache_bzip}.sha512"
2047 unless File.file? cache_bzip
2048 url = "https://rubinius-binaries-rubinius-com.s3.amazonaws.com/stdlib/"
2050 unless File.file? cache_bzip
2051 download "#{url}#{cache_bzip}", cache_bzip
2054 unless File.file? cache_digest
2055 download "#{url}#{cache_digest}", cache_digest
2058 if Digest::SHA512.file(cache_bzip).hexdigest !=
2059 File.read(cache_digest).strip.split(" ").first
2060 failure "Stdlib cache SHA does not match"
2066 @log.write "\nSetting up codetools..."
2068 codetools_cache = "rubinius-codetools-cache"
2069 cache_bzip = "#{codetools_cache}.bz2"
2070 cache_digest = "#{cache_bzip}.sha512"
2072 unless File.file? cache_bzip
2073 url = "https://rubinius-binaries-rubinius-com.s3.amazonaws.com/codetools/"
2075 unless File.file? cache_bzip
2076 download "#{url}#{cache_bzip}", cache_bzip
2079 unless File.file? cache_digest
2080 download "#{url}#{cache_digest}", cache_digest
2083 if Digest::SHA512.file(cache_bzip).hexdigest !=
2084 File.read(cache_digest).strip.split(" ").first
2085 failure "Codetools cache SHA does not match"
2090 # Create directories that don't have to be created by the end user
2092 def create_directories
2093 FileUtils.mkdir_p @gems_cache
2097 unless ENV["RBX_SUPRESS_DEPRECATION"]
2098 @log.deprecated "\n\n'configure' is deprecated and will be removed in the future.\n" \
2099 "Use 'build.sh' to configure, build, package, and install Rubinius.\n\n\n"
2105 detect_homebrew_openssl_lib
2110 set_filesystem_paths
2114 unless sizeof("long") == 8
2115 failure "Support for non-64bit platforms was deprecated 1 Jun 2016 and has now been removed. If non-64bit support is a critical feature for your application, please email contact@rubinius.com"
2127 write_configure_files
2128 write_build_signature
2130 return if @release_config
2132 print_debug if @verbose
2134 if @llvm_source_build
2135 files = prebuilt_files.map { |f| File.basename f, ".tar.bz2" }.join("\n ")
2139 ------------------------------------------------------------------
2140 Unable to find an existing binary build of LLVM for your platform.
2142 Please notify the Rubinius team at the #rubinius channel on
2143 irc.freenode.net and provide the following system information:
2148 ------------------------------------------------------------------
2154 Rubinius (#{release_revision.last[0, 8]}) has been configured.
2156 Run 'rake' to build and test Rubinius.
2160 Rubinius (#{release_revision.last[0, 8]}) has been configured for the following paths:
2162 prefix: #{@prefixdir}
2163 bin: #{@prefixdir}#{@bindir}
2164 lib: #{@prefixdir}#{@libdir}
2165 include: #{@prefixdir}#{@includedir}
2166 codedb: #{@prefixdir}#{@codedbdir}
2167 site: #{@prefixdir}#{@sitedir}
2168 arch: #{@prefixdir}#{@archdir}
2169 vendor: #{@prefixdir}#{@vendordir}
2170 man: #{@prefixdir}#{@mandir}
2171 gems: #{@prefixdir}#{@gemsdir}
2172 gems cache: #{@gems_cache}
2174 Run 'rake' to build, test and install Rubinius.
2178 links = (@bin_links + [@program_name]).uniq
2181 ------------------------------------------------------------------
2184 After building, you may add
2186 '#{@prefixdir}#{@bindir}'
2188 to your PATH or run commands directly from that directory.
2190 Available commands are:
2194 ------------------------------------------------------------------
2199 # Configuration item that has both a default and a configured value
2200 class ConfigurationToggle
2201 attr_reader :default, :configured
2203 def initialize(default_value)
2204 @default = !!default_value
2208 def configured=(value)
2209 @configured = !!value
2213 unless @configured.nil?
2221 # Handles user output and logging while running configure.
2225 # Creates an instance of Logger writing to +file+.
2226 def initialize(file, init=true)
2227 @path = File.expand_path("../#{file}", __FILE__)
2229 File.open(@path, "wb") { }
2230 log "Configuring Rubinius..."
2234 # Copies the contents of +other+ into this logger's file.
2237 f.puts File.read(other)
2241 # Writes +message+ to the logging file but not to the screen.
2242 def log(message, error=false)
2244 stamp = "#{timestamp}#{'*** ERROR' if error}"
2245 if multiline?(message)
2246 f.puts "#{stamp} ---"
2250 f.puts "#{stamp} #{message}"
2255 # Writes a normal message to STDOUT and logs to the file.
2261 # Writes a normal message to STDOUT with #print and logs to file.
2264 STDOUT.print message
2267 # Writes an error message to STDERR and logs to the file with
2268 # error decorations. This should only be used for errors that
2269 # affect configure itself.
2275 DEPRECATION_HEADER =
2276 "------------------------------ Deprecation notice ------------------------------"
2277 DEPRECATION_FOOTER =
2278 "--------------------------------------------------------------------------------"
2280 def deprecated(message)
2281 log DEPRECATION_HEADER, true
2283 log DEPRECATION_FOOTER, true
2285 STDERR.puts DEPRECATION_HEADER
2287 STDERR.puts DEPRECATION_FOOTER
2290 # Yields an IO for writing log messages.
2292 File.open @path, "a" do |f|
2297 # Returns a formatted times suitable for logging.
2299 Time.now.strftime "[%Y-%m-%d %H:%M:%S]"
2302 # Returns true if the message has more than one line.
2303 def multiline?(message)
2304 message.index("\n") != nil
2308 # Returns true if the *port* command is in the PATH and identifies
2309 # itself with "MacPorts" when run interactively.
2311 `echo quit | port 2>&-`.start_with? 'MacPorts'
2314 # Query MacPorts for the path to the latest installed version of
2315 # llvm-config that is within the range of supported LLVM versions.
2316 def macports_llvm_config
2317 supported_versions = (3.6..3.9)
2318 installed_ports = `port installed | egrep -o 'llvm-[^ ]+'`.split
2319 latest_usable_port = installed_ports.sort.select do |fname|
2320 version = fname.match(/-\K.*/)[0].to_f
2321 supported_versions.include? version
2323 avail_binaries = `port contents #{latest_usable_port} |
2324 fgrep llvm-config`.split
2325 avail_binaries.reject { |fname| fname.include? 'libexec' }.last
2329 `brew #{args}`.chomp
2332 # Returns true if the *brew* command is in the PATH and identifies
2333 # itself with "Homebrew" when run interactively with -v argument.
2335 brew("-v 2>&1").start_with? 'Homebrew'
2338 # Check if latest version of openssl is installed; if so, add to include
2340 def detect_homebrew_openssl_lib
2341 if @darwin && homebrew? && (brew("list").split("\n").include? "openssl")
2342 prefix = brew("--prefix openssl")
2344 ENV["OPENSSL_DIR"] = prefix unless ENV["OPENSSL_DIR"]
2352 Configure.new(root).run