rakelib/compile.rake
author Jan Vrany <jan.vrany@fit.cvut.cz>
Thu, 03 Aug 2017 09:37:46 +0100
changeset 135 0325651d2b43
parent 133 8229af6e81df
child 136 29bd0a3c4a31
permissions -rw-r--r--
Makefiles: use our own makefiles rather than eXept's ...found in `stx/rules`. eXept's makefiles doesn't really fit Smalltalk/X jv-branch needs - they're cluttered with workarounds for long unsupported tools and platforms. In the past we had to monkey-patch them here and there. From this commit on, building requires GNU Make on UNUX-like and GCC or Clang toolchain on both UNIX-like and Windows. There we use MSYS2 environment. This is a followup for 6fcb351d23a7.


desc "Compile project"
task :'compile' => :'compile:all'


STX_TOP_DIR = BUILD_DIR / 'stx'
STX_CONF_DIR = STX_TOP_DIR / 'configurations'
STX_RULES_DIR = STX_TOP_DIR / 'rules'
if win32?
  STC = STX_TOP_DIR / 'stc' / 'stc.exe'
  LIBRUN = STX_TOP_DIR / 'librun' / 'objmingw' / 'librun.dll'
else
  STC = STX_TOP_DIR / 'stc' / 'stc'
  LIBRUN = STX_TOP_DIR / 'librun' / 'librun.so'
end

# Return true if stx:stc and stx:librun sources should be removed as soon 
# as STC or librun is built. False otherwise (sources are not removed by 
# rakefiles)
#
# Indeed this is a feeble protection as it's easy to trick this method. But 
# the goal is not to protect sources but rather have a secondaty measure to
# avoid sources to leak (for exaple, due to a bug in packaging scripts).
# Unathorized subjects should not be able to checkout sources in first instance.
def should_remove_librun_and_stc_sources
    return ! (core_developer? or ENV['RETAIN_STX_AND_LIBRUN_SOURCE'] == 'yespleaseretain!')
end

def rm_rf_all_in_except(directory, exceptions = [])
  if File.directory? directory then
    Dir.foreach(directory) do | each |
      if each != '.' and each != '..' and not exceptions.include? each
        rm_rf File.join(directory, each)
      end
    end
  else
    rm_f directory
  end
end

if unix? 
  STC_BINARY_FILES = [    
    'cpu_alpha.h',
    'cpu_arm.h',
    'cpu_hppa.h',
    'cpu_i386.h',
    'cpu_x86_64.h',
    'cpu_ia64.h',
    'cpu_mc68k.h',
    'cpu_mc88k.h',
    'cpu_mips.h',
    'cpu_ns32k.h',
    'cpu_power.h',
    'cpu_s390.h',
    'cpu_sparc.h',
    'cpu_vax.h',
    'stc.h',
    'stcIntern.h',
    'stcVMdata.h',
    'stcVMoffsets.h',
    'stxAsmMacros.h',
    'stxNames.h',
    'stxOSDefs.h',
    'stxTypeMacros.h',     
    'symbols.stc.seed',
    'version.h',
    'README',

    #unix specific
    'stx-config.sh',
    'linuxIntern.h',
    'macIntern.h',        
    'Make.proto',
    'stc',
    'stc.1',    
  ]
  LIBRUN_BINARY_FILES1 = [    
    'libffi-3.2.1',
    'md5.h',
    'mcompiler.h',
    'main.c',
    'librun.so',
    'librun.a',
    'symlist.c',
    'Make.proto',
    'makefile',
  ]
  LIBRUN_BINARY_FILES2 = []
elsif win32?
  STC_BINARY_FILES = [    
    'cpu_alpha.h',
    'cpu_arm.h',
    'cpu_hppa.h',
    'cpu_i386.h',
    'cpu_x86_64.h',
    'cpu_ia64.h',
    'cpu_mc68k.h',
    'cpu_mc88k.h',
    'cpu_mips.h',
    'cpu_ns32k.h',
    'cpu_power.h',
    'cpu_s390.h',
    'cpu_sparc.h',
    'cpu_vax.h',
    'stc.h',
    'stcIntern.h',
    'stcVMdata.h',
    'stcVMoffsets.h',
    'stxAsmMacros.h',
    'stxNames.h',
    'stxOSDefs.h',
    'stxTypeMacros.h', 
    'symbols.stc.seed',
    'version.h',
    'README',

    #windows specific
    'stx-config.bat',
    'mingwmake.bat',
    'ntIntern.h',
    'nt.h',
    'Make.proto',
    'stc.exe',
  ]  
  LIBRUN_BINARY_FILES1 = [    
    'libffi-3.2.1',
    'md5.h',
    'mcompiler.h',
    'main.c',
    'objmingw', 
    'bc.mak',
    'mingwmake.bat',
    'buildDate.h',
    'genDate.com',
  ]
  LIBRUN_BINARY_FILES2 = [
    'librun.dll',
    'librun.lib',
  ]
