# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# All Rights Reserved.
# Confidential and Proprietary - Qualcomm Technologies, Inc.

#-----------------------------------------------------------------------------
#          QTEE SDK Scons Construction Environment Factory
#-----------------------------------------------------------------------------
#
# In spite of its name, this scons file is intended to be a subsidiary
# scons file.  It parses arguments specific to the QTEE SDK and
# returns a scons construction environment that implements tools a TA
# developer can use for configuring and building TAs.
#
# After calling this file the TA developer must call env.InitArch() to
# configure the target architecture for the compiler, then
# env.SecureAppBuilder() to build the TA.
#
# This file has the following dependencies:
# * ARGUMENTS["BUILD_ROOT"] must be set by the invoker
# * ARGUMENTS["CHIPSET"] must be set by the invoker
#
# Scons will automatically populate command line arguments into the
# ARGUMENTS dictionary, so the above dependencies may be met either on
# the command line or from the caller's scons file.  This file will
# also convert all ARGUMENTS into environment variables.
#
# Here is a non-exhaustive list of potentially-useful environment
# variables that will be made available in the construction
# environment returned from this file:
#
# BUILD_ROOT
# ----
#
# Set to BUILD_ROOT argument.  The QTEE SDK will create build/ms/bin/*
# directories underneath the BUILD_ROOT folder and place all output
# binaries there.  The "build/ms" folder structure is consistent with
# other SW releases from Qualcomm.
#
#
# OUT_DIR
# ----
#
# Intermediate build files are placed in this folder prior to copying
# them to the "{BUILD_ROOT}/build/ms" folder.  OUT_DIR may be provided
# as an input argument, but if BUILD_ROOT is set to the base of a
# QC-supplied release, this file will update it to point to a folder
# within the QC-supplied release.  This update is made so that
# reference TAs supplied by QC will find their dependent pre-compiled
# libraries from the release.
#
#
# LIB_OUT_DIR
# ----
#
# Conditionally defined in this file.  Used by secure_app_builder.py
# (secure_app_lib_builder()) to place archives in a specific folder.
# secure_app_lib_builder() sets this to OUT_DIR if it is not defined.
#
#
# SDK_ROOT
# ----
#
# The path where this file exists.  It is the parent folder of all
# contents of the QTEE SDK.
#
#
# SHORT_BUILDPATH / BUILD_ID
# ----
#
# A unique eight-character string that corresponds to the chipset (and
# chipset configuration) that's being compiled.
#
#
# MBN_ROOT
# ----
#
# The path to the directory that will hold MBN artifacts.
#
#
# TZ_EXEC_MODE
# ----
#
# Describes the architecture of the QTEE kernel for the CHIPSET
# argument that was passed in.  Valid values are: aarch32, aarch64,
# x86-32 or x86-64.  The x86 variants are associated with the QTEEEmu
# test environment included in the QTEE SDK.
#
# This variable is OVERWRITTEN by env.InitArch().
#

import getpass
import os
import platform
import re
import sys
import time

build_root_help_text = (
  "The build environment will create build/ms/bin/* directories\n" +
  "            underneath this folder and place build artifacts there in\n" +
  "            addition to the OUT_DIR argument.  These folders are \n" +
  "            consistent with other SW releases from Qualcomm.\n" +
  "\n" +
  "            If using a relative path, it must be a relative path from\n" +
  "            the scons entry point.\n" +
  "\n" +
  "            When BUILD_ROOT is the root folder of a QC-supplied\n" +
  "            release, the build environment will find dependencies\n" +
  "            in the \"apps\" folder and the build environment will\n" +
  "            update OUT_DIR to\n" +
  "            \"${BUILD_ROOT}/apps/bsp/trustzone/${APP_NAME}/build\"\n" +
  "            to match QC-supplied TAs.")

out_dir_help_text = (
  "Build artifacts go to this folder before they are copied to\n" +
  "         a folder created under BUILD_ROOT.  If using a relative\n" +
  "         path, it must be relative to the scons entry point."
)

qtee_sdk_help_text = (
  "The parent folder of the QTEE SDK.  If using a relative path, it must\n" +
  "          be relative to the scons entry point."
)

build_root_warning_text = (
  "WARNING: Cannot find dependencies from the QC trusted application\n" +
  "         software release under BUILD_ROOT. This warning may be safely\n" +
  "         ignored if using the QTEE SDK without the QC trusted\n" +
  "         application software release"
)

THIS_FILE = (lambda x:x).__code__.co_filename
THIS_DIR = os.path.dirname(os.path.abspath(THIS_FILE))

# Because this scons file parses arguments and isn't the entry point
# to scons, any relative paths need to be made relative to the scons
# entry point prior to interpretation.
def fixup_relative_path(arg):
  if ARGUMENTS.get(arg):
    if not os.path.isabs(ARGUMENTS[arg]):
      newpath = os.path.join(Dir("#").abspath, ARGUMENTS[arg])
      ARGUMENTS[arg] = os.path.abspath(newpath)
fixup_relative_path("BUILD_ROOT")
fixup_relative_path("OUT_DIR")

version_file = os.path.join(THIS_DIR, 'version.txt')
no_version_str = 'No Version'
print(("Info: SDK version file found!\n"
        "       {}".format(version_file)))
if os.access(version_file, os.R_OK):
  print(("Info: SDK version file has Read access!\n"))

