# 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.
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')
