Import('env', 'brushlib')
import sys, os
import subprocess

# Use a copy of the environment so new flags can be added
# without affecting the other builds.
mypaintlib_env = env.Clone()
env = mypaintlib_env

def build_py_module(env, *args, **kwargs):
    if sys.platform == "win32": # there 's a better way to do this
        kwargs["SHLIBSUFFIX"]=".pyd"
    elif sys.platform == "msys" and os.environ.get("MSYSTEM") != "MSYS":
        kwargs["SHLIBSUFFIX"]=".pyd"
    elif sys.platform == "darwin":
        kwargs["SHLIBSUFFIX"]=".so"
    else:
        pass
    return env.SharedLibrary(*args, **kwargs)


# Build against brushlib
env.Prepend(LIBS=['mypaint-tests', "mypaint"])
env.Append(LIBPATH="../brushlib")
env.Append(CPPPATH=['../brushlib', '../brushlib/tests'])


def parse_pkg_config(env, libname):
    """Wraps env.ParseConfig(), adding some MSYS2-specific fixes."""
    extras = ""
    if (sys.platform == "msys" and os.environ.get("MSYSTEM") != "MSYS"):
        # Building from MINGW32 or MINGW64, but using MSYS scons.
        # Paths will have drive letters & mess up scons's os.path.join()s
        # unless we do this:
        extras += " --dont-define-prefix"
    cmd = "pkg-config --cflags --libs {libname} {extras}".format(
        libname = libname,
        extras = extras,
    )
    env.ParseConfig(cmd)


def fixup_abspath(path):
    """Fixes up absolute directory paths.

    This fixes up absolute paths when using MSYS2's MSYS-scons to build
    from the MINGW32 or MINGW64 environments.
    It does what --dont-define-prefix does for pkg-config,
    specifically 'C:/msys64/mingw32/foo' -> '/mingw32/foo'.
    Both of these are paths to the same thing on this platform.

    """
    assert os.path.isabs(path)
    if sys.platform == "msys" and os.environ.get("MSYSTEM") != "MSYS":
        # Building from MINGW32 or MINGW64, but using MSYS scons.
        # Note that os.path.splitdrive doesn't work on msys
        # though isabs *does* work for paths with drive letters.
        trail = []
        p, q = os.path.split(path)
        while q:
            trail.insert(0, q)
            p, q = os.path.split(p)
        # Check for a drive letter
        if not (trail[0].endswith(":") and len(trail[0]) == 2):
            return path
        # Drop parts from the front of the path
        # until the dropped part is the same thing as Cygwinish "/".
        # The remainder, expressed as absolute,
        # will be a good path for (mingw) gcc,
        # and one that msys-scons can understand.
        for i in range(1, len(trail)):
            p = os.path.join(*trail[0:i])
            if not os.path.exists(p):
                continue
            if os.path.samefile("/", p):
                q = os.path.join("/", *trail[i:])
                return q
        return path
    else:
        return path

# Normal dependencies
parse_pkg_config(env, "glib-2.0")
parse_pkg_config(env, "libpng")
parse_pkg_config(env, "lcms2")
parse_pkg_config(env, "pygobject-3.0")
parse_pkg_config(env, "gtk+-3.0")

env.Append(CPPDEFINES=['HAVE_GTK3']) # possibly useful while we're porting

if env['enable_openmp']:
    env.Append(CXXFLAGS=['-fopenmp'])
    env.Append(LINKFLAGS=['-fopenmp'])


# Get the numpy include path (for <numpy/arrayobject.h>).
# First, always allow the user to override it with an option.

numpy_path = None
if env.get("numpy_include"):
    numpy_path = env["numpy_include"]

# Next, try to invoke the target Python binary and its installed numpy.
# This supports Linux/POSIX just fine. It also supports using the
# MSYS2's MSYS platform's scons for MINGW32 (native Win32) builds up to
# a point. However the assumptions made by the rest of SCons prevents us
# using MSYS scons in practice. The native Windows *absolute* path
# syntax (with drive letters) resembles POSIX/CygWin *relative* path
# syntax too much, causing os.path.join() to fail.

