12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106 |
- #!/usr/bin/env python3
- #
- # @ build_bios.py
- # Builds BIOS using configuration files and dynamically
- # imported functions from board directory
- #
- # Copyright (c) 2019 - 2020, Intel Corporation. All rights reserved.<BR>
- # Copyright (c) 2021, American Megatrends International LLC.<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 glob
- 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 JSON
- 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 compatible
- 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_FEATURES"] = os.path.join(config["WORKSPACE"],
- config["WORKSPACE_FEATURES"])
- config["WORKSPACE_DRIVERS"] = os.path.join(config["WORKSPACE"],
- config["WORKSPACE_DRIVERS"])
- 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 + config["WORKSPACE_FEATURES"]
- # add all feature domains in WORKSPACE_FEATURES to package path
- for filename in os.listdir(config["WORKSPACE_FEATURES"]):
- filepath = os.path.join(config["WORKSPACE_FEATURES"], filename)
- # feature domains folder does not contain dec file
- if os.path.isdir(filepath) and \
- not glob.glob(os.path.join(filepath, "*.dec")):
- config["PACKAGES_PATH"] += os.pathsep + filepath
- config["PACKAGES_PATH"] += os.pathsep + config["WORKSPACE_DRIVERS"]
- config["PACKAGES_PATH"] += os.pathsep + \
- os.path.join(config["WORKSPACE"], config["WORKSPACE_FSP_BIN"])
- config["PACKAGES_PATH"] += os.pathsep + \
- os.path.join(config["WORKSPACE"], config["WORKSPACE_CORE"])
- config["PACKAGES_PATH"] += os.pathsep + os.path.join(config["WORKSPACE"])
- config["PACKAGES_PATH"] += os.pathsep + config["WORKSPACE_PLATFORM_BIN"]
- 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"])
- #
- # Board may have different FSP binary between API and Dispatch modes.
- # In API mode if FSP_BIN_PKG_FOR_API_MODE is assigned, it should
- # override FSP_BIN_PKG.
- #
- if config.get("API_MODE_FSP_WRAPPER_BUILD", "FALSE") == "TRUE":
- if config.get("FSP_BIN_PKG_FOR_API_MODE") is not None:
- config['FSP_BIN_PKG'] = config['FSP_BIN_PKG_FOR_API_MODE']
- 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:
- if os.environ.get("PYTHONPATH") is not None:
- config["PYTHON_HOME"] = os.environ.get("PYTHONPATH")
- else:
- config["PYTHON_HOME"] = os.path.dirname(sys.executable)
- config["PYTHONPATH"] = config["PYTHON_HOME"]
- if config.get("PYTHON_HOME") is None or \
- not os.path.exists(config.get("PYTHON_HOME")):
- print("PYTHON_HOME 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)
- #
- # build platform silicon tools
- #
- # save the current workspace
- saved_work_directory = config["WORKSPACE"]
- # change the workspace to silicon tools directory
- config["WORKSPACE"] = os.path.join(config["WORKSPACE_SILICON"], "Tools")
- command = ["nmake"]
- if os.name == "posix": # linux
- command = ["make"]
- # add path to generated FitGen binary to
- # environment path variable
- config["PATH"] += os.pathsep + \
- os.path.join(config["BASE_TOOLS_PATH"],
- "Source", "C", "bin")
- # build the silicon tools
- _, _, result, return_code = execute_script(command, config, shell=shell)
- if return_code != 0:
- build_failed(config)
- # restore WORKSPACE environment variable
- config["WORKSPACE"] = saved_work_directory
- 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',
- 'RebaseFspBinBaseAddress.py'),
- os.path.join(config['WORKSPACE_PLATFORM'],
- config['FLASH_MAP_FDF']),
- os.path.join(config['WORKSPACE_FSP_BIN'],
- config['FSP_BIN_PKG']),
- "Fsp.fd",
- "0x0"]
- _, _, _, return_code = execute_script(command, config, shell=False)
- if return_code != 0:
- print("ERROR:RebaseFspBinBaseAddress 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(" BINARY_CACHE_CMD_LINE = ", config.get("HASH"), config.get("BINARY_CACHE_CMD_LINE"))
- 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"] != "":
- ext_build_flags = config["EXT_BUILD_FLAGS"].split(" ")
- ext_build_flags = [x.strip() for x in ext_build_flags]
- ext_build_flags = [x for x in ext_build_flags if x != ""]
- command.extend(ext_build_flags)
- if config.get('BINARY_CACHE_CMD_LINE'):
- command.append(config['HASH'])
- command.append(config['BINARY_CACHE_CMD_LINE'])
- 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"])
- if config.get("API_MODE_FSP_WRAPPER_BUILD", "FALSE") == "TRUE":
- #Override PCD to enable API mode FSP wrapper.
- command.append("--pcd")
- command.append("gIntelFsp2WrapperTokenSpaceGuid.PcdFspModeSelection=1")
- shell = True
- if os.name == "posix":
- shell = False
- _, _, _, exit_code = execute_script(command, config, shell=shell)
- 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.")
- board_fd = config["BOARD"].upper()
- final_fd = os.path.join(config["BUILD_DIR_PATH"], "FV",
- "{}.fd".format(board_fd))
- if config["BIOS_INFO_GUID"]:
- # Generate the fit table
- print("Generating FIT ...")
- if os.path.isfile(final_fd):
- temp_fd = os.path.join(config["BUILD_DIR_PATH"], "FV",
- "{}_.fd".format(board_fd))
- shell = True
- command = ["FitGen", "-D",
- final_fd, temp_fd, "-NA",
- "-I", config["BIOS_INFO_GUID"]] #@todo: Need mechanism to add additional options to the FitGen command line
- if os.name == "posix": # linux
- shell = False
- _, _, result, return_code = execute_script(command, config, shell=shell)
- if return_code != 0:
- print("Error while generating fit")
- else:
- # copy output to final binary
- shutil.copyfile(temp_fd, final_fd)
- # remove temp file
- os.remove(temp_fd)
- else:
- print("{} does not exist".format(final_fd))
- # remove temp file
- # 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
- print("Done")
- if os.path.isfile(final_fd):
- print("Fd file can be found at {}".format(final_fd))
- 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 cleaning
- :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 environment 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 environment 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 cleaning
- :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 specific 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"
- if arguments.fspapi is True:
- result["API_MODE_FSP_WRAPPER_BUILD"] = "TRUE"
- if not arguments.UseHashCache:
- result['BINARY_CACHE_CMD_LINE'] = ''
- elif arguments.BinCacheDest:
- result['HASH'] = '--hash'
- result['BINARY_CACHE_CMD_LINE'] = '--binary-destination=%s' % arguments.BinCacheDest
- elif arguments.BinCacheSource:
- result['HASH'] = '--hash'
- result['BINARY_CACHE_CMD_LINE'] = '--binary-source=%s' % arguments.BinCacheSource
- else:
- result['BINARY_CACHE_CMD_LINE'] = ''
- 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 wrapper build enabled",
- action='store_true', dest="fsp")
- parser.add_argument("--fspapi", help="API mode fsp wrapper build enabled",
- action='store_true', dest="fspapi")
- parser.add_argument("--hash", action="store_true", dest="UseHashCache", default=False,
- help="Enable hash-based caching during build process.")
- parser.add_argument("--binary-destination", help="Generate a cache of binary \
- files in the specified directory.",
- action='store', dest="BinCacheDest")
- parser.add_argument("--binary-source", help="Consume a cache of binary files \
- from the specified directory.",
- action='store', dest="BinCacheSource")
- 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)
|