#!/usr/bin/env python
import os
import stat
import string
import sys

OCAMLC='ocamlc.opt'
OCAMLOPT='ocamlopt.opt -thread'

LEXS = ['py_lex']
PARSES = ['py_parse']

INTERFACES = [
  'gnu_readline'   ,
  'glib'           ,
  'gdk'            ,
  'gtk'            ,
  'util'           ,
  'varray'         ,
  'pcre'           ,
  'py_mtypes'      ,
  'py_types'       ,
  'py_exceptions'  ,
  'py_string'      ,
  'py_parse'       ,
  'py_keywords'    ,
  'py_lex'         ,
  'py_lex1'        ,
  'py_pretok'      ,
  'py_tok'         ,
  'py_module_file' ,
  'py_functions'   ,
  'py_dict'        ,
  'py_module'      ,
  'py_class'       ,
  'py_function'    ,
  'py_env'         ,
  'py_print'       ,
  'py_exec_module' ,
  'py_util'        ,
  'py_printf'      ,
  'py_datum'       ,
  'py_param'       ,
  'py_exec'        ,
  'py_bind'        ,
  'py_builtins_util',
  'py_file'         ,
  'py_list_methods' ,
  'py_dict_methods' ,
  'py_string_methods' ,
  'py_marshal'      ,
  'py_struct'       ,
  'py_pcre'         ,
  'py_posix'        ,
  'py_time'         ,
  'py_gdk'     ,
  'py_gtk'     ,
  'py_builtins'     ,
  'py_sys'         ,
  'py_interp'
]

IMPLEMENTATIONS = [
  'glib'            ,
  'gdk'             ,
  'gtk'             ,
  'util'            ,
  'varray'          ,
  'pcre'            ,
  'py_mtypes'       ,
  'py_exceptions'   ,
  'py_string'       ,
  'py_parse'        ,
  'py_keywords'     ,
  'py_lex'          ,
  'py_lex1'         ,
  'py_pretok'       ,
  'py_tok'          ,
  'py_module_file'  ,
  'py_functions'    ,
  'py_dict'         ,
  'py_module'       ,
  'py_class'        ,
  'py_function'     ,
  'py_env'          ,
  'py_print'        ,
  'py_exec_module'  ,
  'py_util'         ,
  'py_printf'       ,
  'py_datum'        ,
  'py_param'        ,
  'py_exec'         ,
  'py_bind'         ,
  'py_builtins_util',
  'py_file'         ,
  'py_list_methods' ,
  'py_dict_methods' ,
  'py_string_methods' ,
  'py_marshal'      ,
  'py_struct'       ,
  'py_pcre'         ,
  'py_posix'        ,
  'py_time'         ,
  'py_gdk'          ,
  'py_gtk'          ,
  'py_builtins'     ,
  'py_sys'          ,
  'py_interp'
]

f = os.popen("gtk-config --cflags")
GTK_CFLAGS = string.strip(f.readline())
f.close()

f = os.popen("gtk-config --version")
GTK_VERSION = string.split(f.readline(),'.')
f.close()

if GTK_VERSION[0] <> '1':
  print "UNKNOWN GTK VERSION",GTK_VERSION
  raise MakeError

if GTK_VERSION[1] != '2':
  print "GTK VERSION 1.2 REQUIRED"
  raise MakeError

COBJECTS = {
  'gnu_readline'    : '-DHAVE_GNU_READLINE -I /usr/include/readline',
  'pcre_intf'       : '',
  'cpcre'           : '',
  'study'           : '',
  'get'             : '',
  'chartables'      : '',
  'maketables'      : '',
  'mlglib_stub'     : GTK_CFLAGS,
  'mlgdk_stub'      : GTK_CFLAGS,
  'mlgtk_stub'      : GTK_CFLAGS 
}

EXES = [
  'viperi',
  'viparse',
  'vilex'
]

# ----------- Utilities ---------------------
class MakeError: pass

def filetime(f):
  try:
    return os.stat(f)[stat.ST_MTIME]
  except: return 0

def xqt(x):
  print x
  sys.stdin.flush()
  f = os.popen("{ " +x+ " } 2>&1","r")
  output = f.readlines()
  result = f.close()
  if result: print "  .. ERROR CODE",result
  if output: print string.join(output,"")
  sys.stdin.flush()

  if result:
    raise MakeError

# ----------- Here begins the actual build procedure ---------------------

buildall = 0

try:
  for cobject in COBJECTS.keys():
    flags = COBJECTS[cobject]
    if buildall or filetime(cobject+".c") > filetime(cobject+".o"):
      xqt("gcc -c -O2 -I /usr/local/lib/ocaml -I. "+flags+" "+cobject+".c")

  for lex in LEXS:
    if buildall or filetime(lex + '.mll') > filetime(lex+'.ml'):
      buildall = 1
      xqt('ocamllex '+ lex + '.mll')

  for parse in PARSES:
    if buildall or filetime(parse + '.mly') > filetime(parse+'.ml'):
      buildall = 1
      xqt('ocamlyacc '+ parse+ '.mly')

  for interface in INTERFACES:
    if buildall or filetime(interface+ '.mli') > filetime(interface+'.cmi'):
      buildall = 1
      xqt(OCAMLC + ' -c '+interface + '.mli')

  for implementation in IMPLEMENTATIONS:
    if buildall or filetime(implementation + '.ml') > filetime(implementation+'.cmx'):
      buildall = 1
      xqt(OCAMLOPT + ' -c ' + implementation+'.ml')
    

  linkstring = OCAMLOPT + " -a -o viperlib.cmxa "
  for implementation in IMPLEMENTATIONS:
    linkstring = linkstring + implementation + ".cmx "
  xqt(linkstring)

  # *.so/.a libraries
  CLIBRARIES = ['readline','unix','nums','threadsnat', 'pthread']

  # *.cmxa libraries
  OLIBRARIES = ['unix','nums','threads','viperlib']

  f = os.popen("gtk-config --libs")
  GTK_LDFLAGS = string.split(f.readline())
  f.close()
  
  s = ' -cclib "-L.'
  for library in CLIBRARIES:
    s = s + ' -l'+library
  for ldflag in GTK_LDFLAGS:
    s = s + ' '+ ldflag
  s = s + '"'

  x = ''
  for library in OLIBRARIES:
    x = x + ' ' + library + '.cmxa'

  o = ''
  for object in COBJECTS.keys():
    o = o + ' ' + object + '.o'

  # finally, mainline *.ml files to link to executables
  for exe in EXES:
    xqt(OCAMLOPT + s + ' -o '+exe + x + o + ' ' + exe + '.ml')

except MakeError:
  print "Terminating due to error"

