]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/PackageDocumentTools/packagedoc_cli.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / BaseTools / Scripts / PackageDocumentTools / packagedoc_cli.py
1 ## @file
2 # This module provide command line entry for generating package document!
3 #
4 # Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR>
5 #
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
7 #
8
9 from __future__ import print_function
10 import os, sys, logging, traceback, subprocess
11 from optparse import OptionParser
12
13 from plugins.EdkPlugins.edk2.model import baseobject
14 from plugins.EdkPlugins.edk2.model import doxygengen
15
16 gArchMarcoDict = {'ALL' : 'MDE_CPU_IA32 MDE_CPU_X64 MDE_CPU_EBC MDE_CPU_IPF _MSC_EXTENSIONS __GNUC__ __INTEL_COMPILER',
17 'IA32_MSFT': 'MDE_CPU_IA32 _MSC_EXTENSIONS',
18 'IA32_GNU' : 'MDE_CPU_IA32 __GNUC__',
19 'X64_MSFT' : 'MDE_CPU_X64 _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ',
20 'X64_GNU' : 'MDE_CPU_X64 __GNUC__ ASM_PFX= OPTIONAL= ',
21 'IPF_MSFT' : 'MDE_CPU_IPF _MSC_EXTENSIONS ASM_PFX= OPTIONAL= ',
22 'IPF_GNU' : 'MDE_CPU_IPF __GNUC__ ASM_PFX= OPTIONAL= ',
23 'EBC_INTEL': 'MDE_CPU_EBC __INTEL_COMPILER ASM_PFX= OPTIONAL= '}
24
25 def parseCmdArgs():
26 parser = OptionParser(version="Package Document Generation Tools - Version 0.1")
27 parser.add_option('-w', '--workspace', action='store', type='string', dest='WorkspacePath',
28 help='Specify workspace absolute path. For example: c:\\tianocore')
29 parser.add_option('-p', '--decfile', action='store', dest='PackagePath',
30 help='Specify the absolute path for package DEC file. For example: c:\\tianocore\\MdePkg\\MdePkg.dec')
31 parser.add_option('-x', '--doxygen', action='store', dest='DoxygenPath',
32 help='Specify the absolute path of doxygen tools installation. For example: C:\\Program Files\\doxygen\bin\doxygen.exe')
33 parser.add_option('-o', '--output', action='store', dest='OutputPath',
34 help='Specify the document output path. For example: c:\\docoutput')
35 parser.add_option('-a', '--arch', action='store', dest='Arch', choices=list(gArchMarcoDict.keys()),
36 help='Specify the architecture used in preprocess package\'s source. For example: -a IA32_MSFT')
37 parser.add_option('-m', '--mode', action='store', dest='DocumentMode', choices=['CHM', 'HTML'],
38 help='Specify the document mode from : CHM or HTML')
39 parser.add_option('-i', '--includeonly', action='store_true', dest='IncludeOnly',
40 help='Only generate document for package\'s public interfaces produced by include folder. ')
41 parser.add_option('-c', '--htmlworkshop', dest='HtmlWorkshopPath',
42 help='Specify the absolute path for Microsoft HTML Workshop\'s hhc.exe file. For example: C:\\Program Files\\HTML Help Workshop\\hhc.exe')
43 (options, args) = parser.parse_args()
44
45 # validate the options
46 errors = []
47 if options.WorkspacePath is None:
48 errors.append('- Please specify workspace path via option -w!')
49 elif not os.path.exists(options.WorkspacePath):
50 errors.append("- Invalid workspace path %s! The workspace path should be exist in absolute path!" % options.WorkspacePath)
51
52 if options.PackagePath is None:
53 errors.append('- Please specify package DEC file path via option -p!')
54 elif not os.path.exists(options.PackagePath):
55 errors.append("- Invalid package's DEC file path %s! The DEC path should be exist in absolute path!" % options.PackagePath)
56
57 default = "C:\\Program Files\\doxygen\\bin\\doxygen.exe"
58 if options.DoxygenPath is None:
59 if os.path.exists(default):
60 print("Warning: Assume doxygen tool is installed at %s. If not, please specify via -x" % default)
61 options.DoxygenPath = default
62 else:
63 errors.append('- Please specify the path of doxygen tool installation via option -x! or install it in default path %s' % default)
64 elif not os.path.exists(options.DoxygenPath):
65 errors.append("- Invalid doxygen tool path %s! The doxygen tool path should be exist in absolute path!" % options.DoxygenPath)
66
67 if options.OutputPath is not None:
68 if not os.path.exists(options.OutputPath):
69 # create output
70 try:
71 os.makedirs(options.OutputPath)
72 except:
73 errors.append('- Fail to create the output directory %s' % options.OutputPath)
74 else:
75 if options.PackagePath is not None and os.path.exists(options.PackagePath):
76 dirpath = os.path.dirname(options.PackagePath)
77 default = os.path.join (dirpath, "Document")
78 print('Warning: Assume document output at %s. If not, please specify via option -o' % default)
79 options.OutputPath = default
80 if not os.path.exists(default):
81 try:
82 os.makedirs(default)
83 except:
84 errors.append('- Fail to create default output directory %s! Please specify document output diretory via option -o' % default)
85 else:
86 errors.append('- Please specify document output path via option -o!')
87
88 if options.Arch is None:
89 options.Arch = 'ALL'
90 print("Warning: Assume arch is \"ALL\". If not, specify via -a")
91
92 if options.DocumentMode is None:
93 options.DocumentMode = "HTML"
94 print("Warning: Assume document mode is \"HTML\". If not, specify via -m")
95
96 if options.IncludeOnly is None:
97 options.IncludeOnly = False
98 print("Warning: Assume generate package document for all package\'s source including publich interfaces and implementation libraries and modules.")
99
100 if options.DocumentMode.lower() == 'chm':
101 default = "C:\\Program Files\\HTML Help Workshop\\hhc.exe"
102 if options.HtmlWorkshopPath is None:
103 if os.path.exists(default):
104 print('Warning: Assume the installation path of Microsoft HTML Workshop is %s. If not, specify via option -c.' % default)
105 options.HtmlWorkshopPath = default
106 else:
107 errors.append('- Please specify the installation path of Microsoft HTML Workshop via option -c!')
108 elif not os.path.exists(options.HtmlWorkshopPath):
109 errors.append('- The installation path of Microsoft HTML Workshop %s does not exists. ' % options.HtmlWorkshopPath)
110
111 if len(errors) != 0:
112 print('\n')
113 parser.error('Fail to start due to following reasons: \n%s' %'\n'.join(errors))
114 return (options.WorkspacePath, options.PackagePath, options.DoxygenPath, options.OutputPath,
115 options.Arch, options.DocumentMode, options.IncludeOnly, options.HtmlWorkshopPath)
116
117 def createPackageObject(wsPath, pkgPath):
118 try:
119 pkgObj = baseobject.Package(None, wsPath)
120 pkgObj.Load(pkgPath)
121 except:
122 logging.getLogger().error ('Fail to create package object!')
123 return None
124
125 return pkgObj
126
127 def callbackLogMessage(msg, level):
128 print(msg.strip())
129
130 def callbackCreateDoxygenProcess(doxPath, configPath):
131 if sys.platform == 'win32':
132 cmd = '"%s" %s' % (doxPath, configPath)
133 else:
134 cmd = '%s %s' % (doxPath, configPath)
135 print(cmd)
136 subprocess.call(cmd, shell=True)
137
138
139 def DocumentFixup(outPath, arch):
140 # find BASE_LIBRARY_JUMP_BUFFER structure reference page
141
142 print('\n >>> Start fixup document \n')
143
144 for root, dirs, files in os.walk(outPath):
145 for dir in dirs:
146 if dir.lower() in ['.svn', '_svn', 'cvs']:
147 dirs.remove(dir)
148 for file in files:
149 if not file.lower().endswith('.html'): continue
150 fullpath = os.path.join(outPath, root, file)
151 try:
152 f = open(fullpath, 'r')
153 text = f.read()
154 f.close()
155 except:
156 logging.getLogger().error('\nFail to open file %s\n' % fullpath)
157 continue
158 if arch.lower() == 'all':
159 if text.find('BASE_LIBRARY_JUMP_BUFFER Struct Reference') != -1:
160 FixPageBASE_LIBRARY_JUMP_BUFFER(fullpath, text)
161 if text.find('MdePkg/Include/Library/BaseLib.h File Reference') != -1:
162 FixPageBaseLib(fullpath, text)
163 if text.find('IA32_IDT_GATE_DESCRIPTOR Union Reference') != -1:
164 FixPageIA32_IDT_GATE_DESCRIPTOR(fullpath, text)
165 if text.find('MdePkg/Include/Library/UefiDriverEntryPoint.h File Reference') != -1:
166 FixPageUefiDriverEntryPoint(fullpath, text)
167 if text.find('MdePkg/Include/Library/UefiApplicationEntryPoint.h File Reference') != -1:
168 FixPageUefiApplicationEntryPoint(fullpath, text)
169
170 print(' >>> Finish all document fixing up! \n')
171
172 def FixPageBaseLib(path, text):
173 print(' >>> Fixup BaseLib file page at file %s \n' % path)
174 lines = text.split('\n')
175 lastBaseJumpIndex = -1
176 lastIdtGateDescriptor = -1
177 for index in range(len(lines) - 1, -1, -1):
178 line = lines[index]
179 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4 </td>':
180 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;4&nbsp;[IA32] </td>'
181 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10 </td>':
182 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF] </td>'
183 if line.strip() == '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;8 </td>':
184 lines[index] = '<td class="memname">#define BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT&nbsp;&nbsp;&nbsp;9&nbsp;[EBC, x64] </td>'
185 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4') != -1:
186 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4',
187 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;4&nbsp;[IA32]')
188 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10') != -1:
189 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10',
190 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;0x10&nbsp;[IPF]')
191 if line.find('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8') != -1:
192 lines[index] = lines[index].replace('BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8',
193 'BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT</a>&nbsp;&nbsp;&nbsp;8&nbsp;[x64, EBC]')
194 if line.find('>BASE_LIBRARY_JUMP_BUFFER</a>') != -1:
195 if lastBaseJumpIndex != -1:
196 del lines[lastBaseJumpIndex]
197 lastBaseJumpIndex = index
198 if line.find('>IA32_IDT_GATE_DESCRIPTOR</a></td>') != -1:
199 if lastIdtGateDescriptor != -1:
200 del lines[lastIdtGateDescriptor]
201 lastIdtGateDescriptor = index
202 try:
203 f = open(path, 'w')
204 f.write('\n'.join(lines))
205 f.close()
206 except:
207 logging.getLogger().error(" <<< Fail to fixup file %s\n" % path)
208 return
209 print(" <<< Finish to fixup file %s\n" % path)
210
211 def FixPageIA32_IDT_GATE_DESCRIPTOR(path, text):
212 print(' >>> Fixup structure reference IA32_IDT_GATE_DESCRIPTOR at file %s \n' % path)
213 lines = text.split('\n')
214 for index in range(len(lines) - 1, -1, -1):
215 line = lines[index].strip()
216 if line.find('struct {</td>') != -1 and lines[index - 2].find('>Uint64</a></td>') != -1:
217 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
218 if line.find('struct {</td>') != -1 and lines[index - 1].find('Data Fields') != -1:
219 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
220 try:
221 f = open(path, 'w')
222 f.write('\n'.join(lines))
223 f.close()
224 except:
225 logging.getLogger().error(" <<< Fail to fixup file %s\n" % path)
226 return
227 print(" <<< Finish to fixup file %s\n" % path)
228
229 def FixPageBASE_LIBRARY_JUMP_BUFFER(path, text):
230 print(' >>> Fixup structure reference BASE_LIBRARY_JUMP_BUFFER at file %s \n' % path)
231 lines = text.split('\n')
232 bInDetail = True
233 bNeedRemove = False
234 for index in range(len(lines) - 1, -1, -1):
235 line = lines[index]
236 if line.find('Detailed Description') != -1:
237 bInDetail = False
238 if line.startswith('EBC context buffer used by') and lines[index - 1].startswith('x64 context buffer'):
239 lines[index] = "IA32/IPF/X64/" + line
240 bNeedRemove = True
241 if line.startswith("x64 context buffer") or line.startswith('IPF context buffer used by') or \
242 line.startswith('IA32 context buffer used by'):
243 if bNeedRemove:
244 lines.remove(line)
245 if line.find('>R0</a>') != -1 and not bInDetail:
246 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>':
247 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For EBC</h2></td></tr>')
248 if line.find('>Rbx</a>') != -1 and not bInDetail:
249 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>':
250 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For X64</h2></td></tr>')
251 if line.find('>F2</a>') != -1 and not bInDetail:
252 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>':
253 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IPF</h2></td></tr>')
254 if line.find('>Ebx</a>') != -1 and not bInDetail:
255 if lines[index - 1] != '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>':
256 lines.insert(index, '<tr><td colspan="2"><br><h2>Data Fields For IA32</h2></td></tr>')
257 try:
258 f = open(path, 'w')
259 f.write('\n'.join(lines))
260 f.close()
261 except:
262 logging.getLogger().error(" <<< Fail to fixup file %s" % path)
263 return
264 print(" <<< Finish to fixup file %s\n" % path)
265
266 def FixPageUefiDriverEntryPoint(path, text):
267 print(' >>> Fixup file reference MdePkg/Include/Library/UefiDriverEntryPoint.h at file %s \n' % path)
268 lines = text.split('\n')
269 bInModuleEntry = False
270 bInEfiMain = False
271 ModuleEntryDlCount = 0
272 ModuleEntryDelStart = 0
273 ModuleEntryDelEnd = 0
274 EfiMainDlCount = 0
275 EfiMainDelStart = 0
276 EfiMainDelEnd = 0
277
278 for index in range(len(lines)):
279 line = lines[index].strip()
280 if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
281 bInModuleEntry = True
282 if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
283 bInEfiMain = True
284 if line.startswith('<p>References <a'):
285 if bInModuleEntry:
286 ModuleEntryDelEnd = index - 1
287 bInModuleEntry = False
288 elif bInEfiMain:
289 EfiMainDelEnd = index - 1
290 bInEfiMain = False
291 if bInModuleEntry:
292 if line.startswith('</dl>'):
293 ModuleEntryDlCount = ModuleEntryDlCount + 1
294 if ModuleEntryDlCount == 1:
295 ModuleEntryDelStart = index + 1
296 if bInEfiMain:
297 if line.startswith('</dl>'):
298 EfiMainDlCount = EfiMainDlCount + 1
299 if EfiMainDlCount == 1:
300 EfiMainDelStart = index + 1
301
302 if EfiMainDelEnd > EfiMainDelStart:
303 for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
304 del lines[index]
305 if ModuleEntryDelEnd > ModuleEntryDelStart:
306 for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
307 del lines[index]
308
309 try:
310 f = open(path, 'w')
311 f.write('\n'.join(lines))
312 f.close()
313 except:
314 logging.getLogger().error(" <<< Fail to fixup file %s" % path)
315 return
316 print(" <<< Finish to fixup file %s\n" % path)
317
318
319 def FixPageUefiApplicationEntryPoint(path, text):
320 print(' >>> Fixup file reference MdePkg/Include/Library/UefiApplicationEntryPoint.h at file %s \n' % path)
321 lines = text.split('\n')
322 bInModuleEntry = False
323 bInEfiMain = False
324 ModuleEntryDlCount = 0
325 ModuleEntryDelStart = 0
326 ModuleEntryDelEnd = 0
327 EfiMainDlCount = 0
328 EfiMainDelStart = 0
329 EfiMainDelEnd = 0
330
331 for index in range(len(lines)):
332 line = lines[index].strip()
333 if line.find('EFI_STATUS</a> EFIAPI _ModuleEntryPoint </td>') != -1:
334 bInModuleEntry = True
335 if line.find('EFI_STATUS</a> EFIAPI EfiMain </td>') != -1:
336 bInEfiMain = True
337 if line.startswith('<p>References <a'):
338 if bInModuleEntry:
339 ModuleEntryDelEnd = index - 1
340 bInModuleEntry = False
341 elif bInEfiMain:
342 EfiMainDelEnd = index - 1
343 bInEfiMain = False
344 if bInModuleEntry:
345 if line.startswith('</dl>'):
346 ModuleEntryDlCount = ModuleEntryDlCount + 1
347 if ModuleEntryDlCount == 1:
348 ModuleEntryDelStart = index + 1
349 if bInEfiMain:
350 if line.startswith('</dl>'):
351 EfiMainDlCount = EfiMainDlCount + 1
352 if EfiMainDlCount == 1:
353 EfiMainDelStart = index + 1
354
355 if EfiMainDelEnd > EfiMainDelStart:
356 for index in range(EfiMainDelEnd, EfiMainDelStart, -1):
357 del lines[index]
358 if ModuleEntryDelEnd > ModuleEntryDelStart:
359 for index in range(ModuleEntryDelEnd, ModuleEntryDelStart, -1):
360 del lines[index]
361
362 try:
363 f = open(path, 'w')
364 f.write('\n'.join(lines))
365 f.close()
366 except:
367 logging.getLogger().error(" <<< Fail to fixup file %s" % path)
368 return
369 print(" <<< Finish to fixup file %s\n" % path)
370
371 if __name__ == '__main__':
372 wspath, pkgpath, doxpath, outpath, archtag, docmode, isinc, hwpath = parseCmdArgs()
373
374 # configure logging system
375 logfilepath = os.path.join(outpath, 'log.txt')
376 logging.basicConfig(format='%(levelname)-8s %(message)s', level=logging.DEBUG)
377
378 # create package model object firstly
379 pkgObj = createPackageObject(wspath, pkgpath)
380 if pkgObj is None:
381 sys.exit(-1)
382
383 # create doxygen action model
384 arch = None
385 tooltag = None
386 if archtag.lower() != 'all':
387 arch = archtag.split('_')[0]
388 tooltag = archtag.split('_')[1]
389 else:
390 arch = 'all'
391 tooltag = 'all'
392
393 # preprocess package and call doxygen
394 try:
395 action = doxygengen.PackageDocumentAction(doxpath,
396 hwpath,
397 outpath,
398 pkgObj,
399 docmode,
400 callbackLogMessage,
401 arch,
402 tooltag,
403 isinc,
404 True)
405 action.RegisterCallbackDoxygenProcess(callbackCreateDoxygenProcess)
406 action.Generate()
407 except:
408 message = traceback.format_exception(*sys.exc_info())
409 logging.getLogger().error('Fail to create doxygen action! \n%s' % ''.join(message))
410 sys.exit(-1)
411
412 DocumentFixup(outpath, arch)
413
414 # generate CHM is necessary
415 if docmode.lower() == 'chm':
416 indexpath = os.path.join(outpath, 'html', 'index.hhp')
417 if sys.platform == 'win32':
418 cmd = '"%s" %s' % (hwpath, indexpath)
419 else:
420 cmd = '%s %s' % (hwpath, indexpath)
421 subprocess.call(cmd)
422 print('\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.chm'))
423 else:
424 print('\nFinish to generate package document! Please open %s for review' % os.path.join(outpath, 'html', 'index.html'))