import libtbx.load_env
import libtbx.config
from libtbx.path import norm_join
import sys, os

def SCons_Action_FunctionAction_get_contents(self, target, source, env,
                                                   dict=None):
  import cPickle, string
  code = cPickle.dumps(self.execfunction)
  return str(code) + env.subst(string.join(map(lambda v: '${'+v+'}',
                                               self.varlist)))
if (1):
  import SCons.Action
  SCons.Action.FunctionAction.get_contents = \
  SCons_Action_FunctionAction_get_contents

class empty: pass

def set_python_include_and_libs(env_etc):
  env_etc.python_include = libtbx.config.python_include_path()
  if (sys.platform == "win32"):
    env_etc.libs_python = ["python" + sys.version[0] + sys.version[2]]
    env_etc.libpath_python = [sys.prefix + r"\libs"]
  elif (env_etc.compiler == "tru64_cxx"):
    env_etc.libs_python = ["pthread"]
    env_etc.libpath_python = []
  else:
    env_etc.libs_python = []
    env_etc.libpath_python = []
  if (env_etc.compiler.startswith("darwin_")):
    env_etc.python_framework = "/".join(
      env_etc.python_include.split("/")[:-2] + ["Python"])

def darwin_framework_path():
  return os.sep.join(os.path.realpath(sys.executable).split(os.sep)[:-5])

env_etc = empty()
env_etc.no_boost_python = ARGUMENTS.get("no_boost_python", 0)
env_etc.norm_join = norm_join
env_etc.darwin_framework_path = darwin_framework_path

env_etc.include_registry = libtbx.config.include_registry() \
  .scan_boost(flag=libtbx.env.build_options.scan_boost)

compiler = libtbx.env.build_options.compiler
if (sys.platform == "win32"):
  env_etc.compiler = "win32_cl"
elif (sys.platform.startswith("sunos")):
  if (compiler == "default"):
    env_etc.compiler = "sunos_CC"
  else:
    env_etc.compiler = "unix_"+compiler
    compiler = None
elif (sys.platform.startswith("osf")):
  if (compiler == "default"):
    env_etc.compiler = "tru64_cxx"
  else:
    env_etc.compiler = "unix_"+compiler
    compiler = None
elif (sys.platform.startswith("irix")):
  if (compiler == "default"):
    env_etc.compiler = "irix_CC"
  else:
    env_etc.compiler = "unix_"+compiler
    compiler = None
elif (sys.platform.startswith("darwin")):
  if (compiler == "default"):
    env_etc.compiler = "darwin_c++"
  else:
    env_etc.compiler = "darwin_"+compiler
    compiler = None
elif (os.name == "posix"):
  if (compiler == "default"):
    env_etc.compiler = "unix_gcc"
  else:
    env_etc.compiler = "unix_"+compiler
    compiler = None
if (compiler not in ("default", None)):
  sys.tracebacklimit = 0
  raise RuntimeError("Compiler not supported on this platform: %s" % compiler)
supported_compilers = (
  "win32_cl",
  "sunos_CC",
  "unix_gcc",
  "unix_ecc",
  "unix_icc",
  "unix_icpc",
  "tru64_cxx",
  "irix_CC",
  "darwin_c++",
  "darwin_gcc",
)
if (not env_etc.compiler in supported_compilers):
  sys.tracebacklimit = 0
  raise RuntimeError("Unknown platform/compiler: %s. Choices are: %s" % (
    env_etc.compiler, ", ".join(supported_compilers)))

static_exe = libtbx.env.build_options.static_exe