if not numpy_path:
    numpy_cfg_py = "import numpy; print numpy.get_include()"
    try:
        numpy_path = subprocess.check_output([
            env["python_binary"],
            "-c",
            numpy_cfg_py,
        ])
    except:
        numpy_path = None
    else:
        numpy_path = numpy_path.rstrip("\r\n")

# There may be strange builds out there that don't have a target Python
# binary yet at the time of compilation, but for which using the local
# Python binary and its numpy would do. Try that, very much as a last
# resort.

if not numpy_path:
    try:
        import numpy
        numpy_path = numpy.get_include()
    except:
        numpy_path = None

if not numpy_path:
    print (
        "\n"
        "Failed to autodetect the NumPy include path.\n"
        "You need to have NumPy installed.\n"
        "Set numpy_include=ABSPATH to override our autodetections, where\n"
        "ABSPATH is the absolute location of your <numpy/arrayobject.h>\n"
    )
    sys.exit(2)
else:
    env.Append(CPPPATH=fixup_abspath(numpy_path))


# Python dependencies


try:
    # As of Python 2.7.9, a python2.pc exists on both Linux
    # and MSYS2's MinGW/i686. In the latter case, only this provides
    # the correct flags.
    parse_pkg_config(env, "python2")
except OSError:
    # Older methods, and degenerate cases? Maybe we should get rid of these.
    if sys.platform == "win32":
        # official python shipped with no pc file on windows so get
        # from current python
        from distutils import sysconfig
        pre,inc = sysconfig.get_config_vars('exec_prefix', 'INCLUDEPY')
        env.Append(
            CPPPATH=inc,
            LIBPATH=pre+'\libs',
            LIBS='python'+sys.version[0]+sys.version[2],
        )
    else:
        # Some distros use python2.x-config, others python-config2.x
        try:
            env.ParseConfig(env['python_config'] + ' --cflags')
            env.ParseConfig(env['python_config'] + ' --ldflags')
        except OSError:
            print ('%r does not work, trying python-config instead'
                   % env['python_config'])
            env.ParseConfig('python-config --ldflags')
            env.ParseConfig('python-config --cflags')

build_def = (
    sys.platform == "win32"
    or (sys.platform == "msys" and os.environ.get("MSYSTEM") != "MSYS")
)
if build_def:
    # scons ask export definition file during install
    # seems always generated for VC++ but not for mingw/gcc
    env.Append(LINKFLAGS=['-Wl,--output-def,_mypaintlib.def'])
    env.Clean('.', ['_mypaintlib.def', '../_mypaintlib.def'])

# Reenable some build flags that python-config etc. may have turned off.
# Duplicates some stuff from ../SConstruct, but needed.

# Make sure assertions are enabled

if 'NDEBUG' in env.get('CPPDEFINES', []):
    env['CPPDEFINES'].remove('NDEBUG')

# Override Python's optimization flags if we're in HEAVY_DEBUG mode.
if env['debug']:
    env.Append(CCFLAGS='-O0', LINKFLAGS='-O0')


# python extension module

env.Append(SWIGFLAGS="-Wall -noproxydel -python -c++")
#env.Append(SWIGCXXFILESUFFIX="_wrap.cpp") #No: SCons 2.3.1 removes ".ext" (!)
module_src = [
        'mypaintlib.i',
        'fill.cpp',
        'eventhack.cpp',
        'gdkpixbuf2numpy.cpp',
        'pixops.cpp',
        'fastpng.cpp',
    ]
module = build_py_module(
    env,
    target='#_mypaintlib',
    source=module_src,
    SHLIBPREFIX="",
    )
env.Requires("mypaintlib_wrap.cc", brushlib)  # establish order
env.Requires(module, brushlib)  # just to be certain
env.Depends(module, brushlib)   # not sufficient by itself

Return('module')

# vim:syntax=python
