rubinius/rubinius

View on GitHub
rakelib/core.rake

Summary

Maintainability
Test Coverage
# All the tasks to manage building the Rubinius core library--which is
# essentially the Ruby core library plus Rubinius-specific files. The core
# bootstraps a Ruby environment to the point that user code can be loaded and
# executed.
#
# The basic rule is that any generated file should be specified as a file
# task, not hidden inside some arbitrary task. Generated files are created by
# rule (e.g. the rule for compiling a .rb file into a .rbc file) or by a block
# attached to the file task for that particular file.
#
# The only tasks should be those names needed by the user to invoke specific
# parts of the build (including the top-level build task for generating the
# entire core library).

require "rakelib/digest_files"

# drake does not allow invoke to be called inside tasks
def core_clean
  rm_rf Dir["**/*.rbc",
           "**/.*.rbc",
           "#{BUILD_CONFIG[:builddir]}#{BUILD_CONFIG[:codedbdir]}/platform.conf",
           "#{BUILD_CONFIG[:builddir]}#{BUILD_CONFIG[:codedbdir]}/source",
           "#{BUILD_CONFIG[:prefixdir]}/#{BUILD_CONFIG[:archdir]}/**/*",
           "#{BUILD_CONFIG[:prefixdir]}/#{BUILD_CONFIG[:archdir]}/**/*.*",
           "spec/capi/ext/*.{o,sig,#{$dlext}}",
          ],
    :verbose => $verbose
end

codedb_source = []

codedbdir = "#{BUILD_CONFIG[:builddir]}#{BUILD_CONFIG[:codedbdir]}"
platform_conf = "#{codedbdir}/platform.conf"

codedb_cache = "#{codedbdir}/cache"
codedb_cache_next = codedb_cache + ".next"

library_dir = "#{BUILD_CONFIG[:sourcedir]}/library"
codetoolsdir = BUILD_CONFIG[:codetoolsdir]
stdlibdir = BUILD_CONFIG[:stdlibdir]

core_load_order = "core/load_order.txt"

bzip = BUILD_CONFIG[:bzip]
tar = BUILD_CONFIG[:tar]

# TODO: these should be proper dependencies
codedb_cachedir = "#{BUILD_CONFIG[:builddir]}#{BUILD_CONFIG[:codedbdir]}/cache"
codedb_cache_bzip = "rubinius-codedb-cache.bz2"
if File.exist? codedb_cache_bzip and not File.directory? codedb_cachedir
  mkdir_p codedbdir
  sh "#{bzip} -c -d #{codedb_cache_bzip} > #{codedb_cachedir}"
end

codetools_cache_bzip = "rubinius-codetools-cache.bz2"
if File.exist? codetools_cache_bzip and not File.directory? codetoolsdir

  mkdir_p codetoolsdir
  sh "#{tar} -C #{codetoolsdir} -xzf #{BUILD_CONFIG[:sourcedir]}/#{codetools_cache_bzip}"
end

stdlib_cache_bzip = "rubinius-stdlib-cache.bz2"
if File.exist? stdlib_cache_bzip and not File.directory? stdlibdir
  mkdir_p stdlibdir
  sh "#{tar} -C #{stdlibdir} -xzf #{BUILD_CONFIG[:sourcedir]}/#{stdlib_cache_bzip}"
end

def codedb_source_task(db, origin, source)
  db << source

  file source => origin do |t|
    dir = File.dirname t.name
    mkdir_p dir, :verbose => $verbose unless File.directory? dir

    cp t.prerequisites.first, t.name, :verbose => $verbose
  end
end

# Add core files
IO.foreach core_load_order do |name|
  origin = "core/#{name.chomp}"

  codedb_source_task codedb_source, origin, "#{codedbdir}/source/#{origin}"
end

FileList["#{library_dir}/**/*.*"].each do |file|
  source = "#{codedbdir}/source/#{file[(library_dir.size+1)..-1]}"

  unless File.directory? file
    codedb_source_task codedb_source, file, source
  end
end

# Add codetools
FileList["#{codetoolsdir}/{lib,ext}/**/*.rb"].each do |file|
  source = "#{codedbdir}/source/#{file[(codetoolsdir.size+5)..-1]}"

  unless File.directory? file
    codedb_source_task codedb_source, file, source
  end
end

# Add stdlib
FileList["#{stdlibdir}/{lib,ext}/**/*.rb"].each do |file|
  source = "#{codedbdir}/source/#{file[(stdlibdir.size+5)..-1]}"

  unless File.directory? file
    codedb_source_task codedb_source, file, source
  end
end

config_files = FileList[
  "Rakefile",
  "build/config/config.rb",
  "rakelib/*.rb",
  "rakelib/*.rake"
]

ext_source = FileList[
  "#{stdlibdir}/**/*.{c,h}pp",
  "#{stdlibdir}/**/grammar.y",
  "#{stdlibdir}/**/lex.c.*",
  "#{codetoolsdir}/**/*.{c,h}pp",
  "#{codetoolsdir}/**/grammar.y",
  "#{codetoolsdir}/**/lex.c.*",
]

