rakelib/compile.rake
author Jan Vrany <jan.vrany@fit.cvut.cz>
Tue, 31 Jan 2017 11:09:02 +0000
changeset 122 6fcb351d23a7
parent 111 767f2ace9b82
child 133 8229af6e81df
child 137 e665031cade7
permissions -rw-r--r--
Use our own make configuration files rather than eXept's rather than eXept's configs found in `stx/configurations`. eXept's configs don't really fit Smalltalk/X jv-branch needs. In the past, we used to monkey-patch eXept's definitions and tweak them here and there, but this lead to a big mess (not a surprise) in `rakelib/compile.rake`. As we want to support more OS/CPU combinations, thing would go rather wild and truly messy. Hence we provide our own, starting off with eXept's definition. The plan is eventually to clean them up to the point we understand how it works and then rewrite build process of individual packages to unify *NIX and Windows builds (since Windows now use different schema based on ancient, unmaintained Borland make). It is likely that in a future this directory will also contain make rules for actual compilation - stuff now located `stx/rules` (pulled from eXept's CVS)


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'


  case
  when unix?
    task :'config' => [ STX_CONF_DIR / 'COMMON' / 'defines',
                        STX_CONF_DIR / 'vendorConf',
                        STX_CONF_DIR / 'myConf' ,

                        STX_RULES_DIR / 'stdRules' ]


    task STX_RULES_DIR / 'stdRules' do
      # Sigh, yet another hack here. For a funny reason, target newobj depends on .o files
      # and not on target objs. The problem is that some of the .o may need some third party
      # library being built before (for example, stx:libview2 requires libjpeg-9 being built 
      # before!). To workaround this, we have to patch the rule so it depends on target `objs`
      # which depends on `pre_objs` that builds libraries. Triple sigh here. I should fork rules
      # directory...
      sed('newobj: $(LIBNAME)Init.c $(LINKOBJS)' , 'newobj: $(LIBNAME)Init.c objs $(LINKOBJS)', STX_RULES_DIR / 'stdRules', true)
      
      # Yet another hack to pass absolute filenames when compiling. This should help Jenkins's 
      # Warning plugin correctly locate files mentioned in compile log - it cannot deal with relative paths
      # (as it cannot track compilation process's working directory, naturally)
      sed(' $(STFILE)', ' $(PWD)/$(STFILE)', STX_RULES_DIR / 'stdRules', true) 
    end

    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_DIR ?= $(TOP)/#{makelib_dir}
          include $(MAKELIB_DIR)/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
  when win32?
    task :'config' => [ STX_RULES_DIR / 'stdRules_bc_mingwhack.txt' ]

    file STX_RULES_DIR / 'stdRules_bc_mingwhack.txt' do
      File.open( STX_RULES_DIR / 'stdRules_bc', 'a') do | f |
        f.puts "!if defined(USEMINGW32) || defined(USEMINGW64)"
        f.puts "CFLAGS=#{GCC_CFLAGS} $(CFLAGS1) $(CFLAGS2) $(LOCALINCLUDES) $(CLOCAL_INCL) $(CFLAGS_LOCAL)"
        f.puts "!endif"
      end
      File.open( STX_RULES_DIR / 'stdRules_bc_mingwhack.txt', 'a') do | f |
        f.puts "stdRules_bc CFLAGS already fixed"
      end
    end
  else
    error "Unsuported platform: #{Config::CONFIG['host_os']}"
  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


#
# Various compilation hacks here and there (sigh)
# 

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