else
  raise Exception.new("Unsupported platform")
end

def cleanup_stc()  
  if should_remove_librun_and_stc_sources()
    puts "Cleaning up stc..."
    begin
      rm_rf_all_in_except(STX_TOP_DIR / 'stc', STC_BINARY_FILES)    
    rescue
      # When something goes wrong, be safe and remove whole directory
      rm_rf STX_TOP_DIR / 'stc'
    end
  end
end

def cleanup_librun()
  if should_remove_librun_and_stc_sources()
    puts "Cleaning up librun..."
    begin
      rm_rf_all_in_except(STX_TOP_DIR / 'librun', LIBRUN_BINARY_FILES1)
      if win32? then
        rm_rf_all_in_except(STX_TOP_DIR / 'librun' / 'objmingw', LIBRUN_BINARY_FILES2)
      end
    rescue
      # When something goes wrong, be safe and remove whole directory
      rm_rf STX_TOP_DIR / 'librun'
    end      
  end
end

# Setup flags for GCC (both, real GCC and MinGW)
GCC_CFLAGS_OPT = ARCH == 'i386' ? '-O' : ''
GCC_CFLAGS_DBG = core_developer? ? '-ggdb3' : ''
GCC_CFLAGS_PIC = win32? ? '' : '-fPIC'
GCC_CFLAGS = "-pipe -fno-omit-frame-pointer -fno-stack-protector -fno-strict-aliasing -fwrapv #{GCC_CFLAGS_PIC} #{GCC_CFLAGS_OPT} #{GCC_CFLAGS_DBG}"

# Sigh, for MINGW 5.x.x coming with MSYS2 we have to force C language as 
# Borland make and build files are using funny suffixes to confuse GCC's 
# language detection. Triple sigh here!
GCC_CFLAGS += " -x c" if win32?

