# Copyright 2020 Google, Inc.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import copy
import os

main = Environment()

gem5_root = Dir('..').Dir('..')

# Includes which are shared with gem5 itself.
common_include = gem5_root.Dir('include')

ext_dir = gem5_root.Dir('ext')
googletest_dir = ext_dir.Dir('googletest')

src_dir = Dir('src')
build_dir = Dir('build')

main.SConsignFile(build_dir.File("sconsign").abspath)

def abspath(d):
    return os.path.abspath(str(d))

AddOption('--debug-build', dest='debug_build', action='store_true',
          help='Build with debug info, and disable optimizations.')
AddOption('--run-tests', dest='run_tests', action='store_true',
          help='Enable test output xml files as build targets.')
AddOption('--verbose', dest='verbose', action='store_true')

# Universal settings.
if GetOption('debug_build'):
    main.Append(CXXFLAGS=[ '-O0', '-g' ])
    main.Append(CCFLAGS=[ '-O0', '-g' ])
else:
    main.Append(CXXFLAGS=[ '-O2' ])
    main.Append(CCFLAGS=[ '-O2' ])
main.Append(CPPPATH=[ common_include ])
main.Append(CXXFLAGS=[ '-std=c++14' ])

if not GetOption('verbose'):
    # A functor which returns a shorter summary string to replace the normal
    # scons output when running a command.
    class ComStr(object):
        def __init__(self, cmd):
            self.cmd = cmd

        def __call__(self, target, source, env, for_signature=None):
            tgts = list([str(t).strip() for t in target])
            return self.cmd + ' ' + ', '.join(tgts)
    main['CXXCOMSTR'] = ComStr('CXX')
    main['SHCXXCOMSTR'] = ComStr('SHCXX')
    main['CCCOMSTR'] = ComStr('CC')
    main['SHCCCOMSTR'] = ComStr('SHCC')
    main['LINKCOMSTR'] = ComStr('LINK')
    main['SHLINKCOMSTR'] = ComStr('SHLINK')
    main['ASCOMSTR'] = ComStr('AS')
    main['ASPPCOMSTR'] = ComStr('ASPP')
    main['ARCOMSTR'] = ComStr('AR')
    main['RANLIBCOMSTR'] = ComStr('RANLIB')
    main['JARCOMSTR'] = ComStr('JAR')

    def MakeAction(action, string, *args, **kwargs):
        def func(target, source, env, executor):
            tgts = list([str(t).strip() for t in target])
            return string + ' ' + ', '.join(tgts)
        return Action(action, func, *args, **kwargs)
else:
    def MakeAction(action, string, *args, **kwargs):
        return Action(action, *args, **kwargs)

# Propogate the environment's PATH setting.
main['ENV']['PATH'] = os.environ['PATH']
# Pass through terminal information to, for instance, enable color output.
if 'TERM' in os.environ:
    main['ENV']['TERM'] = os.environ['TERM']
# Pass through the java CLASSPATH (if it exists) so we can find libraries.
main['ENV']['CLASSPATH'] = os.environ.get('CLASSPATH', '')

# Detect some dependencies of some forms of the m5 utility/library.
def CheckForJavaPkg(context, pkg_name):
    context.Message('Checking for java package %s...' % pkg_name)
    result = main['HAVE_JAVA'] and \
             context.TryAction('${JAVAC} ${JAVACFLAGS} ${SOURCES}',
                               'import %s.*;' % pkg_name, '.java')[0]
    context.Result(result)
    return result

def CheckForPkgConfigPackage(context, package):
    context.Message('Checking for pkg-config package %s...' % package)
    result = main['HAVE_PKG_CONFIG'] and \
             os.system('pkg-config --exists %s' % package) == 0
    context.Result(result)
    return result;

conf = Configure(main, conf_dir=build_dir.Dir('.scons_config'),
        log_file=build_dir.File('scons_config.log'), custom_tests={
        'CheckForJavaPkg' : CheckForJavaPkg,
        'CheckForPkgConfigPackage' : CheckForPkgConfigPackage
})
main['HAVE_JAVA'] = all(key in main for key in ('JAVAC', 'JAR'))
if not main['HAVE_JAVA']:
    print('javac and/or jar not detected, not building java wrapper.')

main['HAVE_JUNIT'] = conf.CheckForJavaPkg('org.junit')
if main['HAVE_JAVA'] and not main['HAVE_JUNIT']:
    print('junit test framework not found, not build java wrapper test')

main['HAVE_PKG_CONFIG'] = conf.CheckProg('pkg-config')
if not main['HAVE_PKG_CONFIG']:
    print("pkg-config not detected, can't check for lua51.")

main['HAVE_LUA51'] = conf.CheckForPkgConfigPackage('lua51')
if not main['HAVE_LUA51']:
    print('lua 5.1 not detected, not building lua wrapper.')

conf.Finish()

# Put the sconsign file in the build dir so everything can be deleted at once.
main.SConsignFile(os.path.join(abspath(build_dir), 'sconsign'))
# Use soft links instead of hard links when setting up a build directory.
main.SetOption('duplicate', 'soft-copy')

