#!/usr/bin/python
# Project: Soar <http://soar.googlecode.com>
# Author: Jonathan Voigt <voigtjr@gmail.com>
#
import sysconfig
import os
import os.path
import sys

Import('env')
clone = env.Clone()
clone['SWIGPATH'] = clone['CPPPATH']
clone['SWIGFLAGS'] = ['-c++', '-python']
if GetOption('nosvs'):
    clone['SWIGFLAGS'].append('-DNO_SVS')
python_sml_alias = clone['SML_PYTHON_ALIAS']

inc_path = sysconfig.get_path('include')
if os.name == 'nt':
    lib_path = [
        os.path.join(sysconfig.get_config_vars('BINDIR')[0], 'libs'),
        # Finds the correct library path for Github Runner environments (cibuildwheel)
        os.path.join(sysconfig.get_config_vars('LIBDEST')[0], '..\\libs'),
    ]
    pylib = 'python' + sysconfig.get_config_vars('VERSION')[0]
else:
    lib_path = sysconfig.get_config_vars('LIBDIR')[0]
    pylib = sysconfig.get_config_vars('LIBRARY')[0]
lib_install_dir = clone['OUT_DIR']

clone.Append(CPPPATH = inc_path)

# linux: manylinux containers do not ship with python's libraries:
#  https://github.com/pypa/manylinux/issues/191#issuecomment-386489125
# macos: python libraries (only their executables) do not appear to be present when installing python on
#  GHA Runners. (python installations are handled by cibuildwheel)
#
# Omitting python's libraries is safe, as python itself injects its symbols when importing the library.
if (not env['ENSCONS_ACTIVE']):
    clone.Append(LIBPATH = lib_path, LIBS = pylib)
elif os.name == 'nt':
    # For windows specifically, we need to give it a path to find 'python3.lib',
    # without linking it against 'python3X' (with X being the minor version).
    clone.Append(LIBPATH = lib_path)

if os.name == 'posix':
    clone.Append(CPPFLAGS = Split('-Wno-unused -fno-strict-aliasing'))

if sys.platform == 'darwin':
    clone.Replace(SHLINKFLAGS = Split('$LINKFLAGS -bundle -flat_namespace -undefined suppress'))
    clone.Replace(SHLIBSUFFIX = ['.so'])

name = 'Python_sml_ClientInterface'
interface = env.File(name + '.i')
source = env.File(name + '.py')

if os.name == 'nt':
    # the [:1] at the end throws away the .exp and .lib files that are generated
    shlib = clone.SharedLibrary(name, interface, SHLIBPREFIX = '_', SHLIBSUFFIX = '.pyd')[:1]
else:
    shlib = clone.SharedLibrary(name, interface, SHLIBPREFIX = '_')
install_source = env.Install(lib_install_dir, source)
install_lib = env.Install(lib_install_dir, shlib)
install_test = env.Install(lib_install_dir, env.File('TestPythonSML.py'))

if "SOAR_PYTHON_ABI3" in env["ENV"]:
    if env.get('PY_ABI3_VERSION', None) is None:
        print("SOAR_PYTHON_ABI3 requested, but PY_ABI3_VERSION was not defined in env, aborting.", file=sys.stderr)
        Exit(1)
    elif not isinstance(env["PY_ABI3_VERSION"], tuple) or len(env["PY_ABI3_VERSION"]) != 2:
        print("PY_ABI3_VERSION malformed, expected 2-tuple.", file=sys.stderr)
        Exit(1)
    elif env["PY_ABI3_VERSION"] < (3, 2):
        print("PY_ABI3_VERSION below supported version for ABI3", file=sys.stderr)
        Exit(1)

    # Only SWIG 4.2.0 added Python Limited API support:
    # https://github.com/swig/swig/issues/1009
    if env["SWIG_VERSION"] >= (4, 2, 0):
        print("SOAR_PYTHON_ABI3 defined, building Python Limited API...")
        # Signal to enscons that we're building the limited API
        # also deconstruct (major, minor) tuple
        major, minor = env["LIMITED_API_TARGET"] = env["PY_ABI3_VERSION"]

        # CPP Definition constructed from the minor/major ABI3 version parts
        api_version = (0x1000000 * major) + (0x10000 * minor)

        # Signal to the .i file that we're building the limited API
        clone.Append(CPPDEFINES = { 'Py_LIMITED_API': api_version })
    else:
        print("'Requested building Python SML bindings with Python's Limited API, "
              f"but SWIG does not support it (need 4.2.0, have {'.'.join(env['SWIG_VERSION'])}); aborting.'", file=sys.stderr)
        Exit(1)
else:
    print("SOAR_PYTHON_ABI3 not defined, building Python SML bindings with full (less portable) Python API...")

# We add soarlib to the python_sml explicitly, as some operating systems don't pick up on this dependency,
# and crash the build.
Import('soarlib')

env.Alias(python_sml_alias, soarlib + install_lib + install_source + install_test)

python_shlib = shlib
python_source = source
Export('python_shlib')
Export('python_source')
