rakelib/setup.rake
author Jan Vrany <jan.vrany@fit.cvut.cz>
Tue, 24 May 2016 12:03:26 +0100
changeset 7 b6fe3a90f6e0
parent 4 48ec8a59ced4
child 9 34274130f57a
permissions -rw-r--r--
Added `zip()` & `unzip()` extensions to easily create / extract archives from build scripts. Under Windows `zip() creates `.zip`, under Linux it creates `.tar.bz2`. As a side effect, `zip()` automatically generates SHA256 checksum and stores it along the archive in in `.zip.sha256` or `.tar.bz2.sha256`. The SHA256 checksum is automatically checked by `unzip()` if corresponding `.sha256` file exists.

defined? BUILD_DIR or BUILD_DIR = 'build'
defined? BUILD_ID or BUILD_ID = ENV['BUILD_NUMBER'] ? "build#{ENV['BUILD_NUMBER']}" : "#{Time.now.strftime("%Y%m%d")}"
defined? ARTIFACTS_DIR or ARTIFACTS_DIR = 'artifacts'
defined? REPORT_DIR or REPORT_DIR = 'reports'
defined? DEBUG or DEBUG = nil

if win32?
  ENV['CVS_RSH'] = 'plink' if not ENV['CVS_RSH']
  ENV['BCB'] = 'C:\\Borland\\BCC55' if not ENV['BCB']
end

if File.exist? '.config.rake'
  load '.config.rake'
end

defined? PROJECT or PROJECT = 'stx:jv-branch'


if not defined? ARCH then
  if ENV.has_key? 'ARCH' then
    ARCH = ENV['ARCH']
  else
    ARCH = RbConfig::CONFIG['host_cpu']
  end
  if ARCH != 'i386' && ARCH != 'x86_64' then
    raise Exception.new("Unsupported architecture #{ARCH}")
  end
end

if not defined? TOOLCHAIN then
  if ENV.has_key? 'TOOLCHAIN' then
    TOOLCHAIN = ENV['TOOLCHAIN']
  else
    if unix? then
      TOOLCHAIN='gcc'
    elsif win32? then
      if ARCH == 'x86_64' then
        TOOLCHAIN='mingw64'
      else
        # TOOLCHAIN='bcc'
        TOOLCHAIN="mingw32"
      end
    else
      raise new Exception("Unsupported operating system")    
    end
  end
end

if File.exist? '.config.rake'
  if defined? PROJECT
    File.open('.config.rake', 'w') do | f |
      f.puts "PROJECT='#{PROJECT}' if not defined? PROJECT"
      f.puts "ARCH='#{ARCH}' if not defined? ARCH"
      if defined? PROJECT_DIRS
        f.puts "PROJECT_DIRS='#{PROJECT_DIRS}' if not defined? PROJECT_DIRS"
      end
    end
  end
end

defined? PROJECT_DIRS or PROJECT_DIRS = ''

if TOOLCHAIN == 'gcc' then
  OBJ_DIR = '.'
  OBJ_SUFFIX = 'o'
  MAKE='make'
elsif TOOLCHAIN == 'bcc' then
  OBJ_DIR = 'objbc'
  OBJ_SUFFIX = 'obj'
  MAKE='bmake.bat -DUSEBC'
elsif TOOLCHAIN == 'mingw64' then
  if not File.exist? 'C:\mingw64\bin' then
  	raise new Exception("MINGW64 not found in C:\\mingw64!")
  end
  ENV['MINGW_DIR'] ='C:\MINGW64'
  ENV['MINGW'] = '__MINGW64__'
  ENV['USEMINGW_ARG'] = '-DUSEMINGW64'
  OBJ_DIR = 'objmingw'
  OBJ_SUFFIX = 'obj'
  MAKE='mingwmake.bat'  
  ENV["PATH"] = "#{ENV['PATH']};#{ENV['MINGW_DIR']}\\bin"
elsif (TOOLCHAIN == 'mingw' or TOOLCHAIN == 'mingw32') then
  if not File.exist? 'C:\mingw\bin' then
  	raise new Exception("MINGW not found in C:\\mingw!")
  end
  ENV['MINGW_DIR'] ='C:\MINGW'
  ENV['MINGW'] = '__MINGW32__'
  ENV['USEMINGW_ARG'] = '-DUSEMINGW32'	
  OBJ_DIR = 'objmingw'
  OBJ_SUFFIX = 'obj'
  MAKE='mingwmake.bat'
  ENV["PATH"] = "#{ENV['PATH']};#{ENV['MINGW_DIR']}\\bin"
else
  raise new Exception("Unsupported toolchain: #{TOOLCHAIN}")
end
  



task :'setup' => [ :'setup:pre',
                   :'setup:main',
                   :'setup:post' ]

task :'setup:pre'
task :'setup:post'

task :'setup:main' => [ :'setup:projects', :'setup:project' , :'setup:tasks' ];

task :'setup:projects' do
  Rake::Stx::Configuration.read_specs(PROJECT_DIRS)
end

task :'setup:project' =>  :'setup:projects'  do
  error("PROJECT variable not defined!") if not defined? PROJECT
  project! PROJECT.to_sym
  project.apply_imports()
  app_name    = project.app_name    || 'smalltalkx'
  app_version = project.app_version || '6.2.5'

  defined? BUILD_NAME or BUILD_NAME = "#{app_name}-#{app_version}_#{ARCH}-#{win32? ? 'win32' : RbConfig::CONFIG['host_os']}"
end

task :'setup:tasks' => :'setup:tasks:internal'

task :'setup:tasks:internal' => :'setup:project' do

  project().tasks.each do | t |
    t.define!
  end

  # compute required packages - bit hacky!
  pkgs_all  = project.packages.collect { | p | p.name }
  if project.application
    pkgs_all += [ project.application.name ]
    pkgs_reqd = Rake::Task[project.application.name].all_prerequisites_sorted
  else
    pkgs_reqd = (project.packages.select { | p | not p.link  }).collect { | p | p.name }
  end

  pkgs_reqd = pkgs_reqd.reject { | p | not pkgs_all.include? p }
  pkgs_reqd = pkgs_reqd.collect { | p | project.package(p) }
  if project.application
     pkgs_reqd_and_app = pkgs_reqd + [ project.application ]
  else
    pkgs_reqd_and_app = pkgs_reqd
  end

  info "Required packages (in topological order):"
  pkgs_reqd.each do | pkg |
    info "  #{pkg.name}"
  end


  # compile task
  if project.application
    task :'compile:application' => project.application.name
  else
    task :'compile:application'
  end

  info "Defining task for packages..."

  pkgs_reqd_and_app.each do | pkg |

    info "Defining task for package #{pkg.name}"

    if unix? #and not File.exist? BUILD_DIR / pkg.directory / 'makefile'
      task pkg.name => [ BUILD_DIR / pkg.directory / 'makefile' ]
      file BUILD_DIR / pkg.directory / 'makefile' do
        chdir BUILD_DIR / pkg.directory do
          if not system "sh #{ pkg.top() / 'stx' / 'rules' / 'stmkmf'}"
            raise Exception.new("Canmot run stmkmf for #{pkg.directory}")
          end
        end
      end
    end

    #require 'find'
    #[ 'bitmaps', 'resources' ].each do | dir |
    #  path = BUILD_DIR / pkg.directory() / dir
    #  if File.exist?(path)
    #    Find.find(File.expand_path(path)) do | file |
    #      if FileTest.directory?(file)
    #        if (File.basename(file) == '..') || (File.basename(file) == '.')
    #          Find.prune       # Don't look any further into this directory.
    #        else
    #          if File.exists?(File.join(file, '.svn'))
    #            rm_rf File.join(file, '.svn')
    #            #Find.prune
    #          end
    #        end
    #      end
    #    end
    #  end
    #end

    task "#{pkg.name}" => [ "#{pkg.name}:pre", "#{pkg.name}:main", "#{pkg.name}:post" ]

    task "#{pkg.name}:pre"
    task "#{pkg.name}:post"

    task "#{pkg.name}:main" do | t |
      make_vars = ""
      d = win32? ? '-D' : ''
      q = win32? ? '"'  : "'"


      if unix?
        make_vars += "STC=#{STC}"
      end
      if pkg.application? and not win32?
        liblist=''
        libobjs=''
        link_libobjs=''

        pkgs_reqd.each do | p |
          if not p.application?
              if p.link
                liblist += "#{p.dll_name_without_suffix()} "
                libobjs += "#{File.join(pkg.top() , p.directory(), p.dll_name())} "
                link_libobjs += "#{p.dll_name()} "
              end
          end
        end


        make_vars += " #{q}#{d}LIBLIST=#{liblist}#{q}"
        make_vars += " #{q}#{d}LIBOBJS=#{libobjs}#{q}"
        make_vars += " #{q}#{d}LINK_LIBOBJS=#{link_libobjs}#{q}"
      end

      # Update stc flags,
      stc_flags = pkg.stc_flags

      if stc_flags
        make_vars += " #{q}#{d}STC_CMD_OPT=#{stc_flags}#{q}"
      end

      if File.exist? BUILD_DIR / pkg.directory / 'GNUmakefile'
        rm BUILD_DIR / pkg.directory / 'GNUmakefile'
      end

      info "Compiling #{pkg.name}..."
      make_vars = "#{make_vars} #{DEBUG}"
      chdir BUILD_DIR / pkg.directory do
        if pkg.application? and win32?
          make 'exe'
          make 'RESOURCEFILES'
        else
          # Somewhat stupid detection whether we run recent St/X or not...
          if File.exist? BUILD_DIR / 'stx' / 'libbasic2' / 'Makefile.init'
            make "#{make_vars} full"
          else
            make "#{make_vars}"
          end
        end
      end

      if pkg.application?  and unix?
        chdir BUILD_DIR / 'stx' / 'librun' do
          make
        end
      end



    end

    if pkg.application?
      if win32?
        task pkg.name => BUILD_DIR / pkg.directory / 'modules.stx'

        task BUILD_DIR / pkg.directory / 'modules.stx' do | t |
          rm t.name if File.exist? t.name
          File.open(t.name, 'w') do | f |
            pkgs_reqd.each do | p |
              if not p.application? and File.exist? BUILD_DIR / p.directory / OBJ_DIR / p.dll_name()
                f.puts p.dll_name_without_suffix()
              end
            end
          end
        end

        pkgs_reqd.each do | p |
          if not p.application?
            task pkg.name => BUILD_DIR / pkg.directory / p.dll_name()

            file BUILD_DIR / pkg.directory / p.dll_name() => BUILD_DIR / p.directory / OBJ_DIR / p.dll_name() do
              cp BUILD_DIR / p.directory / OBJ_DIR / p.dll_name(),
              BUILD_DIR / pkg.directory / p.dll_name()
            end
          end

          if win32_wine?
            file BUILD_DIR / pkg.directory / p.dll_name() do
              cp BUILD_DIR / p.directory / OBJ_DIR / p.dll_name(),
              BUILD_DIR / pkg.directory / p.dll_name()
            end
          end

        end
      else # UNIX
        task "#{pkg.name}:main" => BUILD_DIR / pkg.directory / 'modulList.stc'

        task BUILD_DIR / pkg.directory / 'modulList.stc' do | t |
          rm t.name if File.exist? t.name
        end

        task "#{pkg.name}:main" => BUILD_DIR / pkg.directory / 'modulList.c'

        task BUILD_DIR / pkg.directory / 'modulList.c' do | t |
          rm t.name if File.exist? t.name
        end
      end
    end
  end

end