def GTest(env, name, *srcs, **kwargs):
    if 'GTEST_ENV' not in env:
        gtest_env = env.Clone(OBJSUFFIX='.to', SHOBJSUFFIX='.sto')
        gtest_env.Append(CPPFLAGS=[ '${GTEST_CPPFLAGS}' ])
        gtest_env.Append(LIBS=[ '${GTEST_LIBS}' ])
        env['GTEST_ENV'] = gtest_env

    if not srcs:
        srcs = [ name + '.cc', name + '.test.cc' ]
    test_bin = env['GTEST_ENV'].Program('test/bin/%s' % name, srcs, **kwargs)

    # The native environment doesn't need QEMU, and doesn't define HAVE_QEMU.
    need_qemu_to_run = 'HAVE_QEMU' in env;

    # If we can run this test...
    if GetOption('run_tests') and (not need_qemu_to_run or env['HAVE_QEMU']):
        # An XML file which holds the results of the test.
        xml = Dir('test').Dir('result').File('%s.xml' % name)
        # The basic command line for the test.
        cmd = '${SOURCES[0]} --gtest_output=xml:${TARGETS[0]}'
        cmd_str = 'TEST'
        if need_qemu_to_run:
            # A prefix that runs it in QEMU if necessary.
            cmd = '${QEMU} -L ${QEMU_SYSROOT} -- ' + cmd
            cmd_str = 'QEMU_TEST'
        AlwaysBuild(env.Command(xml, test_bin, MakeAction(cmd, cmd_str)))

Export('MakeAction')

main.AddMethod(GTest)

native = main.Clone()
native_dir = build_dir.Dir('native')

# Bring in the googletest sources.
native.SConscript(googletest_dir.File('SConscript'),
        variant_dir=native_dir.Dir('googletest'), exports={ 'main': native })

native.SConscript(src_dir.File('SConscript.native'),
        variant_dir=native_dir, exports={ 'env': native })

main['CC'] = '${CROSS_COMPILE}gcc'
main['CXX'] = '${CROSS_COMPILE}g++'
main['AS'] = '${CROSS_COMPILE}as'
main['LD'] = '${CROSS_COMPILE}ld'
main['AR'] = '${CROSS_COMPILE}ar'
main['QEMU'] = 'qemu-${QEMU_ARCH}'

class CallType(object):
    def __init__(self, name):
        self.name = name
        self.impl_file = None
        self.enabled = False
        self.verifier = None
        self.default = False

    def impl(self, impl, verifier=None, default=False):
        self.impl_file = impl
        self.enabled = True
        self.verifier = verifier
        self.default = default

    # Being the default can be disabled for testing purposes, so we can tell if
    # a call type was selected because it was chosen, or because nobody else
    # was.
    def setup_env(self, env, allow_default=True):
        env = env.Clone()
        is_default = 'true' if self.default and allow_default else 'false'
        env.Append(CXXFLAGS=[ '-DCALL_TYPE_IS_DEFAULT=%s' % is_default ])
        return env

call_types = {
    # Magic instruction.
    'inst': CallType('inst'),
    # Magic address.
    'addr': CallType('addr'),
    # Semihosting extension.
    'semi': CallType('semi'),
}

for root, dirs, files in os.walk(abspath(src_dir)):
    # Each SConsopts file describes an ABI of the m5 utility.
    if 'SConsopts' in files:
        env = main.Clone()

        env['CALL_TYPE'] = copy.deepcopy(call_types)

        # The user may override ABI settings by setting environment
        # variables of the form ${ABI}.${OPTION}. For instance, to set the
        # CROSS_COMPILE prefix for abi foo to bar-, the user would set an
        # environment variable foo.CROSS_COMPILE=bar-.
        #
        # This also considers scons command line settings which may look like
        # environment variables, but are set after "scons" on the command line.
        def _extract_abi_opt_val(name, default):
            var_name = env.subst('${ABI}.%s' % name)
            return os.environ.get(var_name, ARGUMENTS.get(var_name, default))
        def get_abi_opt(name, default):
            env[name] = _extract_abi_opt_val(name, default)
        def append_abi_opt(name):
            env.Append(**{ name: _extract_abi_opt_val(name, '') })

        # Process the ABI's settings in the SConsopts file, storing them
        # in a copy of the primary environment.
        env.SConscript(Dir(root).File('SConsopts'),
                       exports=[ 'env', 'get_abi_opt' ])

        # The user can pass extra build flags for each ABI
        append_abi_opt('CCFLAGS')
        append_abi_opt('CXXFLAGS')
        append_abi_opt('LINKFLAGS')

        # Check if this version of QEMU is available for running unit tests.
        env['HAVE_QEMU'] = env.Detect('${QEMU}') is not None
        if env['HAVE_QEMU'] and env.Detect('${CC}'):
            sysroot_cmd = env.subst('${CC} -print-sysroot')
            sysroot = os.popen(sysroot_cmd).read().strip()
            env['QEMU_SYSROOT'] = sysroot

        # Once all the options have been configured, set up build targets for
        # this abi.
        abi_dir = build_dir.Dir(env.subst('${ABI}'))
        # Bring in the googletest sources.
        env.SConscript(googletest_dir.File('SConscript'),
                variant_dir=abi_dir.Dir('googletest'),
                exports={ 'main': env })
        env.SConscript(src_dir.File('SConscript'),
                       variant_dir=abi_dir, exports='env')
