#===============================================================================
#
# Multibuild build script
#
# GENERAL DESCRIPTION
#    App Core build script
#
# Copyright (c) Samsung Electronics Co, Ltd 2017. All rights reserved.
#
#===============================================================================
Import('env')
import os
import sys

def get_multibuild_variable(local_name, default=None):
    var = os.getenv(local_name, default)
    if var != None:
      var = var.strip()

    if not var and default:
      var = default.strip()

    return var

def get_multibuild_array(local_name):
    arr = get_multibuild_variable(local_name)
    if None != arr:
        return arr.split()
    return []

multibuild_src_ta = get_multibuild_array("LOCAL_SRC_TA")
multibuild_src_lib = get_multibuild_array("LOCAL_SRC_LIB")
multibuild_includes = get_multibuild_array("LOCAL_INCLUDE_DIRS")
multibuild_app_name = get_multibuild_variable("LOCAL_NAME")
multibuild_standalone_script = get_multibuild_variable("LOCAL_STANDALONE_SCRIPT", "n")
multibuild_build_tool = get_multibuild_variable("LOCAL_BUILD_TOOL", "arm")
multibuild_ssg_or_core = get_multibuild_variable("LOCAL_APPS_DIR", "core")
multibuild_uuid = get_multibuild_variable("LOCAL_UUID", "6d756c74696275696c64000000000000")
multibuild_custom_libs = get_multibuild_array("LOCAL_CUSTOM_LIBS")
multibuild_defines = get_multibuild_array("LOCAL_CFLAGS")
multibuild_cflags = ""
multibuild_cpp_defines = []
for s in multibuild_defines:
    if not s.startswith('-D'):
        multibuild_cflags += " " + s.replace('"','\\"')
    else:
        multibuild_cpp_defines.append(s.replace('-D', '').replace('"','\\"'))
multibuild_custom_services = get_multibuild_array("LOCAL_QSEE_SERVICES")
multibuild_custom_privileges = get_multibuild_array("LOCAL_QSEE_PRIVILEGES")
multibuild_custom_acc_buf_size = int(get_multibuild_variable("LOCAL_QSEE_ACCEPT_BUFFER_SIZE", "-1"))
multibuild_use_unprotected_mem = get_multibuild_variable("LOCAL_QSEE_UNPROTECTED_MEM")

def get_multibuild_appname(uuid):
    name = uuid.decode('hex')
    return name[:name.index('00'.decode('hex'))];

if multibuild_standalone_script != "n":
    env = env.Clone()
    env.Replace(OUT_DIR = '${BUILD_ROOT}/' + multibuild_ssg_or_core + '/bsp/trustzone/qsapps/multibuild/build')
    env.Replace(LIB_OUT_DIR = '${BUILD_ROOT}/' + multibuild_ssg_or_core + '/securemsm/trustzone/qsapps/multibuild/build')

#------------------------------------------------------------------------------
# Set up variables
#------------------------------------------------------------------------------
includes = ["#../../core/securemsm/trustzone/qsapps/sampleapp/inc",
            "#../../core/api/services",
            "#../../core/api/securemsm/trustzone/qsee",
            "#../../core/securemsm/trustzone/qsapps/multibuild",
            "#../../core/api/boot/qfprom/",
            "#../../core/api/services",
            "#../../core/api/securemsm/trustzone/qsee",
            "#../../core/api/kernel/libstd/stringl",
            "#../../core/securemsm/trustzone/qsapps/libs/applib/qsee/inc",
            "#../../core/securemsm/trustzone/qsapps/libs/applib/qsee/src",
            "#../../core/securemsm/trustzone/qsee/mink/include",
            '#../../ssg/securemsm/trustzone/qsapps/sampleapp/inc',
            "#../../ssg/api/securemsm/trustzone/qsee",
            '#../../ssg/securemsm/trustzone/qsapps/libs/applib/qsee/src',
            '#../../ssg/securemsm/trustzone/qsee/mink/include',
            '#../../ssg/securemsm/trustzone/qsapps/common',
           ]

includes.extend(multibuild_includes);

#----------------------------------------------------------------------------
# App core Objects
#----------------------------------------------------------------------------
target_name = 'multibuild'
app_name = get_multibuild_appname(multibuild_uuid)

#-------------------------------------------------------------------------------
# Add libraries
#-------------------------------------------------------------------------------

libs = []
for lib in multibuild_custom_libs:
    libb = env.File(env.SubstRealPath("${BUILD_ROOT}/" + multibuild_ssg_or_core + "/securemsm/trustzone/qsapps/multibuild/build/" + os.path.basename(lib)))
    libs.append(libb);