melbourne_ext = FileList["#{codetoolsdir}/ext/**/melbourne/extconf.rb"].first
extconf_source = FileList["#{stdlibdir}/ext/**/extconf.rb"]

extensions_dir = "#{BUILD_CONFIG[:builddir]}/#{BUILD_CONFIG[:archdir]}"
directory extensions_dir

signature_files = codedb_source + config_files + ext_source

def build_extension(file, melbourne=false)
  FileUtils.mkdir_p "#{BUILD_CONFIG[:builddir]}#{BUILD_CONFIG[:includedir]}/ruby/digest"

  Dir.chdir File.dirname(file) do
    if file =~ /openssl/ and openssl = ENV["OPENSSL_DIR"]
      options = "--with-cppflags=-I#{openssl}/include --with-ldflags=-L#{openssl}/lib"
    else
      options = nil
    end

    ignore = false

    unless File.exist? "Makefile"
      begin
        ENV["RBX_PREFIX_PATH"] = BUILD_CONFIG[:builddir]

        extconf = melbourne ? "--main rubinius/code/melbourne/extconf.rb" : "extconf.rb"

        sh "#{BUILD_CONFIG[:build_exe]} -v --disable-gems #{extconf} #{options}",
           :verbose => $verbose do |ok, result|
          unless ok
            puts "#{file} failed to run, skipping C-extension"
            ignore = true
          end
       end
      ensure
        ENV.delete "RBX_PREFIX_PATH"
      end
    end

    unless ignore
      sh "#{BUILD_CONFIG[:build_make]}", :verbose => $verbose
      sh "#{BUILD_CONFIG[:build_make]} install", :verbose => $verbose
    end
  end
end

namespace :codedb do
  task :signature => signature_files do
    SIGNATURE_HASH = digest_files signature_files
  end

  task :extensions => [extensions_dir, melbourne_ext] + extconf_source do
    # It would be better to define file commands for every extension but we
    # don't know the extension shared library without some other source
    # parsing so we just iterate based on files.

    begin
      destdir = ENV["DESTDIR"]
      ENV.delete "DESTDIR"

      ENV["CXX"] = BUILD_CONFIG[:cxx]
      ENV["CXXFLAGS"] = BUILD_CONFIG[:system_cxxflags]
      ENV["CPPFLAGS"] = BUILD_CONFIG[:system_cppflags]
      ENV["INCFLAGS"] = BUILD_CONFIG[:system_incflags]
      ENV["LDSHAREDXX"] = BUILD_CONFIG[:ldsharedxx]
      ENV["LDFLAGS"] = BUILD_CONFIG[:system_ldflags]

      build_extension melbourne_ext, true

      Dir.chdir "#{codetoolsdir}/lib" do
        FileList["./**/*.#{RbConfig::CONFIG["DLEXT"]}"].each do |lib|
          lib_dir = "#{extensions_dir}/#{File.dirname(lib)}"
          mkdir_p lib_dir

          cp lib, lib_dir, :verbose => $verbose
        end
      end
    ensure
      ENV["DESTDIR"] = destdir

      ENV.delete "CXX"
      ENV.delete "CXXFLAGS"
      ENV.delete "CPPFLAGS"
      ENV.delete "INCFLAGS"
      ENV.delete "LDSHAREDXX"
      ENV.delete "LDFLAGS"
    end

    # Rebuild the CodeDB cache to include platform-specific code
    begin
      ENV["RBX_PREFIX_PATH"] = BUILD_CONFIG[:builddir]

      Dir.chdir BUILD_CONFIG[:builddir] do
        sh "#{BUILD_CONFIG[:build_exe]} -v --disable-gems #{BUILD_CONFIG[:scriptdir]}/create_codedb_cache.rb #{codedb_cache_next}", :verbose => $verbose
      end

      mv codedb_cache_next, codedb_cache, :verbose => $verbose
    ensure
      ENV.delete "RBX_PREFIX_PATH"
    end

    extconf_source.each do |file|
      build_extension file
    end
  end
end

signature_header = "machine/signature.h"

file signature_header => "codedb:signature" do |t|
  File.open t.name, "wb" do |file|
    file.puts <<-EOC
#ifndef RBX_SIGNATURE_H
#define RBX_SIGNATURE_H

#define RBX_SIGNATURE          #{SIGNATURE_HASH.inspect}

#endif
    EOC
  end
end

desc "Build all core library files"
task :core => 'core:build'

namespace :core do
  desc "Build all core and library files"
  task :build => [platform_conf, signature_header] +
                 [codedbdir, codetoolsdir, stdlibdir] +
                 codedb_source + ["codedb:extensions"]

  desc "Delete all core and library artifacts"
  task :clean do
    core_clean
  end

  task :distclean => :clean do
  rm_rf Dir["#{BUILD_CONFIG[:sourcedir]}/rubinius-codedb-cache*",
           "#{BUILD_CONFIG[:sourcedir]}/rubinius-codetools-cache*",
           "#{BUILD_CONFIG[:sourcedir]}/rubinius-stdlib-cache*",
           codedbdir,
           codetoolsdir,
           stdlibdir,
          ],
    :verbose => $verbose
  end
end