namespace :'compile' do

  task :'all' => [ :'prereq', :'pre', :'main', :'post' ]

  task :'pre'
  task :'post'

  task :'prereq' => [ :'setup' ]

  task :'main' => [ 
        :'config',
        :'libraries',
        :'stc',       
        :'librun',        
        :'application',                
      ]      

  task :'config' => [ STX_TOP_DIR / 'include' ]

  directory STX_TOP_DIR / 'include'

  task :'application' => :'setup:dependencies'


  
  if unix?
    mkdir_p STX_CONF_DIR
                        STX_CONF_DIR / 'vendorConf',
                        STX_CONF_DIR / 'myConf' ]

    directory STX_CONF_DIR do | t |
      mkdir_p t.name()
    end

    directory STX_CONF_DIR / 'COMMON' do | t |
      mkdir_p t.name()
    end

    directory STX_CONF_DIR / 'COMMON' / 'defines' => STX_CONF_DIR / 'COMMON' do | t |
      File.open(t.name(), "w") do | f |
        f.puts <<-CONTENTS
          # Do not edit! Automatically generated by rake (rakelib/#{__FILE__})
          # 
          # Nothing here, all "common" definitions are included in config file
          # (`config-<OS>-<ARCH>.make`)
          CONTENTS
      end
    end

    file STX_CONF_DIR / 'vendorConf' => STX_CONF_DIR  do | t |
      makelib_dir = Pathname.new(File.expand_path('makelib')).relative_path_from(Pathname.new(BUILD_DIR / 'stx' ))
      os = nil
      case 
      when linux? 
        os = 'linux'
      else
        raise Exveption.new("Unssuported operating system")
      end

      File.open(t.name(), "w") do | f |
        f.puts <<-CONTENTS      
          # Do not edit! Automatically generated by rake (rakelib/#{__FILE__})
          #
          TOP ?= #{BUILD_DIR / 'stx'}
          MAKELIB ?= $(TOP)/#{makelib_dir}
          include $(MAKELIB)/config-#{os}-#{ARCH}.make          
          CONTENTS
      end
    end

    file STX_CONF_DIR / 'myConf' => STX_CONF_DIR  do | t |
      File.open(t.name(), "w") do | f |
        f.puts <<-CONTENTS
          # Local modifications / additions specific to this very build, if needed. 
          #           
          CONTENTS
      end
    end  
  end

  rule 'makefile' do | t |
    if File.exist?(File.dirname(t.name) / 'GNUmakefile')
      rm (File.dirname(t.name) / 'GNUmakefile')
    end

    chdir File.dirname(t.name) do
      sh "'#{STX_TOP_DIR / 'rules' / 'stmkmf'}'"
    end
  end

  task :stc do
    if linux? and x86_64? and ARCH == 'i386'
      stx_make_flags="STC_LEXLIB=libfl/libfl_pic.a"
    else
      stx_make_flags=""
    end

    chdir STX_TOP_DIR / 'stc' do      
      begin
        make stx_make_flags
        cleanup_stc()
      rescue Exception => e
        cleanup_stc()
        cleanup_librun()
        error "Cannot compile stx:stc: #{e.description}"
      end  
    end
  
    if not File.exist? STX_TOP_DIR / 'include' / 'stx-config.h' then
      cp STX_TOP_DIR / 'stc' / 'stx-config.h' , STX_TOP_DIR / 'include' / 'stx-config.h'
    end

    if not File.exist? STC
      cleanup_stc()
      cleanup_librun()
      error "Cannot compile stx:stc"
    end
  end

 task :librun do
    chdir STX_TOP_DIR / 'librun' do
      begin
        begin
            if win32_wine?
              if not File.exist? 'libffi' / 'build_win32' / 'objbc'
                mkdir 'libffi' / 'build_win32' / 'objbc'
              end
            end
          # A workaround for Windows 10 & ancient Borland make which 
          # tend to crash there when trying to recompile already compiled
          # librun. Sigh, we have to move away from it as soon as possible!
          
          if win32? and (File.exist? 'stxmain.c') then
            touch "stxmain.c"
          end
          make
          cleanup_librun()
        rescue Exception => e
          cleanup_stc()
          cleanup_librun()
          error "Cannot compile stx:librun: #{e.description}"
        end
      end
    end
  end

  if unix?
    task :stc => STX_TOP_DIR / 'stc' / 'makefile'
    task :librun => STX_TOP_DIR / 'librun' / 'makefile'
  end

  if win32? and TOOLCHAIN == 'bcc'
    directory STX_TOP_DIR / 'lib' / 'bc'
    task :librun => STX_TOP_DIR / 'lib' / 'bc'
  end

  task :'libraries'

  if unix?
    vogl_dir = STX_TOP_DIR / 'support' / 'VGL' / 'vogl'

    task 'libraries' => [ vogl_dir / 'src' / 'libvogl.a' ]

    file vogl_dir / 'src' / 'libvogl.a' => [ vogl_dir / 'makefile'  ] do
      chdir STX_TOP_DIR / 'support' / 'VGL' / 'vogl' do
        make
      end
    end
  end
end


task "stx:librun:symbols"

#
# Various compilation hacks here and there (sigh)
# 
desc "Update the VM symbol database"
task 'stx:librun:symbols' do | task |    
  symbols_stc = BUILD_DIR / 'stx' / 'include' / 'symbols.stc'
  if unix?
    # UNIX VMs have the symbol database built into the binary as
    # static data so we need to recompile the VM
    stx_librun = project.package('stx:librun')
    stx_librun_dll = BUILD_DIR / stx_librun.directory() / OBJ_DIR / stx_librun.dll_name()

    if not uptodate?(stx_librun_dll, [ symbols_stc ]) then
      Rake::Task["stx:librun"].reenable()
      Rake::Task["stx:librun"].invoke()
    end
  elsif win32? 
    # Windows VM reads the symbol database from a file `symbols.stc` located
    # alongside the program executable so we need to copy that file
    app = project.application
    symbols_stc_in_app_directory = BUILD_DIR / app.directory() / 'symbols.stc'
    if not uptodate?(symbols_stc_in_app_directory, [ symbols_stc ]) then
      cp symbols_stc, symbols_stc_in_app_directory
    end
  end
  task.reenable()
end

if unix?
  # A hack for Debian (and possibly other Linux distros) that does not ship
  # 32bit libodbc.a / libodbcinst.a. Link directly against .so
  task :'stx:libdb/libodbc:pre' do     
	  sed('-lodbc -lodbcinst' , '-l:libodbc.so.2 -l:libodbcinst.so.2', BUILD_DIR / 'stx' / 'libdb' / 'libodbc' / 'Make.proto', true)
  end  
end