if (sys.platform == "win32"):
  env_etc.static_libraries = 1
  env_etc.static_bpl = 0
  env_base = Environment(ENV=os.environ)
  set_python_include_and_libs(env_etc)
  env_etc.extension_module_suffix = ".pyd"
  if (env_etc.compiler == "win32_cl"):
    env_base.Replace(
      SHCC="cl",
      SHCXX="cl",
      SHLINK="link",
    )
    env_etc.cxxflags_base = Split("""
        /nologo
        /MD
        /GR /GX
        /Zm800
        /DBOOST_DISABLE_THREADS
    """)
    env_etc.ccflags_base = Split("""
        /nologo
        /MD
        /Zm800
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["/DNDEBUG", "/Ox"]
    else:
      opts = ["/Od"]
    if (libtbx.env.build_options.debug_symbols):
      sys.tracebacklimit = 0
      raise RuntimeError("Debug build not supported.")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    env_etc.shlinkflags = "/nologo /incremental:no /dll"
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
    env_etc.libm = []
  else:
    sys.tracebacklimit = 0
    raise RuntimeError("Unknown compiler choice: %s" % env_etc.compiler)
else:
  env_base = Environment(
    ENV=os.environ,
    tools=['gcc','g++','gnulink','ar'])
  set_python_include_and_libs(env_etc)
  env_etc.extension_module_suffix = ".so"
  env_etc.libm = ["m"]
  if (env_etc.compiler == "tru64_cxx"):
    env_etc.static_libraries = 0
    env_etc.static_bpl = 0
    cxx = "cxx"# -model ansi"
    env_base.Replace(
      CC="cc",
      SHCC="cc",
      CXX=cxx,
      LINK=cxx,
      SHCXX=cxx,
      SHLINK=cxx,
    )
    env_etc.cxxflags_base = Split("""
        -std strict_ansi
        -msg_display_number -msg_disable 186,450,1115,1133
        -tlocal
        -DBOOST_DISABLE_THREADS
    """)
    env_etc.ccflags_base = Split("""
        -std1
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O2", "-fast"]
    else:
      opts = ["-O0"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    if (static_exe):
      env_base.Prepend(LINKFLAGS=["-non_shared"])
      static_exe = None
    env_etc.shlinkflags = "-shared -expect_unresolved 'Py*'" \
                        + " -expect_unresolved '_Py*'"
    for line in os.popen4("strings /usr/bin/ld")[1].read().splitlines():
      if (line == "lock_registry"):
        env_etc.shlinkflags += " -Wl,-lock_registry"
        break
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
  elif (env_etc.compiler == "sunos_CC"):
    env_etc.static_libraries = 0
    env_etc.static_bpl = 0
    # boost compilation fails under Sun compilers (M.D. Winn, 2005 Oct)
    env_etc.no_boost_python = 1
    cxx = "CC"
    env_base.Replace(
      CC="cc",
      SHCC="cc",
      CXX=cxx,
      LINK=cxx,
      SHCXX=cxx,
      SHLINK=cxx,
    )
    env_etc.cxxflags_base = Split("""
    """)
    env_etc.ccflags_base = Split("""
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["-O"]
    else:
      opts = ["-O0"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    if (static_exe):
      env_base.Prepend(LINKFLAGS=[""])
      static_exe = None
    env_etc.shlinkflags = "-shared -expect_unresolved 'Py*'" \
                        + " -expect_unresolved '_Py*'"
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
  elif (env_etc.compiler == "unix_gcc"):
    env_etc.static_libraries = 0
    env_etc.static_bpl = 0
    env_base.Replace(
      CC="gcc",
      SHCC="gcc",
      CXX="g++",
      LINK="g++",
      SHCXX="g++",
      SHLINK="g++",
    )
    env_etc.cxxflags_base = Split("""
      -fPIC
      -ftemplate-depth-120
      -w
      -DBOOST_DISABLE_THREADS
    """)
    env_etc.ccflags_base = Split("""
      -fPIC
      -w
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O3", "-ffast-math"]
    else:
      opts = ["-O0", "-fno-inline"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    if (static_exe):
      env_base.Prepend(LINKFLAGS=["-static"])
      static_exe = None
    env_etc.shlinkflags = "-shared"
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
  elif (env_etc.compiler == "unix_ecc"):
    env_etc.static_libraries = 0
    env_etc.static_bpl = 0
    env_base.Replace(
      CC="ecc",
      SHCC="ecc",
      CXX="ecc",
      LINK="ecc",
      SHCXX="ecc",
      SHLINK="ecc",
    )
    env_etc.cxxflags_base = Split("""
      -fPIC
      -DBOOST_DISABLE_THREADS
    """)
    env_etc.ccflags_base = Split("""
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O", "-tpp2", "-ip", "-ftz"]
    else:
      opts = ["-O0"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    env_etc.shlinkflags = "-shared"
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
  elif (env_etc.compiler == "unix_icc"):
    env_etc.static_libraries = 0
    env_etc.static_bpl = 0
    env_base.Replace(
      CC="icc",
      SHCC="icc",
      CXX="icc",
      LINK="icc",
      SHCXX="icc",
      SHLINK="icc",
    )
    env_etc.cxxflags_base = Split("""
      -fPIC
      -DBOOST_DISABLE_THREADS
    """)
    env_etc.ccflags_base = Split("""
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O2"]
    else:
      opts = ["-O0"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    env_etc.shlinkflags = "-shared"
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
  elif (env_etc.compiler == "unix_icpc"):
    # support for CCP4 build, submitted by Charles Ballard
    env_etc.static_libraries = 0
    env_etc.static_bpl = 0
    env_base.Replace(
      CC="icc",
      SHCC="icc",
      CXX="icpc",
      LINK="icpc",
      SHCXX="icpc",
      SHLINK="icpc",
    )
    env_etc.cxxflags_base = Split("""
      -fPIC
      -DBOOST_DISABLE_THREADS
    """)
    env_etc.ccflags_base = Split("""
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O2"]
    else:
      opts = ["-O0"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    env_etc.shlinkflags = "-shared"
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
  elif (env_etc.compiler == "irix_CC"):
    mipspro_version = libtbx.config.get_mipspro_version()
    env_etc.static_libraries = 0
    env_etc.static_bpl = 0
    cxx = "CC -n32 -mips4 -LANG:std"
    cxx += " -LANG:pch=OFF -no_prelink -ptused"
    env_base.Replace(
      CC="cc",
      SHCC="cc",
      CXX=cxx,
      LINK=cxx+" -LD_MSG:off=15,84",
      SHCXX=cxx,
      SHLINK=cxx,
    )
    if (mipspro_version == "73"):
      env_etc.cxxflags_base = [
        "-woff", "1001,1183,1188,1234,1311,1682,3439"]
    else:
      env_etc.cxxflags_base = [
        "-woff", "1001,1174,1183,1188,1234,1311,1682,3439,3506"]
    if (mipspro_version == "73" and libtbx.env.module_dict.has_key("boost")):
      env_etc.cxxflags_base.insert(0,
        "-I%s/boost/compatibility/cpp_c_headers"
        % libtbx.env.dist_path("boost"))
    env_etc.cxxflags_base.append("-DBOOST_DISABLE_THREADS")
    env_etc.ccflags_base = []
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O2", "-OPT:Olimit=0"]
    else:
      opts = ["-O0"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    if (static_exe):
      env_base.Prepend(LINKFLAGS=["-non_shared"])
      static_exe = None
    env_etc.shlinkflags = ["-shared", "-LD_MSG:off=15,84"]
    env_etc.shlinkflags_bpl = env_etc.shlinkflags
  elif (env_etc.compiler == "darwin_gcc"):
    env_etc.static_libraries = 1
    env_etc.static_bpl = 0
    env_base.Replace(
      CC="gcc",
      SHCC="gcc",
      CXX="g++",
      LINK="g++",
      SHCXX="g++",
      SHLINK="g++",
      SHLIBSUFFIX=".dylib",
    )
    env_base.Append(LIBSUFFIXES=[".dylib"])
    env_etc.cxxflags_base = Split("""
      -fPIC
      -ftemplate-depth-130
      -w
      -DBOOST_DISABLE_THREADS
    """)
    env_etc.ccflags_base = Split("""
      -w
    """)
    cxx_version = os.popen("c++ -dumpversion").read().strip()
    cxx_major = cxx_version.split(".")[:1]
    if (len(cxx_major) == 1):
      try: cxx_major = int(cxx_major[0])
      except ValueError: pass
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O3", "-ffast-math"]
      if (cxx_version == "4.0.0"):
        opts[1] = "-O2" # Apple's optimizer is broken
    else:
      opts = ["-O0", "-fno-inline"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    env_etc.shlinkflags = []
    env_etc.shlinkflags_bpl = [
      "-w", # for some odd reason -bundle cannot be the first option
      "-bundle",
      "-F"+darwin_framework_path(),
      "-framework", "Python"]
    if (static_exe):
      # no action required
      static_exe = None
  elif (env_etc.compiler == "darwin_c++"):
    env_etc.static_libraries = 1
    env_etc.static_bpl = 0
    env_base.Replace(
      CC="cc",
      SHCC="cc",
      CXX="c++",
      LINK="c++",
      LINKFLAGS=["-w"], # suppress "source/lib does not exist" warning
      SHCXX="c++",
      SHLINK="c++",
      SHLIBSUFFIX=".dylib",
    )
    env_base.Append(LIBSUFFIXES=[".dylib"])
    env_etc.cxxflags_base = Split("""
      -fPIC
      -no-cpp-precomp
      -ftemplate-depth-130
      -fcoalesce-templates
      -Wno-long-double
      -w
      -DBOOST_DISABLE_THREADS
    """)
    cxx_version = os.popen("c++ -dumpversion").read().strip()
    cxx_major = cxx_version.split(".")[:1]
    if (len(cxx_major) == 1):
      try: cxx_major = int(cxx_major[0])
      except ValueError: pass
      else:
        if (cxx_major > 3):
          env_etc.cxxflags_base.remove("-fcoalesce-templates")
    env_etc.ccflags_base = Split("""
      -fPIC
      -no-cpp-precomp
      -Wno-long-double
      -w
    """)
    if (libtbx.env.build_options.optimization):
      opts = ["-DNDEBUG", "-O3", "-ffast-math"]
      if (cxx_version == "4.0.0"):
        opts[1] = "-O2" # Apple's optimizer is broken
    else:
      opts = ["-O0", "-fno-inline"]
    if (libtbx.env.build_options.debug_symbols):
      opts.insert(0, "-g")
    env_etc.cxxflags_base.extend(opts)
    env_etc.ccflags_base.extend(opts)
    env_etc.shlinkflags = []
    env_etc.shlinkflags_bpl = [
      "-w", # suppress "source/lib does not exist" warning
      "-bundle",
      "-F"+darwin_framework_path(),
      "-framework", "Python"]
    if (static_exe):
      # no action required
      static_exe = None
  else:
    sys.tracebacklimit = 0
    raise RuntimeError("Unknown compiler choice: %s" % env_etc.compiler)

env_base["SHOBJSUFFIX"] = env_base["OBJSUFFIX"]

if (static_exe):
  sys.tracebacklimit = 0
  raise RuntimeError("Static executables not supported on this platforms.")

if (env_etc.static_libraries == 0
    and libtbx.env.build_options.static_libraries):
  env_etc.static_libraries = 1
env_etc.static_exe = libtbx.env.build_options.static_exe

env_etc.libtbx_build = libtbx.env.build_path
env_etc.libtbx_include = libtbx.env.under_build("include")
env_etc.libtbx_lib = libtbx.env.lib_path

Export("env_base", "env_etc")