vars = Variables(version_file, args=ARGUMENTS)
vars.AddVariables(
  PathVariable("BUILD_ROOT",
               build_root_help_text,
               ""),
  PathVariable("OUT_DIR",
               out_dir_help_text,
               "${BUILD_ROOT}/out",
               PathVariable.PathAccept),
  BoolVariable("QCBUILDDEBUG",
               "Enable additional log messages in QC build files.",
               False),
  BoolVariable("DETERMINISTIC",
               "Set build flags to enable reproducible/deterministic builds.",
               False),
  ('sdk_version', 'QTEE SDK Version Set By version.txt', no_version_str),
)

denv = DefaultEnvironment(ENV = os.environ, tools = ['mingw','textfile'])
env = Environment(variables = vars)

print(("Info: SDK file version!\n"
        "       {}".format(env.get("sdk_version"))))

Help(vars.GenerateHelpText(env))

# Since there are no command line arguments supported except CHIPSET in
# APPS SI, there's no need to store these variables in the environment.
if 'LOAD_CHIPSET_SPECIFIC_TOOLS' not in ARGUMENTS:
  for k,v in list(ARGUMENTS.items()):
    env[k] = v

# This seems necessary because some other build files don't handle
# relative paths for these variables without choooooking (hard)
env.Replace(SDK_ROOT = THIS_DIR)
env.Replace(BUILD_ROOT = os.path.abspath(env.subst(env["BUILD_ROOT"])))
env.Replace(OUT_DIR = os.path.abspath(env.subst(env["OUT_DIR"])))
env.Replace(STANDALONE_SDK = True)
env.Replace(OFF_TARGET_ENABLED = True)

# Adding external library directory of sectools to system paths so
# that libraries like six and others can be imported bt sectools scripts.
sys.path.insert(1, os.path.join(env['SDK_ROOT'], 'scripts', 'sectools', 'ext'))

# Dead code. sdk version is not used anywhere.
# Enable after Jira OPSHELP-539647 issue fixed.
#
#version_string = env.get("sdk_version")
#if (version_string == no_version_str):
#  print("Error: No SDK version file found!")
#  Exit(1)
#
#match = re.match(r"TZ\.(XF|FU|VERIFY)\.(.+\..+)", version_string)
#if not match or not match.group(2):
#  print(("Error: SDK version file found had unexpected format!\n"
#        "       {}".format(version_string)))
#  Exit(1)
#
#env.Replace(QTEE_SDK_VERSION = match.group(1))

# Some QC scons files have a dependency on the "CHIPSET" key being
# available in the ARGUMENTS variable.
if not ARGUMENTS.get("CHIPSET"):
  ARGUMENTS["CHIPSET"] = env.get('CHIPSET', '')

if env.get("DETERMINISTIC"):
  env.Replace(BUILD_TIMESTAMP = "Wed Dec 31 16:00:00 1969")
  env.Replace(BUILD_USER_NAME = "deterministic user name")
  env.Replace(BUILD_MACHINE_NAME = "deterministic machine name")
else:
  env.Replace(BUILD_TIMESTAMP = time.ctime())
  env.Replace(BUILD_USER_NAME = getpass.getuser())
  env.Replace(BUILD_MACHINE_NAME = platform.node())

build_root = env.get("BUILD_ROOT")
apps_tz_root = os.path.join(build_root, "apps/bsp/trustzone")

print_out_dir = False

# apps_tz_root is expected to be there even in a stripped and packed
# build

if os.path.exists(apps_tz_root):
  out_dir = os.path.join(apps_tz_root, 'qsapps/${APP_NAME}/build/${SHORT_BUILDPATH}')
  lib_out_dir = os.path.join(apps_tz_root,
                             'qsapps/${LIBNAME}/${APP_NAME}/' +
                             '${PROC}/${SHORT_BUILDPATH}')
  env.Replace(OUT_DIR = out_dir)
  env.Replace(LIB_OUT_DIR = lib_out_dir)
  if ARGUMENTS.get("OUT_DIR") is not None:
    print(("Warning: OUT_DIR argument will be ignored.  The path to the\n" +
          "         expected OUT_DIR for QC builds will be used instead."))
    print_out_dir = True
else:
  print(build_root_warning_text)

if env.get("QCBUILDDEBUG") or print_out_dir:
  print(("==================================================================" +
        "============"))
  print(("CHIPSET       = " + format(env.get("CHIPSET"))))
  print(("BUILD_ROOT    = " + format(env.get("BUILD_ROOT"))))
  print(("SDK_ROOT      = " + format(env.get("SDK_ROOT"))))
  print(("OUT_DIR       = " + format(env.get("OUT_DIR"))))
  print(("DETERMINISTIC = " + format(env.get("DETERMINISTIC"))))
  print(("==================================================================" +
        "============"))

tooldir = os.path.join(env.subst("$SDK_ROOT"), "scripts")

env.Tool('ssg_environment', toolpath = [tooldir])

# These scripts are required here as verify_deploy_sdk uses these scripts in TZ image.
# In apps image these scripts are loaded at a later point.
if 'LOAD_CHIPSET_SPECIFIC_TOOLS' not in ARGUMENTS:
  env.Tool('qcscons_replacement', toolpath = [tooldir])
  env.Tool('sdk_tools', toolpath = [tooldir])
  env.Tool('idlcompiler', toolpath = [tooldir])

env.Replace(SECTOOLS_BUILDER_VERBOSITY = 'z')
env.Decider('MD5-timestamp')

def dummy(*args,**kwargs):
  pass

if env.FindFile('deploy_builder.py', tooldir):
  env.Tool('deploy_builder', toolpath = [tooldir])
else:
  env.AddMethod(dummy,'Deploy')

env.AddMethod(dummy,'DeployInternal')
env.AddMethod(lambda *args, **kwargs: [],'GetDefaultPublicVariants')
env.AddMethod(lambda *args, **kwargs: [],'GetDefaultPrivateVariants')

Return('env')
