|
@@ -0,0 +1,976 @@
|
|
|
+
|
|
|
+# @ build_bios.py
|
|
|
+# Builds BIOS using configuration files and dynamically
|
|
|
+# imported functions from board directory
|
|
|
+#
|
|
|
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
|
|
|
+# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
+#
|
|
|
+
|
|
|
+"""
|
|
|
+This module builds BIOS using configuration files and dynamically
|
|
|
+imported functions from board directory
|
|
|
+"""
|
|
|
+
|
|
|
+
|
|
|
+import os
|
|
|
+import re
|
|
|
+import sys
|
|
|
+import signal
|
|
|
+import shutil
|
|
|
+import argparse
|
|
|
+import traceback
|
|
|
+import subprocess
|
|
|
+from importlib import import_module
|
|
|
+
|
|
|
+try:
|
|
|
+ # python 2.7
|
|
|
+ import ConfigParser as configparser
|
|
|
+except ImportError:
|
|
|
+ # python 3
|
|
|
+ import configparser
|
|
|
+
|
|
|
+
|
|
|
+def pre_build(build_config, build_type="DEBUG", silent=False, toolchain=None):
|
|
|
+ """Sets the environment variables that shall be used for the build
|
|
|
+
|
|
|
+ :param build_config: The build configuration as defined in the JOSN
|
|
|
+ configuration files
|
|
|
+ :type build_config: Dictionary
|
|
|
+ :param build_type: The build target, DEBUG, RELEASE, RELEASE_PDB,
|
|
|
+ TEST_RELEASE
|
|
|
+ :type build_type: String
|
|
|
+ :param silent: Enables build in silent mode
|
|
|
+ :type silent: Boolean
|
|
|
+ :param toolchain: Specifies the tool chain tag to use for the build
|
|
|
+ :type toolchain: String
|
|
|
+ :returns: The updated environment variables
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+
|
|
|
+ # get current environment variables
|
|
|
+ config = os.environ.copy()
|
|
|
+
|
|
|
+ # patch the build config
|
|
|
+ build_config = patch_config(build_config)
|
|
|
+
|
|
|
+ # update the current config with the build config
|
|
|
+ config.update(build_config)
|
|
|
+
|
|
|
+ # make the config and build python 2.7 compartible
|
|
|
+ config = py_27_fix(config)
|
|
|
+
|
|
|
+ # Set WORKSPACE environment.
|
|
|
+ config["WORKSPACE"] = os.path.abspath(os.path.join("..", "..", "..", ""))
|
|
|
+ print("Set WORKSPACE as: {}".format(config["WORKSPACE"]))
|
|
|
+
|
|
|
+ # Check whether Git has been installed and been added to system path.
|
|
|
+ try:
|
|
|
+ subprocess.Popen(["git", "--help"], stdout=subprocess.PIPE)
|
|
|
+ except OSError:
|
|
|
+ print("The 'git' command is not recognized.")
|
|
|
+ print("Please make sure that Git is installed\
|
|
|
+ and has been added to system path.")
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ # Create the Conf directory under WORKSPACE
|
|
|
+ if not os.path.isdir(os.path.join(config["WORKSPACE"], "Conf")):
|
|
|
+ try:
|
|
|
+ # create directory
|
|
|
+ os.makedirs(os.path.join(config["WORKSPACE"], "Conf"))
|
|
|
+ # copy files to it
|
|
|
+ config_template_path = os.path.join(config["WORKSPACE"],
|
|
|
+ config["BASE_TOOLS_PATH"],
|
|
|
+ "Conf")
|
|
|
+ config_path = os.path.join(config["WORKSPACE"], "Conf")
|
|
|
+ shutil.copyfile(config_template_path +
|
|
|
+ os.sep + "target.template",
|
|
|
+ config_path + os.sep + "target.txt")
|
|
|
+ shutil.copyfile(config_template_path +
|
|
|
+ os.sep + "tools_def.template",
|
|
|
+ config_path + os.sep + "tools_def.txt")
|
|
|
+ shutil.copyfile(config_template_path +
|
|
|
+ os.sep + "build_rule.template",
|
|
|
+ config_path + os.sep + "build_rule.txt")
|
|
|
+ except OSError:
|
|
|
+ print("Error while creating Conf")
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ # Set other environments.
|
|
|
+ # Basic Rule:
|
|
|
+ # Platform override Silicon override Core
|
|
|
+ # Source override Binary
|
|
|
+ config["WORKSPACE_PLATFORM"] = os.path.join(config["WORKSPACE"],
|
|
|
+ config["WORKSPACE_PLATFORM"])
|
|
|
+ config["WORKSPACE_SILICON"] = os.path.join(config["WORKSPACE"],
|
|
|
+ config["WORKSPACE_SILICON"])
|
|
|
+ config["WORKSPACE_PLATFORM_BIN"] = \
|
|
|
+ os.path.join(config["WORKSPACE"], config["WORKSPACE_PLATFORM_BIN"])
|
|
|
+ config["WORKSPACE_SILICON_BIN"] = \
|
|
|
+ os.path.join(config["WORKSPACE"], config["WORKSPACE_SILICON_BIN"])
|
|
|
+ config["WORKSPACE_FSP_BIN"] = os.path.join(config["WORKSPACE"],
|
|
|
+ config["WORKSPACE_FSP_BIN"])
|
|
|
+
|
|
|
+ # add to package path
|
|
|
+ config["PACKAGES_PATH"] = config["WORKSPACE_PLATFORM"]
|
|
|
+ config["PACKAGES_PATH"] += os.pathsep + config["WORKSPACE_SILICON"]
|
|
|
+ config["PACKAGES_PATH"] += os.pathsep + config["WORKSPACE_SILICON_BIN"]
|
|
|
+ config["PACKAGES_PATH"] += os.pathsep + \
|
|
|
+ os.path.join(config["WORKSPACE"], "FSP")
|
|
|
+ config["PACKAGES_PATH"] += os.pathsep + \
|
|
|
+ os.path.join(config["WORKSPACE"], "edk2")
|
|
|
+ config["PACKAGES_PATH"] += os.pathsep + os.path.join(config["WORKSPACE"])
|
|
|
+ config["EDK_TOOLS_PATH"] = os.path.join(config["WORKSPACE"],
|
|
|
+ config["EDK_TOOLS_PATH"])
|
|
|
+ config["BASE_TOOLS_PATH"] = config["EDK_TOOLS_PATH"]
|
|
|
+ config["EDK_TOOLS_BIN"] = os.path.join(config["WORKSPACE"],
|
|
|
+ config["EDK_TOOLS_BIN"])
|
|
|
+ config["PLATFORM_FSP_BIN_PACKAGE"] = \
|
|
|
+ os.path.join(config['WORKSPACE_FSP_BIN'], config['FSP_BIN_PKG'])
|
|
|
+ config['PROJECT_DSC'] = os.path.join(config["WORKSPACE_PLATFORM"],
|
|
|
+ config['PROJECT_DSC'])
|
|
|
+ config['BOARD_PKG_PCD_DSC'] = os.path.join(config["WORKSPACE_PLATFORM"],
|
|
|
+ config['BOARD_PKG_PCD_DSC'])
|
|
|
+ config["CONF_PATH"] = os.path.join(config["WORKSPACE"], "Conf")
|
|
|
+
|
|
|
+ # get the python path
|
|
|
+ if os.environ.get("PYTHON_HOME") is None:
|
|
|
+ config["PYTHON_HOME"] = None
|
|
|
+ if os.environ.get("PYTHONPATH") is not None:
|
|
|
+ config["PYTHON_HOME"] = os.environ.get("PYTHONPATH")
|
|
|
+ else:
|
|
|
+ print("PYTHONPATH environment variable is not found")
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ # if python is installed, disable the binary base tools.
|
|
|
+ # python is installed if this code is running :)
|
|
|
+ if config.get("PYTHON_HOME") is not None:
|
|
|
+ if config.get("EDK_TOOLS_BIN") is not None:
|
|
|
+ del config["EDK_TOOLS_BIN"]
|
|
|
+
|
|
|
+ # Run edk setup and update config
|
|
|
+ if os.name == 'nt':
|
|
|
+ edk2_setup_cmd = [os.path.join(config["EFI_SOURCE"], "edksetup"),
|
|
|
+ "Rebuild"]
|
|
|
+
|
|
|
+ if config.get("EDK_SETUP_OPTION") and \
|
|
|
+ config["EDK_SETUP_OPTION"] != " ":
|
|
|
+ edk2_setup_cmd.append(config["EDK_SETUP_OPTION"])
|
|
|
+
|
|
|
+ _, _, result, return_code = execute_script(edk2_setup_cmd,
|
|
|
+ config,
|
|
|
+ collect_env=True,
|
|
|
+ shell=True)
|
|
|
+ if return_code == 0 and result is not None and isinstance(result,
|
|
|
+ dict):
|
|
|
+ config.update(result)
|
|
|
+
|
|
|
+ # nmake BaseTools source
|
|
|
+ # and enable BaseTools source build
|
|
|
+ shell = True
|
|
|
+ command = ["nmake", "-f", os.path.join(config["BASE_TOOLS_PATH"],
|
|
|
+ "Makefile")]
|
|
|
+ if os.name == "posix": # linux
|
|
|
+ shell = False
|
|
|
+ command = ["make", "-C", os.path.join(config["BASE_TOOLS_PATH"])]
|
|
|
+
|
|
|
+ _, _, result, return_code = execute_script(command, config, shell=shell)
|
|
|
+ if return_code != 0:
|
|
|
+ build_failed(config)
|
|
|
+
|
|
|
+ config["SILENT_MODE"] = 'TRUE' if silent else 'FALSE'
|
|
|
+
|
|
|
+ print("==============================================")
|
|
|
+
|
|
|
+ if os.path.isfile(os.path.join(config['WORKSPACE'], "Prep.log")):
|
|
|
+ os.remove(os.path.join(config['WORKSPACE'], "Prep.log"))
|
|
|
+
|
|
|
+ config["PROJECT"] = os.path.join(config["PLATFORM_BOARD_PACKAGE"],
|
|
|
+ config["BOARD"])
|
|
|
+
|
|
|
+ # Setup Build
|
|
|
+ # @todo: Need better TOOL_CHAIN_TAG detection
|
|
|
+ if toolchain is not None:
|
|
|
+ config["TOOL_CHAIN_TAG"] = toolchain
|
|
|
+ elif config.get("TOOL_CHAIN_TAG") is None:
|
|
|
+ if os.name == 'nt':
|
|
|
+ config["TOOL_CHAIN_TAG"] = "VS2015"
|
|
|
+ else:
|
|
|
+ config["TOOL_CHAIN_TAG"] = "GCC5"
|
|
|
+
|
|
|
+ # echo Show CL revision
|
|
|
+ config["PrepRELEASE"] = build_type
|
|
|
+
|
|
|
+ if build_type == "DEBUG":
|
|
|
+ config["TARGET"] = 'DEBUG'
|
|
|
+ config["TARGET_SHORT"] = 'D'
|
|
|
+ else:
|
|
|
+ config["TARGET"] = 'RELEASE'
|
|
|
+ config["TARGET_SHORT"] = 'R'
|
|
|
+
|
|
|
+ # set BUILD_DIR_PATH path
|
|
|
+ config["BUILD_DIR_PATH"] = os.path.join(config["WORKSPACE"],
|
|
|
+ 'Build',
|
|
|
+ config["PROJECT"],
|
|
|
+ "{}_{}".format(
|
|
|
+ config["TARGET"],
|
|
|
+ config["TOOL_CHAIN_TAG"]))
|
|
|
+ # set BUILD_DIR path
|
|
|
+ config["BUILD_DIR"] = os.path.join('Build',
|
|
|
+ config["PROJECT"],
|
|
|
+ "{}_{}".format(
|
|
|
+ config["TARGET"],
|
|
|
+ config["TOOL_CHAIN_TAG"]))
|
|
|
+
|
|
|
+ config["BUILD_X64"] = os.path.join(config["BUILD_DIR_PATH"], 'X64')
|
|
|
+ config["BUILD_IA32"] = os.path.join(config["BUILD_DIR_PATH"], 'IA32')
|
|
|
+
|
|
|
+ if not os.path.isdir(config["BUILD_DIR_PATH"]):
|
|
|
+ try:
|
|
|
+ os.makedirs(config["BUILD_DIR_PATH"])
|
|
|
+ except OSError:
|
|
|
+ print("Error while creating Build folder")
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ # Set FSP_WRAPPER_BUILD
|
|
|
+ if config['FSP_WRAPPER_BUILD'] == "TRUE":
|
|
|
+ # Create dummy Fsp_Rebased_S_padded.fd to build the BiosInfo.inf
|
|
|
+ # if it is wrapper build, due to the SECTION inclusion
|
|
|
+ open(os.path.join(config["WORKSPACE_FSP_BIN"],
|
|
|
+ config["FSP_BIN_PKG"],
|
|
|
+ "Fsp_Rebased_S_padded.fd"), 'w').close()
|
|
|
+
|
|
|
+ if not os.path.isdir(config["BUILD_X64"]):
|
|
|
+ try:
|
|
|
+ os.mkdir(config["BUILD_X64"])
|
|
|
+ except OSError:
|
|
|
+ print("Error while creating {}".format(config["BUILD_X64"]))
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ # update config file with changes
|
|
|
+ update_target_file(config)
|
|
|
+
|
|
|
+ # Additional pre build scripts for this platform
|
|
|
+ result = pre_build_ex(config)
|
|
|
+ if result is not None and isinstance(result, dict):
|
|
|
+ config.update(result)
|
|
|
+
|
|
|
+ # print user settings
|
|
|
+ print("BIOS_SIZE_OPTION = {}".format(config["BIOS_SIZE_OPTION"]))
|
|
|
+ print("EFI_SOURCE = {}".format(config["EFI_SOURCE"]))
|
|
|
+ print("TARGET = {}".format(config["TARGET"]))
|
|
|
+ print("TARGET_ARCH = {}".format("IA32 X64"))
|
|
|
+ print("TOOL_CHAIN_TAG = {}".format(config["TOOL_CHAIN_TAG"]))
|
|
|
+ print("WORKSPACE = {}".format(config["WORKSPACE"]))
|
|
|
+ print("WORKSPACE_CORE = {}".format(config["WORKSPACE_CORE"]))
|
|
|
+ print("EXT_BUILD_FLAGS = {}".format(config["EXT_BUILD_FLAGS"]))
|
|
|
+
|
|
|
+ return config
|
|
|
+
|
|
|
+
|
|
|
+def build(config):
|
|
|
+ """Builds the BIOS image
|
|
|
+
|
|
|
+ :param config: The environment variables to be used
|
|
|
+ in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: nothing
|
|
|
+ """
|
|
|
+
|
|
|
+ if config["FSP_WRAPPER_BUILD"] == "TRUE":
|
|
|
+ pattern = "Fsp_Rebased.*\\.fd$"
|
|
|
+ file_dir = os.path.join(config['WORKSPACE_FSP_BIN'],
|
|
|
+ config['FSP_BIN_PKG'])
|
|
|
+ for item in os.listdir(file_dir):
|
|
|
+ if re.search(pattern, item):
|
|
|
+ os.remove(os.path.join(file_dir, item))
|
|
|
+
|
|
|
+ command = [os.path.join(config['PYTHON_HOME'], "python"),
|
|
|
+ os.path.join(config['WORKSPACE_PLATFORM'],
|
|
|
+ config['PLATFORM_PACKAGE'],
|
|
|
+ 'Tools', 'Fsp',
|
|
|
+ 'RebaseAndPatchFspBinBaseAddress.py'),
|
|
|
+ os.path.join(config['WORKSPACE_PLATFORM'],
|
|
|
+ config['FLASH_MAP_FDF']),
|
|
|
+ os.path.join(config['WORKSPACE_FSP_BIN'],
|
|
|
+ config['FSP_BIN_PKG']),
|
|
|
+ "Fsp.fd",
|
|
|
+ os.path.join(config['WORKSPACE_PLATFORM'],
|
|
|
+ config['PROJECT'],
|
|
|
+ config['BOARD_PKG_PCD_DSC']),
|
|
|
+ "0x0"]
|
|
|
+
|
|
|
+ _, _, _, return_code = execute_script(command, config, shell=False)
|
|
|
+
|
|
|
+ if return_code != 0:
|
|
|
+ print("ERROR:RebaseAndPatchFspBinBaseAddress failed")
|
|
|
+ sys.exit(return_code)
|
|
|
+
|
|
|
+ # create Fsp_Rebased.fd which is Fsp_Rebased_S.fd +
|
|
|
+ # Fsp_Rebased_M + Fsp_Rebased_T
|
|
|
+ with open(os.path.join(file_dir, "Fsp_Rebased_S.fd"), 'rb') as fsp_s, \
|
|
|
+ open(os.path.join(file_dir,
|
|
|
+ "Fsp_Rebased_M.fd"), 'rb') as fsp_m, \
|
|
|
+ open(os.path.join(file_dir,
|
|
|
+ "Fsp_Rebased_T.fd"), 'rb') as fsp_t:
|
|
|
+
|
|
|
+ fsp_rebased = fsp_s.read() + fsp_m.read() + fsp_t.read()
|
|
|
+ with open(os.path.join(file_dir,
|
|
|
+ "Fsp_Rebased.fd"), 'wb') as new_fsp:
|
|
|
+ new_fsp.write(fsp_rebased)
|
|
|
+
|
|
|
+ if not os.path.isfile(os.path.join(file_dir, "Fsp_Rebased.fd")):
|
|
|
+ print("!!! ERROR:failed to create fsp!!!")
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+ # Output the build variables the user has selected.
|
|
|
+ print("==========================================")
|
|
|
+ print(" User Selected build options:")
|
|
|
+ print(" SILENT_MODE = ", config.get("SILENT_MODE"))
|
|
|
+ print(" REBUILD_MODE = ", config.get("REBUILD_MODE"))
|
|
|
+ print(" BUILD_ROM_ONLY = ", config.get("BUILD_ROM_ONLY"))
|
|
|
+ print("==========================================")
|
|
|
+
|
|
|
+ command = ["build", "-n", config["NUMBER_OF_PROCESSORS"]]
|
|
|
+
|
|
|
+ if config["REBUILD_MODE"] and config["REBUILD_MODE"] != "":
|
|
|
+ command.append(config["REBUILD_MODE"])
|
|
|
+
|
|
|
+ if config["EXT_BUILD_FLAGS"] and config["EXT_BUILD_FLAGS"] != "":
|
|
|
+ command.append(config["EXT_BUILD_FLAGS"])
|
|
|
+
|
|
|
+ if config.get("SILENT_MODE", "FALSE") == "TRUE":
|
|
|
+ command.append("--silent")
|
|
|
+ command.append("--quiet")
|
|
|
+
|
|
|
+ else:
|
|
|
+ command.append("--log=" + config.get("BUILD_LOG", "Build.log"))
|
|
|
+ command.append("--report-file=" +
|
|
|
+ config.get("BUILD_REPORT", "BuildReport.log"))
|
|
|
+
|
|
|
+ if config.get("VERBOSE", "FALSE") == "TRUE":
|
|
|
+ command.append("--verbose")
|
|
|
+
|
|
|
+ if config.get("MAX_SOCKET") is not None:
|
|
|
+ command.append("-D")
|
|
|
+ command.append("MAX_SOCKET=" + config["MAX_SOCKET"])
|
|
|
+
|
|
|
+ _, _, _, exit_code = execute_script(command, config)
|
|
|
+ if exit_code != 0:
|
|
|
+ build_failed(config)
|
|
|
+
|
|
|
+ # Additional build scripts for this platform
|
|
|
+ result = build_ex(config)
|
|
|
+ if result is not None and isinstance(result, dict):
|
|
|
+ config.update(result)
|
|
|
+
|
|
|
+ return config
|
|
|
+
|
|
|
+
|
|
|
+def post_build(config):
|
|
|
+ """Post build process of BIOS image
|
|
|
+
|
|
|
+ :param config: The environment variables to be used in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: nothing
|
|
|
+ """
|
|
|
+ print("Running post_build to complete the build process.")
|
|
|
+
|
|
|
+ # Additional build scripts for this platform
|
|
|
+ result = post_build_ex(config)
|
|
|
+ if result is not None and isinstance(result, dict):
|
|
|
+ config.update(result)
|
|
|
+
|
|
|
+ # cleanup
|
|
|
+ pattern = "Fsp_Rebased.*\\.fd$"
|
|
|
+ file_dir = os.path.join(config['WORKSPACE_FSP_BIN'],
|
|
|
+ config['FSP_BIN_PKG'])
|
|
|
+ for item in os.listdir(file_dir):
|
|
|
+ if re.search(pattern, item):
|
|
|
+ os.remove(os.path.join(file_dir, item))
|
|
|
+
|
|
|
+ if config.get("DYNAMIC_BUILD_INIT_FILES") is not None:
|
|
|
+ for item in config["DYNAMIC_BUILD_INIT_FILES"].split(","):
|
|
|
+ try:
|
|
|
+ os.remove(item) # remove __init__.py
|
|
|
+ os.remove(item + "c") # remove __init__.pyc as well
|
|
|
+ except OSError:
|
|
|
+ pass
|
|
|
+
|
|
|
+
|
|
|
+def build_failed(config):
|
|
|
+ """Displays results when build fails
|
|
|
+
|
|
|
+ :param config: The environment variables used in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: nothing
|
|
|
+ """
|
|
|
+ print(" The EDKII BIOS Build has failed!")
|
|
|
+ # clean up
|
|
|
+ if config.get("DYNAMIC_BUILD_INIT_FILES") is not None:
|
|
|
+ for item in config["DYNAMIC_BUILD_INIT_FILES"].split(","):
|
|
|
+ if os.path.isfile(item):
|
|
|
+ try:
|
|
|
+ os.remove(item) # remove __init__.py
|
|
|
+ os.remove(item + "c") # remove __init__.pyc as well
|
|
|
+ except OSError:
|
|
|
+ pass
|
|
|
+ sys.exit(1)
|
|
|
+
|
|
|
+
|
|
|
+def import_platform_lib(path, function):
|
|
|
+ """Imports custom functions for the platforms being built
|
|
|
+
|
|
|
+ :param path: the location of the custom build script to be executed
|
|
|
+ :type path: String
|
|
|
+ :param path: the function to be executed
|
|
|
+ :type path: String
|
|
|
+ :returns: nothing
|
|
|
+ """
|
|
|
+ if path.endswith(".py"):
|
|
|
+ path = path[:-3]
|
|
|
+ path = path.replace(os.sep, ".")
|
|
|
+ module = import_module(path)
|
|
|
+ lib = getattr(module, function)
|
|
|
+ return lib
|
|
|
+
|
|
|
+
|
|
|
+def pre_build_ex(config):
|
|
|
+ """ An extension of the pre_build process as defined platform
|
|
|
+ specific pre_build setup script
|
|
|
+
|
|
|
+ :param config: The environment variables used in the pre build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: config dictionary
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ if config.get("ADDITIONAL_SCRIPTS"):
|
|
|
+ try:
|
|
|
+ platform_function =\
|
|
|
+ import_platform_lib(config["ADDITIONAL_SCRIPTS"],
|
|
|
+ "pre_build_ex")
|
|
|
+ functions = {"execute_script": execute_script}
|
|
|
+ return platform_function(config, functions)
|
|
|
+ except ImportError as error:
|
|
|
+ print(config["ADDITIONAL_SCRIPTS"], str(error))
|
|
|
+ build_failed(config)
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def build_ex(config):
|
|
|
+ """ An extension of the build process as defined platform
|
|
|
+ specific build setup script
|
|
|
+
|
|
|
+ :param config: The environment variables used in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: config dictionary
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ if config.get("ADDITIONAL_SCRIPTS"):
|
|
|
+ try:
|
|
|
+ platform_function =\
|
|
|
+ import_platform_lib(config["ADDITIONAL_SCRIPTS"],
|
|
|
+ "build_ex")
|
|
|
+ functions = {"execute_script": execute_script}
|
|
|
+ return platform_function(config, functions)
|
|
|
+ except ImportError as error:
|
|
|
+ print("error", config["ADDITIONAL_SCRIPTS"], str(error))
|
|
|
+ build_failed(config)
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def post_build_ex(config):
|
|
|
+ """ An extension of the post build process as defined platform
|
|
|
+ specific build setup script
|
|
|
+
|
|
|
+ :param config: The environment variables used in the post build
|
|
|
+ process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: config dictionary
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ if config.get("ADDITIONAL_SCRIPTS"):
|
|
|
+ try:
|
|
|
+ platform_function =\
|
|
|
+ import_platform_lib(config["ADDITIONAL_SCRIPTS"],
|
|
|
+ "post_build_ex")
|
|
|
+ functions = {"execute_script": execute_script}
|
|
|
+ return platform_function(config, functions)
|
|
|
+ except ImportError as error:
|
|
|
+ print(config["ADDITIONAL_SCRIPTS"], str(error))
|
|
|
+ build_failed(config)
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def clean_ex(config):
|
|
|
+ """ An extension of the platform cleanning
|
|
|
+
|
|
|
+ :param config: The environment variables used in the clean process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: config dictionary
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ if config.get("ADDITIONAL_SCRIPTS"):
|
|
|
+ try:
|
|
|
+ platform_function =\
|
|
|
+ import_platform_lib(config["ADDITIONAL_SCRIPTS"],
|
|
|
+ "clean_ex")
|
|
|
+ functions = {"execute_script": execute_script}
|
|
|
+ return platform_function(config, functions)
|
|
|
+ except ImportError as error:
|
|
|
+ print(config["ADDITIONAL_SCRIPTS"], str(error))
|
|
|
+ build_failed(config)
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def get_environment_variables(std_out_str, marker):
|
|
|
+ """Gets the environment variables from a process
|
|
|
+
|
|
|
+ :param std_out_str: The std_out pipe
|
|
|
+ :type std_out_str: String
|
|
|
+ :param marker: A begining and end mark of environment
|
|
|
+ variables printed to std_out
|
|
|
+ :type marker: String
|
|
|
+ :returns: The environment variables read from the process' std_out pipe
|
|
|
+ :rtype: Tuple
|
|
|
+ """
|
|
|
+ start_env_update = False
|
|
|
+ environment_vars = {}
|
|
|
+ out_put = ""
|
|
|
+ for line in std_out_str.split("\n"):
|
|
|
+ if start_env_update and len(line.split("=")) == 2:
|
|
|
+ key, value = line.split("=")
|
|
|
+ environment_vars[key] = value
|
|
|
+ else:
|
|
|
+ out_put += "\n" + line.replace(marker, "")
|
|
|
+
|
|
|
+ if marker in line:
|
|
|
+ if start_env_update:
|
|
|
+ start_env_update = False
|
|
|
+ else:
|
|
|
+ start_env_update = True
|
|
|
+ return (out_put, environment_vars)
|
|
|
+
|
|
|
+
|
|
|
+def execute_script(command, env_variables, collect_env=False,
|
|
|
+ enable_std_pipe=False, shell=True):
|
|
|
+ """launches a process that executes a script/shell command passed to it
|
|
|
+
|
|
|
+ :param command: The command/script with its commandline
|
|
|
+ arguments to be executed
|
|
|
+ :type command: List:String
|
|
|
+ :param env_variables: Environment variables passed to the process
|
|
|
+ :type env_variables: String
|
|
|
+ :param collect_env: Enables the collection of evironment variables
|
|
|
+ when process execution is done
|
|
|
+ :type collect_env: Boolean
|
|
|
+ :param enable_std_pipe: Enables process out to be piped to
|
|
|
+ :type enable_std_pipe: String
|
|
|
+ :returns: a tuple of std_out, stderr , environment variables,
|
|
|
+ return code
|
|
|
+ :rtype: Tuple: (std_out, stderr , enVar, return_code)
|
|
|
+ """
|
|
|
+
|
|
|
+ print("Calling " + " ".join(command))
|
|
|
+
|
|
|
+ env_marker = '-----env-----'
|
|
|
+ env = {}
|
|
|
+ kwarg = {"env": env_variables,
|
|
|
+ "universal_newlines": True,
|
|
|
+ "shell": shell,
|
|
|
+ "cwd": env_variables["WORKSPACE"]}
|
|
|
+
|
|
|
+ if enable_std_pipe or collect_env:
|
|
|
+ kwarg["stdout"] = subprocess.PIPE
|
|
|
+ kwarg["stderr"] = subprocess.PIPE
|
|
|
+
|
|
|
+ # collect environment variables
|
|
|
+ if collect_env:
|
|
|
+ # get the binary that prints environment variables based on os
|
|
|
+ if os.name == 'nt':
|
|
|
+ get_var_command = "set"
|
|
|
+ else:
|
|
|
+ get_var_command = "env"
|
|
|
+ # modify the command to print the environment variables
|
|
|
+ if isinstance(command, list):
|
|
|
+ command += ["&&", "echo", env_marker, "&&",
|
|
|
+ get_var_command, "&&", "echo", env_marker]
|
|
|
+ else:
|
|
|
+ command += " " + " ".join(["&&", "echo", env_marker,
|
|
|
+ "&&", get_var_command,
|
|
|
+ "&&", "echo", env_marker])
|
|
|
+
|
|
|
+ # execute the command
|
|
|
+ execute = subprocess.Popen(command, **kwarg)
|
|
|
+ std_out, stderr = execute.communicate()
|
|
|
+ code = execute.returncode
|
|
|
+
|
|
|
+ # wait for process to be done
|
|
|
+ execute.wait()
|
|
|
+
|
|
|
+ # if collect enviroment variables
|
|
|
+ if collect_env:
|
|
|
+ # get the new environment variables
|
|
|
+ std_out, env = get_environment_variables(std_out, env_marker)
|
|
|
+ return (std_out, stderr, env, code)
|
|
|
+
|
|
|
+
|
|
|
+def patch_config(config):
|
|
|
+ """ An extension of the platform cleanning
|
|
|
+
|
|
|
+ :param config: The environment variables used in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: config dictionary
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ new_config = {}
|
|
|
+ for key in config:
|
|
|
+ new_config[str(key)] = str(config[key].replace("/", os.sep))
|
|
|
+ return new_config
|
|
|
+
|
|
|
+
|
|
|
+def py_27_fix(config):
|
|
|
+ """ Prepares build for python 2.7 => build
|
|
|
+ :param config: The environment variables used in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: config dictionary
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ if not sys.version_info > (3, 0):
|
|
|
+ path_list = []
|
|
|
+ # create __init__.py in directories in this path
|
|
|
+ if config.get("ADDITIONAL_SCRIPTS"):
|
|
|
+ # get the directory
|
|
|
+ path_to_directory =\
|
|
|
+ os.path.dirname(config.get("ADDITIONAL_SCRIPTS"))
|
|
|
+ path = ""
|
|
|
+ for directories in path_to_directory.split(os.sep):
|
|
|
+ path += directories + os.sep
|
|
|
+ init_file = path + os.sep + "__init__.py"
|
|
|
+ if not os.path.isfile(init_file):
|
|
|
+ open(init_file, 'w').close()
|
|
|
+ path_list.append(init_file)
|
|
|
+ config["DYNAMIC_BUILD_INIT_FILES"] = ",".join(path_list)
|
|
|
+
|
|
|
+ return config
|
|
|
+
|
|
|
+
|
|
|
+def clean(build_config, board=False):
|
|
|
+ """Cleans the build workspace
|
|
|
+
|
|
|
+ :param config: The environment variables used in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :param board: This flag specifies specific board clean
|
|
|
+ :type board: Bool
|
|
|
+ :returns: nothing
|
|
|
+ """
|
|
|
+
|
|
|
+ # patch the config
|
|
|
+ build_config = patch_config(build_config)
|
|
|
+
|
|
|
+ # get current environment variables
|
|
|
+ config = os.environ.copy()
|
|
|
+
|
|
|
+ # update it with the build variables
|
|
|
+ config.update(build_config)
|
|
|
+
|
|
|
+ if config.get('WORKSPACE') is None or not config.get('WORKSPACE'):
|
|
|
+ config["WORKSPACE"] =\
|
|
|
+ os.path.abspath(os.path.join("..", "..", "..", ""))
|
|
|
+
|
|
|
+ # build cleanall
|
|
|
+ print("Cleaning directories...")
|
|
|
+
|
|
|
+ if board:
|
|
|
+ platform_pkg = config.get("PLATFORM_BOARD_PACKAGE", None)
|
|
|
+ if platform_pkg is None or\
|
|
|
+ not os.path.isdir(os.path.join(config['WORKSPACE'],
|
|
|
+ "Build", platform_pkg)):
|
|
|
+ print("Platform package not found")
|
|
|
+ sys.exit(1)
|
|
|
+ else:
|
|
|
+ print("Removing " + os.path.join(config['WORKSPACE'],
|
|
|
+ "Build", platform_pkg))
|
|
|
+ shutil.rmtree(os.path.join(config['WORKSPACE'],
|
|
|
+ "Build", platform_pkg))
|
|
|
+
|
|
|
+ else:
|
|
|
+ if os.path.isdir(os.path.join(config['WORKSPACE'], "Build")):
|
|
|
+ print("Removing " + os.path.join(config['WORKSPACE'], "Build"))
|
|
|
+ shutil.rmtree(os.path.join(config['WORKSPACE'], "Build"))
|
|
|
+
|
|
|
+ if os.path.isdir(os.path.join(config['WORKSPACE'], "Conf")):
|
|
|
+ print("Removing " + os.path.join(config['WORKSPACE'], "Conf"))
|
|
|
+ shutil.rmtree(os.path.join(config['WORKSPACE'], "Conf"))
|
|
|
+
|
|
|
+ print("Cleaning files...")
|
|
|
+
|
|
|
+ if os.path.isfile(os.path.join(config['WORKSPACE'],
|
|
|
+ config.get("BUILD_REPORT",
|
|
|
+ "BuildReport.log"))):
|
|
|
+ print("Removing ", os.path.join(config['WORKSPACE'],
|
|
|
+ config.get("BUILD_REPORT",
|
|
|
+ "BuildReport.log")))
|
|
|
+ os.remove(os.path.join(config['WORKSPACE'],
|
|
|
+ config.get("BUILD_REPORT", "BuildReport.log")))
|
|
|
+
|
|
|
+ print(" All done...")
|
|
|
+
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
+
|
|
|
+def update_target_file(config):
|
|
|
+ """Updates Conf's target file that will be used in the build
|
|
|
+
|
|
|
+ :param config: The environment variables used in the build process
|
|
|
+ :type config: Dictionary
|
|
|
+ :returns: True if update was successful and False if update fails
|
|
|
+ :rtype: Boolean
|
|
|
+ """
|
|
|
+ contents = None
|
|
|
+ result = False
|
|
|
+ with open(os.path.join(config["CONF_PATH"], "target.txt"), 'r') as target:
|
|
|
+ contents = target.readlines()
|
|
|
+ options_list = ['ACTIVE_PLATFORM', 'TARGET',
|
|
|
+ 'TARGET_ARCH', 'TOOL_CHAIN_TAG', 'BUILD_RULE_CONF']
|
|
|
+ modified = []
|
|
|
+
|
|
|
+ # remove these options from the config file
|
|
|
+ for line in contents:
|
|
|
+ if line.replace(" ", "")[0] != '#' and\
|
|
|
+ any(opt in line for opt in options_list):
|
|
|
+ continue
|
|
|
+ modified.append(line)
|
|
|
+
|
|
|
+ # replace with config options provided
|
|
|
+ string = "{} = {}\n".format("ACTIVE_PLATFORM",
|
|
|
+ os.path.join(
|
|
|
+ config['WORKSPACE_PLATFORM'],
|
|
|
+ config['PLATFORM_BOARD_PACKAGE'],
|
|
|
+ config['BOARD'],
|
|
|
+ config['PROJECT_DSC']))
|
|
|
+ modified.append(string)
|
|
|
+
|
|
|
+ string = "{} = {}\n".format("TARGET", config['TARGET'])
|
|
|
+ modified.append(string)
|
|
|
+
|
|
|
+ string = "TARGET_ARCH = IA32 X64\n"
|
|
|
+ modified.append(string)
|
|
|
+
|
|
|
+ string = "{} = {}\n".format("TOOL_CHAIN_TAG", config['TOOL_CHAIN_TAG'])
|
|
|
+ modified.append(string)
|
|
|
+
|
|
|
+ string = "{} = {}\n".format("BUILD_RULE_CONF",
|
|
|
+ os.path.join("Conf", "build_rule.txt"))
|
|
|
+ modified.append(string)
|
|
|
+
|
|
|
+ if modified is not None:
|
|
|
+ with open(os.path.join(config["WORKSPACE"],
|
|
|
+ "Conf", "target.txt"), 'w') as target:
|
|
|
+ for line in modified:
|
|
|
+ target.write(line)
|
|
|
+ result = True
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+
|
|
|
+def get_config():
|
|
|
+ """Reads the default projects config file
|
|
|
+
|
|
|
+ :returns: The config defined in the the Build.cfg file
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ config_file = configparser.RawConfigParser()
|
|
|
+ config_file.optionxform = str
|
|
|
+ config_file.read('build.cfg')
|
|
|
+ config_dictionary = {}
|
|
|
+ for section in config_file.sections():
|
|
|
+ dictionary = dict(config_file.items(section))
|
|
|
+ config_dictionary[section] = dictionary
|
|
|
+ return config_dictionary
|
|
|
+
|
|
|
+
|
|
|
+def get_platform_config(platform_name, config_data):
|
|
|
+ """ Reads the platform specifig config file
|
|
|
+
|
|
|
+ param platform_name: The name of the platform to be built
|
|
|
+ :type platform_name: String
|
|
|
+ param configData: The environment variables to be
|
|
|
+ used in the build process
|
|
|
+ :type configData: Dictionary
|
|
|
+ :returns: The config defined in the the Build.cfg file
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ config = {}
|
|
|
+
|
|
|
+ platform_data = config_data.get("PLATFORMS")
|
|
|
+ path = platform_data.get(platform_name)
|
|
|
+ config_file = configparser.RawConfigParser()
|
|
|
+ config_file.optionxform = str
|
|
|
+ config_file.read(path)
|
|
|
+ for section in config_file.sections():
|
|
|
+ config[section] = dict(config_file.items(section))
|
|
|
+
|
|
|
+ return config
|
|
|
+
|
|
|
+
|
|
|
+def get_cmd_config_arguments(arguments):
|
|
|
+ """Get commandline config arguments
|
|
|
+
|
|
|
+ param arguments: The environment variables to be used in the build process
|
|
|
+ :type arguments: argparse
|
|
|
+ :returns: The config dictionary built from the commandline arguments
|
|
|
+ :rtype: Dictionary
|
|
|
+ """
|
|
|
+ result = {}
|
|
|
+ if arguments.capsule is True:
|
|
|
+ result["CAPSULE_BUILD"] = "1"
|
|
|
+
|
|
|
+ if arguments.performance is True:
|
|
|
+ result["PERFORMANCE_BUILD"] = "TRUE"
|
|
|
+
|
|
|
+ if arguments.fsp is True:
|
|
|
+ result["FSP_WRAPPER_BUILD"] = "TRUE"
|
|
|
+
|
|
|
+ return result
|
|
|
+
|
|
|
+
|
|
|
+def get_cmd_arguments(build_config):
|
|
|
+ """ Get commandline inputs from user
|
|
|
+
|
|
|
+ param config_data: The environment variables to be
|
|
|
+ used in the build process
|
|
|
+ :type config_data: Dictionary
|
|
|
+ :returns: The commandline arguments input by the user
|
|
|
+ :rtype: argparse object
|
|
|
+ """
|
|
|
+
|
|
|
+ class PrintPlatforms(argparse.Action):
|
|
|
+ """ this is an argparse action that lists the available platforms
|
|
|
+ """
|
|
|
+ def __call__(self, parser, namespace, values, option_string=None):
|
|
|
+ print("Platforms:")
|
|
|
+ for key in build_config.get("PLATFORMS"):
|
|
|
+ print(" " + key)
|
|
|
+ setattr(namespace, self.dest, values)
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
+ # get the build commands
|
|
|
+ parser = argparse.ArgumentParser(description="Build Help")
|
|
|
+ parser.add_argument('--platform', '-p', dest="platform",
|
|
|
+ help='the platform to build',
|
|
|
+ choices=build_config.get("PLATFORMS"),
|
|
|
+ required=('-l' not in sys.argv and
|
|
|
+ '--cleanall' not in sys.argv))
|
|
|
+
|
|
|
+ parser.add_argument('--toolchain', '-t', dest="toolchain",
|
|
|
+ help="using the Tool Chain Tagname to build \
|
|
|
+ the platform,overriding \
|
|
|
+ target.txt's TOOL_CHAIN_TAG definition")
|
|
|
+
|
|
|
+ parser.add_argument("--DEBUG", '-d', help="debug flag",
|
|
|
+ action='store_const', dest="target",
|
|
|
+ const="DEBUG", default="DEBUG")
|
|
|
+
|
|
|
+ parser.add_argument("--RELEASE", '-r', help="release flag",
|
|
|
+ action='store_const',
|
|
|
+ dest="target", const="RELEASE")
|
|
|
+
|
|
|
+ parser.add_argument("--TEST_RELEASE", '-tr', help="test Release flag",
|
|
|
+ action='store_const',
|
|
|
+ dest="target", const="TEST_RELEASE")
|
|
|
+
|
|
|
+ parser.add_argument("--RELEASE_PDB", '-rp', help="release flag",
|
|
|
+ action='store_const', dest="target",
|
|
|
+ const="RELEASE_PDB")
|
|
|
+
|
|
|
+ parser.add_argument('--list', '-l', action=PrintPlatforms,
|
|
|
+ help='lists available platforms', nargs=0)
|
|
|
+
|
|
|
+ parser.add_argument('--cleanall', dest='clean_all',
|
|
|
+ help='cleans all', action='store_true')
|
|
|
+
|
|
|
+ parser.add_argument('--clean', dest='clean',
|
|
|
+ help='cleans specific platform', action='store_true')
|
|
|
+
|
|
|
+ parser.add_argument("--capsule", help="capsule build enabled",
|
|
|
+ action='store_true', dest="capsule")
|
|
|
+
|
|
|
+ parser.add_argument("--silent", help="silent build enabled",
|
|
|
+ action='store_true', dest="silent")
|
|
|
+
|
|
|
+ parser.add_argument("--performance", help="performance build enabled",
|
|
|
+ action='store_true', dest="performance")
|
|
|
+
|
|
|
+ parser.add_argument("--fsp", help="fsp build enabled",
|
|
|
+ action='store_true', dest="fsp")
|
|
|
+
|
|
|
+ return parser.parse_args()
|
|
|
+
|
|
|
+
|
|
|
+def keyboard_interruption(int_signal, int_frame):
|
|
|
+ """ Catches a keyboard interruption handler
|
|
|
+
|
|
|
+ param int_signal: The signal this handler is called with
|
|
|
+ :type int_signal: Signal
|
|
|
+ param int_frame: The signal this handler is called with
|
|
|
+ :type int_frame: frame
|
|
|
+ :rtype: nothing
|
|
|
+ """
|
|
|
+ print("Signal #: {} Frame: {}".format(int_signal, int_frame))
|
|
|
+ print("Quiting...")
|
|
|
+ sys.exit(0)
|
|
|
+
|
|
|
+
|
|
|
+def main():
|
|
|
+ """ The main function of this module
|
|
|
+ :rtype: nothing
|
|
|
+ """
|
|
|
+ # to quit the build
|
|
|
+ signal.signal(signal.SIGINT, keyboard_interruption)
|
|
|
+
|
|
|
+ # get general build configurations
|
|
|
+ build_config = get_config()
|
|
|
+
|
|
|
+ # get commandline parameters
|
|
|
+ arguments = get_cmd_arguments(build_config)
|
|
|
+
|
|
|
+ if arguments.clean_all:
|
|
|
+ clean(build_config.get("DEFAULT_CONFIG"))
|
|
|
+
|
|
|
+ # get platform specific config
|
|
|
+ platform_config = get_platform_config(arguments.platform, build_config)
|
|
|
+
|
|
|
+ # update general build config with platform specific config
|
|
|
+ config = build_config.get("DEFAULT_CONFIG")
|
|
|
+ config.update(platform_config.get("CONFIG"))
|
|
|
+
|
|
|
+ # if user selected clean
|
|
|
+ if arguments.clean:
|
|
|
+ clean(config, board=True)
|
|
|
+
|
|
|
+ # Override config with cmd arguments
|
|
|
+ cmd_config_args = get_cmd_config_arguments(arguments)
|
|
|
+ config.update(cmd_config_args)
|
|
|
+
|
|
|
+ # get pre_build configurations
|
|
|
+ config = pre_build(config,
|
|
|
+ build_type=arguments.target,
|
|
|
+ toolchain=arguments.toolchain,
|
|
|
+ silent=arguments.silent)
|
|
|
+
|
|
|
+ # build selected platform
|
|
|
+ config = build(config)
|
|
|
+
|
|
|
+ # post build
|
|
|
+ post_build(config)
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == "__main__":
|
|
|
+ try:
|
|
|
+ EXIT_CODE = 0
|
|
|
+ main()
|
|
|
+ except Exception as error:
|
|
|
+ EXIT_CODE = 1
|
|
|
+ traceback.print_exc()
|
|
|
+ sys.exit(EXIT_CODE)
|