--- /dev/null
+# @file Edk2ToolsBuild.py\r
+# Invocable class that builds the basetool c files.\r
+#\r
+# Supports VS2017, VS2019, and GCC5\r
+##\r
+# Copyright (c) Microsoft Corporation\r
+#\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+import os\r
+import sys\r
+import logging\r
+import argparse\r
+from edk2toolext import edk2_logging\r
+from edk2toolext.environment import self_describing_environment\r
+from edk2toolext.base_abstract_invocable import BaseAbstractInvocable\r
+from edk2toollib.utility_functions import RunCmd\r
+from edk2toollib.windows.locate_tools import QueryVcVariables\r
+\r
+\r
+class Edk2ToolsBuild(BaseAbstractInvocable):\r
+\r
+ def ParseCommandLineOptions(self):\r
+ ''' parse arguments '''\r
+ ParserObj = argparse.ArgumentParser()\r
+ ParserObj.add_argument("-t", "--tool_chain_tag", dest="tct", default="VS2017",\r
+ help="Set the toolchain used to compile the build tools")\r
+ args = ParserObj.parse_args()\r
+ self.tool_chain_tag = args.tct\r
+\r
+ def GetWorkspaceRoot(self):\r
+ ''' Return the workspace root for initializing the SDE '''\r
+\r
+ # this is the bastools dir...not the traditional EDK2 workspace root\r
+ return os.path.dirname(os.path.abspath(__file__))\r
+\r
+ def GetActiveScopes(self):\r
+ ''' return tuple containing scopes that should be active for this process '''\r
+\r
+ # for now don't use scopes\r
+ return ('global',)\r
+\r
+ def GetLoggingLevel(self, loggerType):\r
+ ''' Get the logging level for a given type (return Logging.Level)\r
+ base == lowest logging level supported\r
+ con == Screen logging\r
+ txt == plain text file logging\r
+ md == markdown file logging\r
+ '''\r
+ if(loggerType == "con"):\r
+ return logging.ERROR\r
+ else:\r
+ return logging.DEBUG\r
+\r
+ def GetLoggingFolderRelativeToRoot(self):\r
+ ''' Return a path to folder for log files '''\r
+ return "BaseToolsBuild"\r
+\r
+ def GetVerifyCheckRequired(self):\r
+ ''' Will call self_describing_environment.VerifyEnvironment if this returns True '''\r
+ return True\r
+\r
+ def GetLoggingFileName(self, loggerType):\r
+ ''' Get the logging file name for the type.\r
+ Return None if the logger shouldn't be created\r
+\r
+ base == lowest logging level supported\r
+ con == Screen logging\r
+ txt == plain text file logging\r
+ md == markdown file logging\r
+ '''\r
+ return "BASETOOLS_BUILD"\r
+\r
+ def WritePathEnvFile(self, OutputDir):\r
+ ''' Write a PyTool path env file for future PyTool based edk2 builds'''\r
+ content = '''##\r
+# Set shell variable EDK_TOOLS_BIN to this folder\r
+#\r
+# Autogenerated by Edk2ToolsBuild.py\r
+#\r
+# Copyright (c), Microsoft Corporation\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+##\r
+{\r
+ "id": "You-Built-BaseTools",\r
+ "scope": "edk2-build",\r
+ "flags": ["set_shell_var", "set_path"],\r
+ "var_name": "EDK_TOOLS_BIN"\r
+}\r
+'''\r
+ with open(os.path.join(OutputDir, "basetoolsbin_path_env.yaml"), "w") as f:\r
+ f.write(content)\r
+\r
+ def Go(self):\r
+ logging.info("Running Python version: " + str(sys.version_info))\r
+\r
+ (build_env, shell_env) = self_describing_environment.BootstrapEnvironment(\r
+ self.GetWorkspaceRoot(), self.GetActiveScopes())\r
+\r
+ # # Bind our current execution environment into the shell vars.\r
+ ph = os.path.dirname(sys.executable)\r
+ if " " in ph:\r
+ ph = '"' + ph + '"'\r
+ shell_env.set_shell_var("PYTHON_HOME", ph)\r
+ # PYTHON_COMMAND is required to be set for using edk2 python builds.\r
+ pc = sys.executable\r
+ if " " in pc:\r
+ pc = '"' + pc + '"'\r
+ shell_env.set_shell_var("PYTHON_COMMAND", pc)\r
+\r
+ if self.tool_chain_tag.lower().startswith("vs"):\r
+\r
+ # # Update environment with required VC vars.\r
+ interesting_keys = ["ExtensionSdkDir", "INCLUDE", "LIB"]\r
+ interesting_keys.extend(\r
+ ["LIBPATH", "Path", "UniversalCRTSdkDir", "UCRTVersion", "WindowsLibPath", "WindowsSdkBinPath"])\r
+ interesting_keys.extend(\r
+ ["WindowsSdkDir", "WindowsSdkVerBinPath", "WindowsSDKVersion", "VCToolsInstallDir"])\r
+ vc_vars = QueryVcVariables(\r
+ interesting_keys, 'x86', vs_version=self.tool_chain_tag.lower())\r
+ for key in vc_vars.keys():\r
+ logging.debug(f"Var - {key} = {vc_vars[key]}")\r
+ if key.lower() == 'path':\r
+ shell_env.insert_path(vc_vars[key])\r
+ else:\r
+ shell_env.set_shell_var(key, vc_vars[key])\r
+\r
+ self.OutputDir = os.path.join(\r
+ shell_env.get_shell_var("EDK_TOOLS_PATH"), "Bin", "Win32")\r
+\r
+ # compiled tools need to be added to path because antlr is referenced\r
+ shell_env.insert_path(self.OutputDir)\r
+\r
+ # Actually build the tools.\r
+ ret = RunCmd('nmake.exe', None,\r
+ workingdir=shell_env.get_shell_var("EDK_TOOLS_PATH"))\r
+ if ret != 0:\r
+ raise Exception("Failed to build.")\r
+\r
+ self.WritePathEnvFile(self.OutputDir)\r
+ return ret\r
+\r
+ elif self.tool_chain_tag.lower().startswith("gcc"):\r
+ ret = RunCmd("make", "-C .", workingdir=shell_env.get_shell_var("EDK_TOOLS_PATH"))\r
+ if ret != 0:\r
+ raise Exception("Failed to build.")\r
+\r
+ self.OutputDir = os.path.join(\r
+ shell_env.get_shell_var("EDK_TOOLS_PATH"), "Source", "C", "bin")\r
+\r
+ self.WritePathEnvFile(self.OutputDir)\r
+ return ret\r
+\r
+ logging.critical("Tool Chain not supported")\r
+ return -1\r
+\r
+\r
+def main():\r
+ Edk2ToolsBuild().Invoke()\r
+\r
+\r
+if __name__ == "__main__":\r
+ main()\r