#-------------------------------------------------------------------------------
# Add flags and defines
#-------------------------------------------------------------------------------
ccflags_str = multibuild_cflags

if env['PROC'] == 'scorpion':
    ccflags_str = " -mfpu=neon " + ccflags_str

#-------------------------------------------------------------------------------
# Add stack protector
#-------------------------------------------------------------------------------
ccflags_str = " -fstack-protector -fstack-protector-all " + ccflags_str

env.Append(CCFLAGS = ccflags_str)
env.Append(CPPDEFINES = multibuild_cpp_defines)
#-------------------------------------------------------------------------------
# Add metadata to image
#-------------------------------------------------------------------------------
md = {
   'appName':    app_name,
   'privileges': ['default',
                  'I2C',
                  'OEMUnwrapKeys',
                  'CertValidate',
                  'SPI',
                  'TLMM',
                  'SecureDisplay',
                  'IntMask',
                  'OEMBuf',
                  'TransNSAddr',
                 ],
   'services':  multibuild_custom_services,
}

if multibuild_custom_acc_buf_size >= 0:
  md['acceptBufSize'] = multibuild_custom_acc_buf_size

md['privileges'].extend(multibuild_custom_privileges)

if multibuild_use_unprotected_mem == 'y':
  md['memoryType'] = 'Unprotected'

# Don't delete env['USES_CLEAN_PACK'] for sdm439, because it starts to build
# already prebuilt dependencies which have no sources in nhlos and errors occur.
if 'USES_CLEAN_PACK' in env and env['CHIPSET'] != 'sdm439':
  del env['USES_CLEAN_PACK']

multibuild_lib = env.SecureAppLibBuilder(
  sources = multibuild_src_lib,
  includes = includes,
  libname = multibuild_app_name
)

libs.append(multibuild_lib)

# Needed for linking CryptoCore
if env['PROC'] == 'scorpion':
  libca = env.SubstRealPath('${MUSL32PATH}/lib/libc.a')
else:
  libca = env.SubstRealPath('${MUSLPATH}/lib/libc.a')
  libs.append(env.File(env.SubstRealPath('${LLVMLIB}/libclang_rt.builtins-aarch64.a')))

libs.append(env.File(libca))

# Workaround to be able create custom services and use it.
# import SecureAppMetadata object from nhlos build system
sys.path.append(env.SubstRealPath('${BUILD_ROOT}/' + multibuild_ssg_or_core +'/bsp/build/scripts/'))
import SecureAppMetadata

for i in multibuild_includes:
  if not os.path.exists(i):
    raise RuntimeError("path does not exist: " + i + "\n" + "   module name is: " + multibuild_app_name + "\n\n")

rel_include_dirs = [os.path.relpath(i, env.SubstRealPath('${BUILD_ROOT}/')) for i in multibuild_includes]

if hasattr(SecureAppMetadata, '_kClassIdDirs'):
  SecureAppMetadata._kClassIdDirs.extend(rel_include_dirs)

# Workaround(o.fadieiev): The latest SDM8150 NHLOS doesn't have
# _kClassIdDirs, but it uses BUILD_ROOT. It's possible to substitute
# BUILD_ROOT and to generate IDL class map. It has no effect on the
# older NHLOS, just eats more CPU cycles.
e = env.Clone()
for i in multibuild_includes:
  e.Replace(BUILD_ROOT = i)
  try:
    # Workaround(i.makarchuk): SDM855 (SDM8150) - we have to
    # regenerate IDL_CLASS_MAP after modifications, otherwise
    # the above change of _kClassIdDir will have no effect.
    from SecureAppMetadata import IDLScanner
    idl_class_ids = env['ROOT_GLOBAL_ENV']['IDL_CLASS_MAP']
    idl_class_ids.update(IDLScanner().create_class_id_map(e))
  except:
    pass

# Here we try to build app specifying heap and stack in app builder. (msm8998 way)
# If this fails, we try to specify them via metadata. (new sdm845 way)
try:
  multibuild_units = env.SecureAppBuilder(
    sources = multibuild_src_ta,
    includes = includes,
    metadata = md,
    image = target_name,
    user_libs = libs,
    heap_size = '0x32000',
    stack_size = '0x32000'
  )
except:
  md['heapSize'] = 0x32000
  md['stackSize'] = 0x32000
  multibuild_units = env.SecureAppBuilder(
    sources = multibuild_src_ta,
    includes = includes,
    metadata = md,
    image = target_name,
    user_libs = libs,
  )

if multibuild_standalone_script != "n":
    aliases = ['multibuild', 'all']
    env.Alias(aliases, multibuild_units)
else:
    for image in env['IMAGE_ALIASES']:
        op = env.Alias(image, multibuild_units)

