1 # @file Edk2ToolsBuild.py
2 # Invocable class that builds the basetool c files.
4 # Supports VS2017, VS2019, and GCC5
6 # Copyright (c) Microsoft Corporation
8 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 import multiprocessing
15 from edk2toolext
import edk2_logging
16 from edk2toolext
.environment
import self_describing_environment
17 from edk2toolext
.base_abstract_invocable
import BaseAbstractInvocable
18 from edk2toollib
.utility_functions
import RunCmd
19 from edk2toollib
.windows
.locate_tools
import QueryVcVariables
22 class Edk2ToolsBuild(BaseAbstractInvocable
):
24 def ParseCommandLineOptions(self
):
25 ''' parse arguments '''
26 ParserObj
= argparse
.ArgumentParser()
27 ParserObj
.add_argument("-t", "--tool_chain_tag", dest
="tct", default
="VS2017",
28 help="Set the toolchain used to compile the build tools")
29 args
= ParserObj
.parse_args()
30 self
.tool_chain_tag
= args
.tct
32 def GetWorkspaceRoot(self
):
33 ''' Return the workspace root for initializing the SDE '''
35 # this is the bastools dir...not the traditional EDK2 workspace root
36 return os
.path
.dirname(os
.path
.abspath(__file__
))
38 def GetActiveScopes(self
):
39 ''' return tuple containing scopes that should be active for this process '''
41 # for now don't use scopes
44 def GetLoggingLevel(self
, loggerType
):
45 ''' Get the logging level for a given type (return Logging.Level)
46 base == lowest logging level supported
48 txt == plain text file logging
49 md == markdown file logging
51 if(loggerType
== "con"):
56 def GetLoggingFolderRelativeToRoot(self
):
57 ''' Return a path to folder for log files '''
58 return "BaseToolsBuild"
60 def GetVerifyCheckRequired(self
):
61 ''' Will call self_describing_environment.VerifyEnvironment if this returns True '''
64 def GetLoggingFileName(self
, loggerType
):
65 ''' Get the logging file name for the type.
66 Return None if the logger shouldn't be created
68 base == lowest logging level supported
70 txt == plain text file logging
71 md == markdown file logging
73 return "BASETOOLS_BUILD"
75 def WritePathEnvFile(self
, OutputDir
):
76 ''' Write a PyTool path env file for future PyTool based edk2 builds'''
78 # Set shell variable EDK_TOOLS_BIN to this folder
80 # Autogenerated by Edk2ToolsBuild.py
82 # Copyright (c), Microsoft Corporation
83 # SPDX-License-Identifier: BSD-2-Clause-Patent
86 "id": "You-Built-BaseTools",
87 "scope": "edk2-build",
88 "flags": ["set_shell_var", "set_path"],
89 "var_name": "EDK_TOOLS_BIN"
92 with
open(os
.path
.join(OutputDir
, "basetoolsbin_path_env.yaml"), "w") as f
:
96 logging
.info("Running Python version: " + str(sys
.version_info
))
98 (build_env
, shell_env
) = self_describing_environment
.BootstrapEnvironment(
99 self
.GetWorkspaceRoot(), self
.GetActiveScopes())
101 # # Bind our current execution environment into the shell vars.
102 ph
= os
.path
.dirname(sys
.executable
)
105 shell_env
.set_shell_var("PYTHON_HOME", ph
)
106 # PYTHON_COMMAND is required to be set for using edk2 python builds.
110 shell_env
.set_shell_var("PYTHON_COMMAND", pc
)
112 if self
.tool_chain_tag
.lower().startswith("vs"):
114 # # Update environment with required VC vars.
115 interesting_keys
= ["ExtensionSdkDir", "INCLUDE", "LIB"]
116 interesting_keys
.extend(
117 ["LIBPATH", "Path", "UniversalCRTSdkDir", "UCRTVersion", "WindowsLibPath", "WindowsSdkBinPath"])
118 interesting_keys
.extend(
119 ["WindowsSdkDir", "WindowsSdkVerBinPath", "WindowsSDKVersion", "VCToolsInstallDir"])
120 vc_vars
= QueryVcVariables(
121 interesting_keys
, 'x86', vs_version
=self
.tool_chain_tag
.lower())
122 for key
in vc_vars
.keys():
123 logging
.debug(f
"Var - {key} = {vc_vars[key]}")
124 if key
.lower() == 'path':
125 shell_env
.insert_path(vc_vars
[key
])
127 shell_env
.set_shell_var(key
, vc_vars
[key
])
129 self
.OutputDir
= os
.path
.join(
130 shell_env
.get_shell_var("EDK_TOOLS_PATH"), "Bin", "Win32")
132 # compiled tools need to be added to path because antlr is referenced
133 shell_env
.insert_path(self
.OutputDir
)
135 # Actually build the tools.
136 ret
= RunCmd('nmake.exe', None,
137 workingdir
=shell_env
.get_shell_var("EDK_TOOLS_PATH"))
139 raise Exception("Failed to build.")
141 self
.WritePathEnvFile(self
.OutputDir
)
144 elif self
.tool_chain_tag
.lower().startswith("gcc"):
145 cpu_count
= self
.GetCpuThreads()
146 ret
= RunCmd("make", f
"-C . -j {cpu_count}", workingdir
=shell_env
.get_shell_var("EDK_TOOLS_PATH"))
148 raise Exception("Failed to build.")
150 self
.OutputDir
= os
.path
.join(
151 shell_env
.get_shell_var("EDK_TOOLS_PATH"), "Source", "C", "bin")
153 self
.WritePathEnvFile(self
.OutputDir
)
156 logging
.critical("Tool Chain not supported")
159 def GetCpuThreads(self
) -> int:
160 ''' Function to return number of cpus. If error return 1'''
163 cpus
= multiprocessing
.cpu_count()
165 # from the internet there are cases where cpu_count is not implemented.
166 # will handle error by just doing single proc build
173 Edk2ToolsBuild().Invoke()
176 if __name__
== "__main__":