PreBuild.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. ## @file
  2. # PreBuild operations for Vlv2TbltDevicePkg
  3. #
  4. # Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
  5. #
  6. # SPDX-License-Identifier: BSD-2-Clause-Patent
  7. #
  8. '''
  9. PreBuild
  10. '''
  11. import os
  12. import sys
  13. import argparse
  14. import subprocess
  15. import glob
  16. import shutil
  17. import struct
  18. import datetime
  19. #
  20. # Globals for help information
  21. #
  22. __prog__ = 'PreBuild'
  23. __copyright__ = 'Copyright (c) 2019, Intel Corporation. All rights reserved.'
  24. __description__ = 'Vlv2Tbl2DevicePkg pre-build operations.\n'
  25. #
  26. # Globals
  27. #
  28. gWorkspace = ''
  29. gBaseToolsPath = ''
  30. gArgs = None
  31. def LogAlways(Message):
  32. sys.stdout.write (__prog__ + ': ' + Message + '\n')
  33. sys.stdout.flush()
  34. def Log(Message):
  35. global gArgs
  36. if not gArgs.Verbose:
  37. return
  38. sys.stdout.write (__prog__ + ': ' + Message + '\n')
  39. sys.stdout.flush()
  40. def Error(Message, ExitValue=1):
  41. sys.stderr.write (__prog__ + ': ERROR: ' + Message + '\n')
  42. sys.exit (ExitValue)
  43. def RelativePath(target):
  44. global gWorkspace
  45. Log('RelativePath' + target)
  46. return os.path.relpath (target, gWorkspace)
  47. def NormalizePath(target):
  48. if isinstance(target, tuple):
  49. return os.path.normpath (os.path.join (*target))
  50. else:
  51. return os.path.normpath (target)
  52. def RemoveFile(target):
  53. target = NormalizePath(target)
  54. if not target or target == os.pathsep:
  55. Error ('RemoveFile() invalid target')
  56. if os.path.exists(target):
  57. os.remove (target)
  58. Log ('remove %s' % (RelativePath (target)))
  59. def RemoveDirectory(target):
  60. target = NormalizePath(target)
  61. if not target or target == os.pathsep:
  62. Error ('RemoveDirectory() invalid target')
  63. if os.path.exists(target):
  64. Log ('rmdir %s' % (RelativePath (target)))
  65. shutil.rmtree(target)
  66. def CreateDirectory(target):
  67. target = NormalizePath(target)
  68. if not os.path.exists(target):
  69. Log ('mkdir %s' % (RelativePath (target)))
  70. os.makedirs (target)
  71. def Copy(src, dst):
  72. src = NormalizePath(src)
  73. dst = NormalizePath(dst)
  74. for File in glob.glob(src):
  75. Log ('copy %s -> %s' % (RelativePath (File), RelativePath (dst)))
  76. shutil.copy (File, dst)
  77. def GenCapsuleDevice (BaseName, PayloadFileName, Guid, Version, Lsv, CapsulesPath, CapsulesSubDir):
  78. global gBaseToolsPath
  79. LogAlways ('Generate Capsule: {0} {1:08x} {2:08x} {3}'.format (Guid, Version, Lsv, PayloadFileName))
  80. VersionString = '.'.join([str(ord(x)) for x in struct.pack('>I', Version).decode()])
  81. FmpCapsuleFile = NormalizePath ((CapsulesPath, CapsulesSubDir, BaseName + '.' + VersionString + '.cap'))
  82. Command = GenerateCapsuleCommand.format (
  83. FMP_CAPSULE_GUID = Guid,
  84. FMP_CAPSULE_VERSION = Version,
  85. FMP_CAPSULE_LSV = Lsv,
  86. BASE_TOOLS_PATH = gBaseToolsPath,
  87. FMP_CAPSULE_FILE = FmpCapsuleFile,
  88. FMP_CAPSULE_PAYLOAD = PayloadFileName
  89. )
  90. Command = ' '.join(Command.splitlines()).strip()
  91. if gArgs.Verbose:
  92. Command = Command + ' -v'
  93. Log (Command)
  94. Process = subprocess.Popen(Command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  95. ProcessOutput = Process.communicate()
  96. if Process.returncode == 0:
  97. Log (ProcessOutput[0].decode())
  98. else:
  99. LogAlways (Command)
  100. LogAlways (ProcessOutput[0].decode())
  101. Error ('GenerateCapsule returned an error')
  102. Copy (PayloadFileName, (CapsulesPath, 'firmware.bin'))
  103. MetaInfoXml = MetaInfoXmlTemplate
  104. MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_GUID', Guid)
  105. MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_BASE_NAME', BaseName)
  106. MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_VERSION_DECIMAL', str(Version))
  107. MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_STRING', VersionString)
  108. MetaInfoXml = MetaInfoXml.replace ('FMP_CAPSULE_DATE', str(datetime.date.today()))
  109. f = open (NormalizePath ((CapsulesPath, 'firmware.metainfo.xml')), 'w')
  110. f.write(MetaInfoXml)
  111. f.close()
  112. f = open (NormalizePath ((CapsulesPath, 'Lvfs.ddf')), 'w')
  113. f.write(LvfsDdfTemplate)
  114. f.close()
  115. if sys.platform == "win32":
  116. Command = 'makecab /f ' + NormalizePath ((CapsulesPath, 'Lvfs.ddf'))
  117. else:
  118. Command = 'gcab --create firmware.cab firmware.bin firmware.metainfo.xml'
  119. Log (Command)
  120. Process = subprocess.Popen(Command, cwd=CapsulesPath, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  121. ProcessOutput = Process.communicate()
  122. if Process.returncode == 0:
  123. Log (ProcessOutput[0].decode())
  124. else:
  125. LogAlways (Command)
  126. LogAlways (ProcessOutput[0].decode())
  127. Error ('GenerateCapsule returned an error')
  128. FmpCabinetFile = NormalizePath ((CapsulesPath, CapsulesSubDir, BaseName + '.' + VersionString + '.cab'))
  129. Copy ((CapsulesPath, 'firmware.cab'), FmpCabinetFile)
  130. RemoveFile ((CapsulesPath, 'firmware.cab'))
  131. RemoveFile ((CapsulesPath, 'setup.inf'))
  132. RemoveFile ((CapsulesPath, 'setup.rpt'))
  133. RemoveFile ((CapsulesPath, 'Lvfs.ddf'))
  134. RemoveFile ((CapsulesPath, 'firmware.metainfo.xml'))
  135. RemoveFile ((CapsulesPath, 'firmware.bin'))
  136. BiosIdTemplate = '''
  137. BOARD_ID = MNW2MAX
  138. BOARD_REV = $BOARD_REV
  139. BOARD_EXT = $ARCH
  140. VERSION_MAJOR = 0090
  141. BUILD_TYPE = $BUILD_TYPE
  142. VERSION_MINOR = 01
  143. '''
  144. if __name__ == '__main__':
  145. #
  146. # Create command line argument parser object
  147. #
  148. parser = argparse.ArgumentParser (
  149. prog = __prog__,
  150. description = __description__ + __copyright__,
  151. conflict_handler = 'resolve'
  152. )
  153. parser.add_argument (
  154. '-a', '--arch', dest = 'Arch', nargs = '+', action = 'append',
  155. required = True,
  156. help = '''ARCHS is one of list: IA32, X64, IPF, ARM, AARCH64 or EBC,
  157. which overrides target.txt's TARGET_ARCH definition. To
  158. specify more archs, please repeat this option.'''
  159. )
  160. parser.add_argument (
  161. '-t', '--tagname', dest = 'ToolChain', required = True,
  162. help = '''Using the Tool Chain Tagname to build the platform,
  163. overriding target.txt's TOOL_CHAIN_TAG definition.'''
  164. )
  165. parser.add_argument (
  166. '-p', '--platform', dest = 'PlatformFile', required = True,
  167. help = '''Build the platform specified by the DSC file name argument,
  168. overriding target.txt's ACTIVE_PLATFORM definition.'''
  169. )
  170. parser.add_argument (
  171. '-b', '--buildtarget', dest = 'BuildTarget', required = True,
  172. help = '''Using the TARGET to build the platform, overriding
  173. target.txt's TARGET definition.'''
  174. )
  175. parser.add_argument (
  176. '--conf=', dest = 'ConfDirectory', required = True,
  177. help = '''Specify the customized Conf directory.'''
  178. )
  179. parser.add_argument (
  180. '-D', '--define', dest = 'Define', nargs='*', action = 'append',
  181. help = '''Macro: "Name [= Value]".'''
  182. )
  183. parser.add_argument (
  184. '-v', '--verbose', dest = 'Verbose', action = 'store_true',
  185. help = '''Turn on verbose output with informational messages printed'''
  186. )
  187. parser.add_argument (
  188. '--package', dest = 'Package', nargs = '*', action = 'append',
  189. help = '''The directory name of a package of tests to copy'''
  190. )
  191. #
  192. # Parse command line arguments
  193. #
  194. gArgs, remaining = parser.parse_known_args()
  195. gArgs.BuildType = 'all'
  196. for BuildType in ['all', 'fds', 'genc', 'genmake', 'clean', 'cleanall', 'modules', 'libraries', 'run']:
  197. if BuildType in remaining:
  198. gArgs.BuildType = BuildType
  199. remaining.remove(BuildType)
  200. break
  201. gArgs.Remaining = ' '.join(remaining)
  202. #
  203. # Get WORKSPACE environment variable
  204. #
  205. try:
  206. gWorkspace = os.environ['WORKSPACE']
  207. except:
  208. Error ('WORKSPACE environment variable not set')
  209. #
  210. # Get PACKAGES_PATH and generate prioritized list of paths
  211. #
  212. PathList = [gWorkspace]
  213. try:
  214. PathList += os.environ['PACKAGES_PATH'].split(os.pathsep)
  215. except:
  216. pass
  217. #
  218. # Determine full path to BaseTools
  219. #
  220. Vlv2Tbl2DevicePkgPath = ''
  221. for Path in PathList:
  222. if gBaseToolsPath == '':
  223. if os.path.exists (os.path.join (Path, 'BaseTools')):
  224. gBaseToolsPath = os.path.join (Path, 'BaseTools')
  225. if Vlv2Tbl2DevicePkgPath == '':
  226. if os.path.exists (os.path.join (Path, 'Vlv2TbltDevicePkg')):
  227. Vlv2Tbl2DevicePkgPath = os.path.join (Path, 'Vlv2TbltDevicePkg')
  228. if gBaseToolsPath == '':
  229. Error ('Can not find BaseTools in WORKSPACE or PACKAGES_PATH')
  230. if Vlv2Tbl2DevicePkgPath == '':
  231. Error ('Can not find Vlv2Tbl2DevicePkg in WORKSPACE or PACKAGES_PATH')
  232. #
  233. # Parse OUTPUT_DIRECTORY from DSC file
  234. #
  235. for Path in PathList:
  236. if os.path.exists (os.path.join (Path, gArgs.PlatformFile)):
  237. Dsc = open (os.path.join (Path, gArgs.PlatformFile), 'r').readlines()
  238. break
  239. for Line in Dsc:
  240. if Line.strip().startswith('OUTPUT_DIRECTORY'):
  241. OutputDirectory = Line.strip().split('=')[1].strip()
  242. break
  243. #
  244. # Determine full paths to EDK II build directory, EDK II build output
  245. # directory and the CPU arch of the UEFI phase.
  246. #
  247. CommandDir = os.path.dirname(sys.argv[0])
  248. EdkiiBuildDir = os.path.join (gWorkspace, OutputDirectory)
  249. EdkiiBuildOutput = os.path.join (EdkiiBuildDir, gArgs.BuildTarget + '_' + gArgs.ToolChain)
  250. UefiArch = gArgs.Arch[0][0]
  251. if len (gArgs.Arch) > 1:
  252. if ['X64'] in gArgs.Arch:
  253. UefiArch = 'X64'
  254. if gArgs.BuildType == 'run':
  255. Error ("'run' target not supported")
  256. if gArgs.BuildType == 'clean':
  257. sys.exit (0)
  258. #
  259. # Create output directories to put BiosId files
  260. #
  261. try:
  262. CreateDirectory ((gWorkspace, 'Build'))
  263. except:
  264. pass
  265. try:
  266. CreateDirectory ((EdkiiBuildDir))
  267. except:
  268. pass
  269. try:
  270. CreateDirectory ((EdkiiBuildOutput))
  271. except:
  272. pass
  273. #
  274. # Generate BiosId files
  275. #
  276. BiosId = BiosIdTemplate
  277. if sys.platform == "win32":
  278. # Built from a Windows Host OS
  279. BiosId = BiosId.replace ('$BOARD_REV', 'W')
  280. else:
  281. # Built from a Linux/Unix/Mac Host OS
  282. BiosId = BiosId.replace ('$BOARD_REV', 'L')
  283. if UefiArch == 'X64':
  284. BiosId = BiosId.replace ('$ARCH', 'X64')
  285. else:
  286. BiosId = BiosId.replace ('$ARCH', 'I32')
  287. BiosId = BiosId.replace ('$BUILD_TYPE', gArgs.BuildTarget[0])
  288. BiosIdFileName = NormalizePath ((EdkiiBuildOutput, 'BiosId.env'))
  289. f = open (BiosIdFileName, 'w')
  290. f.write(BiosId)
  291. f.close()
  292. Command = 'python ' + NormalizePath ((Vlv2Tbl2DevicePkgPath, '../Tools/GenBiosId/GenBiosId.py'))
  293. Command = Command + ' -i ' + BiosIdFileName
  294. Command = Command + ' -o ' + NormalizePath ((EdkiiBuildOutput, 'BiosId.bin'))
  295. Command = Command + ' -ot ' + NormalizePath ((EdkiiBuildOutput, 'BiosId.txt'))
  296. LogAlways (Command)
  297. Process = subprocess.Popen(Command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
  298. ProcessOutput = Process.communicate()
  299. if Process.returncode == 0:
  300. Log (ProcessOutput[0].decode())
  301. else:
  302. LogAlways (Command)
  303. LogAlways (ProcessOutput[0].decode())
  304. Error ('GenBiosId returned an error')