blob: 0d7f86596b9d19a6fb099332a17c548aa52c8424 [file] [log] [blame]
Justin DeMartino32c10882019-11-05 15:59:43 -08001# Copyright 2019 Google Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Generates gen_headers_<arch>.bp or generates/checks kernel headers."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21import argparse
22import filecmp
23import os
24import re
25import subprocess
26import sys
27
28
29def gen_version_h(verbose, gen_dir, version_makefile):
30 """Generate linux/version.h
31
32 Scan the version_makefile for the version info, and then generate
33 linux/version.h in the gen_dir as done in kernel Makefile function
34 filechk_version.h
35
36 Args:
37 verbose: Set True to print progress messages.
38 gen_dir: Where to place the generated files.
39 version_makefile: The makefile that contains version info.
40 Return:
41 If version info not found, False. Otherwise, True.
42 """
43
44 version_re = re.compile(r'VERSION\s*=\s*(\d+)')
45 patchlevel_re = re.compile(r'PATCHLEVEL\s*=\s*(\d+)')
46 sublevel_re = re.compile(r'SUBLEVEL\s*=\s*(\d+)')
47
48 version_str = None
49 patchlevel_str = None
50 sublevel_str = None
51
52 if verbose:
53 print('gen_version_h: processing [%s]' % version_makefile)
54
55 with open(version_makefile, 'r') as f:
56 while not version_str or not patchlevel_str or not sublevel_str:
57 line = f.readline()
58
59 if not line:
60 print(
61 'error: gen_version_h: failed to parse kernel version from %s' %
62 version_makefile)
63 return False
64
65 line = line.rstrip()
66
67 if verbose:
68 print('gen_version_h: line is %s' % line)
69
70 if not version_str:
71 match = version_re.match(line)
72 if match:
73 if verbose:
74 print('gen_version_h: matched version [%s]' % line)
75 version_str = match.group(1)
76 continue
77
78 if not patchlevel_str:
79 match = patchlevel_re.match(line)
80 if match:
81 if verbose:
82 print('gen_version_h: matched patchlevel [%s]' % line)
83 patchlevel_str = match.group(1)
84 continue
85
86 if not sublevel_str:
87 match = sublevel_re.match(line)
88 if match:
89 if verbose:
90 print('gen_version_h: matched sublevel [%s]' % line)
91 sublevel_str = match.group(1)
92 continue
93
94 version = int(version_str)
95 patchlevel = int(patchlevel_str)
96 sublevel = int(sublevel_str)
97
98 if verbose:
99 print(
100 'gen_version_h: found kernel version %d.%d.%d' %
101 (version, patchlevel, sublevel))
102
103 version_h = os.path.join(gen_dir, 'linux', 'version.h')
104
105 with open(version_h, 'w') as f:
106 # This code must match the code in Makefile in the make function
107 # filechk_version.h
108 version_code = (version << 16) + (patchlevel << 8) + sublevel
109 f.write('#define LINUX_VERSION_CODE %d\n' % version_code)
110 f.write(
111 '#define KERNEL_VERSION(a,b,c) ' +
112 '(((a) << 16) + ((b) << 8) + (c))\n')
113
114 return True
115
116
117def scan_arch_kbuild(verbose, arch_asm_kbuild, asm_generic_kbuild, arch_include_uapi):
118 """Scan arch_asm_kbuild for generated headers.
119
120 This function processes the Kbuild file to scan for three types of files that
121 need to be generated. The first type are syscall generated headers, which are
122 identified by adding to the generated-y make variable. The second type are
123 generic headers, which are arch-specific headers that simply wrap the
124 asm-generic counterpart, and are identified by adding to the generic-y make
125 variable. The third type are mandatory headers that should be present in the
126 /usr/include/asm folder.
127
128 Args:
129 verbose: Set True to print progress messages.
130 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
131 asm_generic_kbuild: The Kbuild file containing lists of mandatory headers.
132 arch_include_uapi: Headers in /arch/<arch>/include/uapi directory
133 Return:
134 Two lists of discovered headers, one for generated and one for generic.
135 """
136
137 generated_y_re = re.compile(r'generated-y\s*\+=\s*(\S+)')
138 generic_y_re = re.compile(r'generic-y\s*\+=\s*(\S+)')
139 mandatory_y_re = re.compile(r'mandatory-y\s*\+=\s*(\S+)')
140
141 # This loop parses arch_asm_kbuild for various kinds of headers to generate.
142
143 if verbose:
144 print('scan_arch_kbuild: processing [%s]' % arch_asm_kbuild)
145
146 generated_list = []
147 generic_list = []
148 arch_include_uapi_list = [os.path.basename(x) for x in arch_include_uapi]
149 mandatory_pre_list = []
150 mandatory_list = []
151
152
153 with open(arch_asm_kbuild, 'r') as f:
154 while True:
155 line = f.readline()
156
157 if not line:
158 break
159
160 line = line.rstrip()
161
162 if verbose:
163 print('scan_arch_kbuild: line is %s' % line)
164
165 match = generated_y_re.match(line)
166
167 if match:
168 if verbose:
169 print('scan_arch_kbuild: matched [%s]' % line)
170 generated_list.append(match.group(1))
171 continue
172
173 match = generic_y_re.match(line)
174
175 if match:
176 if verbose:
177 print('scan_arch_kbuild: matched [%s]' % line)
178 generic_list.append(match.group(1))
179 continue
180
181 # This loop parses asm_generic_kbuild for various kinds of headers to generate.
182
183 if verbose:
184 print('scan_arch_kbuild: processing [%s]' % asm_generic_kbuild)
185
186 with open(asm_generic_kbuild, 'r') as f:
187 while True:
188 line = f.readline()
189
190 if not line:
191 break
192
193 line = line.rstrip()
194
195 if verbose:
196 print('scan_arch_kbuild: line is %s' % line)
197
198 match = mandatory_y_re.match(line)
199
200 if match:
201 if verbose:
202 print('scan_arch_kbuild: matched [%s]' % line)
203 mandatory_pre_list.append(match.group(1))
204 continue
205
206 comb_list = generic_list + generated_list + arch_include_uapi_list
207 mandatory_list = [ x for x in mandatory_pre_list if x not in comb_list]
208 if verbose:
209 print("generic")
210 for x in generic_list:
211 print(x)
212 print("generated")
213 for x in generated_list:
214 print(x)
215 print("mandatory")
216 for x in mandatory_list:
217 print(x)
218 print("arch_include_uapi_list")
219 for x in arch_include_uapi_list:
220 print(x)
221
222 return (generated_list, generic_list, mandatory_list)
223
224
225def gen_arch_headers(
226 verbose, gen_dir, arch_asm_kbuild, asm_generic_kbuild, arch_syscall_tool, arch_syscall_tbl, arch_include_uapi):
227 """Process arch-specific and asm-generic uapi/asm/Kbuild to generate headers.
228
229 The function consists of a call to scan_arch_kbuild followed by three loops.
230 The first loop generates headers found and placed in the generated_list by
231 scan_arch_kbuild. The second loop generates headers found and placed in the
232 generic_list by the scan_arch_kbuild. The third loop generates headers found
233 in mandatory_list by scan_arch_kbuild.
234
235 The function does some parsing of file names and tool invocations. If that
236 parsing fails for some reason (e.g., we don't know how to generate the
237 header) or a tool invocation fails, then this function will count that as
238 an error but keep processing. In the end, the function returns the number of
239 errors encountered.
240
241 Args:
242 verbose: Set True to print progress messages.
243 gen_dir: Where to place the generated files.
244 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
245 asm_generic_kbuild: The Kbuild file containing lists of mandatory headers.
246 arch_syscall_tool: The arch script that generates syscall headers, or None.
247 arch_syscall_tbl: The arch script that defines syscall vectors, or None.
248 arch_include_uapi: Headers in arch/<arch>/include/uapi directory.
249 Return:
250 The number of parsing errors encountered.
251 """
252
253 error_count = 0
254
255 # First generate the lists
256
257 (generated_list, generic_list, mandatory_list) = scan_arch_kbuild(verbose, arch_asm_kbuild, asm_generic_kbuild ,arch_include_uapi)
258
259 # Now we're at the first loop, which is able to generate syscall headers
260 # found in the first loop, and placed in generated_list. It's okay for this
261 # list to be empty. In that case, of course, the loop does nothing.
262
263 abi_re = re.compile(r'unistd-(\S+)\.h')
264
265 for generated in generated_list:
266 gen_h = os.path.join(gen_dir, 'asm', generated)
267 match = abi_re.match(generated)
268
269 if match:
270 abi = match.group(1)
271
272 cmd = [
273 '/bin/bash',
274 arch_syscall_tool,
275 arch_syscall_tbl,
276 gen_h,
277 abi,
278 '',
279 '__NR_SYSCALL_BASE',
280 ]
281
282 if verbose:
283 print('gen_arch_headers: cmd is %s' % cmd)
284
285 result = subprocess.call(cmd)
286
287 if result != 0:
288 print('error: gen_arch_headers: cmd %s failed %d' % (cmd, result))
289 error_count += 1
290 else:
291 print('error: gen_arch_headers: syscall header has bad filename: %s' % generated)
292 error_count += 1
293
294 # Now we're at the second loop, which generates wrappers from arch-specific
295 # headers listed in generic_list to the corresponding asm-generic header.
296
297 for generic in generic_list:
298 wrap_h = os.path.join(gen_dir, 'asm', generic)
299 with open(wrap_h, 'w') as f:
300 f.write('#include <asm-generic/%s>\n' % generic)
301
302 # Now we're at the third loop, which generates wrappers from asm
303 # headers listed in mandatory_list to the corresponding asm-generic header.
304
305 for mandatory in mandatory_list:
306 wrap_h = os.path.join(gen_dir, 'asm', mandatory)
307 with open(wrap_h, 'w') as f:
308 f.write('#include <asm-generic/%s>\n' % mandatory)
309 return error_count
310
311
312def run_headers_install(verbose, gen_dir, headers_install, prefix, h):
313 """Process a header through the headers_install script.
314
315 The headers_install script does some processing of a header so that it is
316 appropriate for inclusion in a userland program. This function invokes that
317 script for one header file.
318
319 The input file is a header file found in the directory named by prefix. This
320 function stips the prefix from the header to generate the name of the
321 processed header.
322
323 Args:
324 verbose: Set True to print progress messages.
325 gen_dir: Where to place the generated files.
326 headers_install: The script that munges the header.
327 prefix: The prefix to strip from h to generate the output filename.
328 h: The input header to process.
329 Return:
330 If parsing or the tool fails, False. Otherwise, True
331 """
332
333 if not h.startswith(prefix):
334 print('error: expected prefix [%s] on header [%s]' % (prefix, h))
335 return False
336
337 out_h = os.path.join(gen_dir, h[len(prefix):])
338 (out_h_dirname, out_h_basename) = os.path.split(out_h)
339 h_dirname = os.path.dirname(h)
340
341 cmd = [headers_install, h, out_h]
342
343 if verbose:
344 print('run_headers_install: cmd is %s' % cmd)
345
346 result = subprocess.call(cmd)
347
348 if result != 0:
349 print('error: run_headers_install: cmd %s failed %d' % (cmd, result))
350 return False
351
352 return True
353
354
355def glob_headers(prefix, rel_glob, excludes):
356 """Recursively scan the a directory for headers.
357
358 This function recursively scans the directory identified by prefix for
359 headers. We don't yet have a new enough version of python3 to use the
360 better glob function, so right now we assume the glob is '**/*.h'.
361
362 The function filters out any files that match the items in excludes.
363
364 Args:
365 prefix: The directory to recursively scan for headers.
366 rel_glob: The shell-style glob that identifies the header pattern.
367 excludes: A list of headers to exclude from the glob.
368 Return:
369 A list of headers discovered with excludes excluded.
370 """
371
372 # If we had python 3.5+, we could use the fancy new glob.glob.
373 # full_glob = os.path.join(prefix, rel_glob)
374 # full_srcs = glob.glob(full_glob, recursive=True)
375
376 full_dirs = [prefix]
377 full_srcs = []
378
379 while full_dirs:
380 full_dir = full_dirs.pop(0)
381 items = sorted(os.listdir(full_dir))
382
383 for item in items:
384 full_item = os.path.join(full_dir, item)
385
386 if os.path.isdir(full_item):
387 full_dirs.append(full_item)
388 continue
389
390 if full_item in excludes:
391 continue
392
393 if full_item.endswith('.h'):
394 full_srcs.append(full_item)
395
396 return full_srcs
397
398
399def find_out(verbose, module_dir, prefix, rel_glob, excludes, outs):
400 """Build a list of outputs for the genrule that creates kernel headers.
401
402 This function scans for headers in the source tree and produces a list of
403 output (generated) headers.
404
405 Args:
406 verbose: Set True to print progress messages.
407 module_dir: The root directory of the kernel source.
408 prefix: The prefix with in the kernel source tree to search for headers.
409 rel_glob: The pattern to use when matching headers under prefix.
410 excludes: A list of files to exclude from the glob.
411 outs: The list to populdate with the headers that will be generated.
412 Return:
413 The number of errors encountered.
414 """
415
416 # Turn prefix, which is relative to the soong module, to a full prefix that
417 # is relative to the Android source tree.
418
419 full_prefix = os.path.join(module_dir, prefix)
420
421 # Convert the list of excludes, which are relative to the soong module, to a
422 # set of excludes (for easy hashing), relative to the Android source tree.
423
424 full_excludes = set()
425
426 if excludes:
427 for exclude in excludes:
428 full_exclude = os.path.join(full_prefix, exclude)
429 full_excludes.add(full_exclude)
430
431 # Glob those headers.
432
433 full_srcs = glob_headers(full_prefix, rel_glob, full_excludes)
434
435 # Now convert the file names, which are relative to the Android source tree,
436 # to be relative to the gen dir. This means stripping off the module prefix
437 # and the directory within this module.
438
439 module_dir_sep = module_dir + os.sep
440 prefix_sep = prefix + os.sep
441
442 if verbose:
443 print('find_out: module_dir_sep [%s]' % module_dir_sep)
444 print('find_out: prefix_sep [%s]' % prefix_sep)
445
446 error_count = 0
447
448 for full_src in full_srcs:
449 if verbose:
450 print('find_out: full_src [%s]' % full_src)
451
452 if not full_src.startswith(module_dir_sep):
453 print('error: expected %s to start with %s' % (full_src, module_dir_sep))
454 error_count += 1
455 continue
456
457 local_src = full_src[len(module_dir_sep):]
458
459 if verbose:
460 print('find_out: local_src [%s]' % local_src)
461
462 if not local_src.startswith(prefix_sep):
463 print('error: expected %s to start with %s' % (local_src, prefix_sep))
464 error_count += 1
465 continue
466
467 # After stripping the module directory and the prefix, we're left with the
468 # name of a header that we'll generate, relative to the base of of a the
469 # the include path.
470
471 local_out = local_src[len(prefix_sep):]
472
473 if verbose:
474 print('find_out: local_out [%s]' % local_out)
475
476 outs.append(local_out)
477
478 return error_count
479
480
481def gen_blueprints(
482 verbose, header_arch, gen_dir, arch_asm_kbuild, asm_generic_kbuild, module_dir,
483 rel_arch_asm_kbuild, rel_asm_generic_kbuild, arch_include_uapi, techpack_include_uapi):
484 """Generate a blueprints file containing modules that invoke this script.
485
486 This function generates a blueprints file that contains modules that
487 invoke this script to generate kernel headers. We generate the blueprints
488 file as needed, but we don't actually use the generated file. The blueprints
489 file that we generate ends up in the out directory, and we can use it to
490 detect if the checked-in version of the file (in the source directory) is out
491 of date. This pattern occurs in the Android source tree in several places.
492
493 Args:
494 verbose: Set True to print progress messages.
495 header_arch: The arch for which to generate headers.
496 gen_dir: Where to place the generated files.
497 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
498 asm_generic_kbuild: The Kbuild file containing lists of mandatory headers.
499 module_dir: The root directory of the kernel source.
500 rel_arch_asm_kbuild: arch_asm_kbuild relative to module_dir.
501 Return:
502 The number of errors encountered.
503 """
504 error_count = 0
505
506 # The old and new blueprints files. We generate the new one, but we need to
507 # refer to the old one in the modules that we generate.
508 old_gen_headers_bp = 'gen_headers_%s.bp' % header_arch
509 new_gen_headers_bp = os.path.join(gen_dir, old_gen_headers_bp)
510
511 # Tools and tool files.
512 headers_install_sh = 'headers_install.sh'
513 kernel_headers_py = 'kernel_headers.py'
514 arm_syscall_tool = 'arch/arm/tools/syscallhdr.sh'
515
516 # Sources
517 makefile = 'Makefile'
518 arm_syscall_tbl = 'arch/arm/tools/syscall.tbl'
519 rel_glob = '**/*.h'
520 generic_prefix = 'include/uapi'
521 arch_prefix = os.path.join('arch', header_arch, generic_prefix)
522 generic_src = os.path.join(generic_prefix, rel_glob)
523 arch_src = os.path.join(arch_prefix, rel_glob)
524 techpack_src = 'techpack/*'
525
526 # Excluded sources, architecture specific.
527 exclude_srcs = []
528
529 if header_arch == "arm":
530 exclude_srcs = ['linux/a.out.h']
531
532 if header_arch == "arm64":
533 exclude_srcs = ['linux/a.out.h']
534
535 # Scan the arch_asm_kbuild file for files that need to be generated and those
536 # that are generic (i.e., need to be wrapped).
537
538 (generated_list, generic_list, mandatory_list) = scan_arch_kbuild(verbose,
539 arch_asm_kbuild, asm_generic_kbuild, arch_include_uapi)
540
541 generic_out = []
542 error_count += find_out(
543 verbose, module_dir, generic_prefix, rel_glob, exclude_srcs, generic_out)
544
545 arch_out = []
546 error_count += find_out(
547 verbose, module_dir, arch_prefix, rel_glob, None, arch_out)
548
549 techpack_out = [x.split('include/uapi/')[1] for x in techpack_include_uapi]
550
551 if error_count != 0:
552 return error_count
553
554 # Generate the blueprints file.
555
556 if verbose:
557 print('gen_blueprints: generating %s' % new_gen_headers_bp)
558
559 with open(new_gen_headers_bp, 'w') as f:
560 f.write('// ***** DO NOT EDIT *****\n')
561 f.write('// This file is generated by %s\n' % kernel_headers_py)
562 f.write('\n')
563 f.write('gen_headers_%s = [\n' % header_arch)
564
565 if generated_list:
566 f.write('\n')
567 f.write(' // Matching generated-y:\n')
568 f.write('\n')
569 for h in generated_list:
570 f.write(' "asm/%s",\n' % h)
571
572 if generic_list:
573 f.write('\n')
574 f.write(' // Matching generic-y:\n')
575 f.write('\n')
576 for h in generic_list:
577 f.write(' "asm/%s",\n' % h)
578
579 if mandatory_list:
580 f.write('\n')
581 f.write(' // Matching mandatory-y:\n')
582 f.write('\n')
583 for h in mandatory_list:
584 f.write(' "asm/%s",\n' % h)
585
586 if generic_out:
587 f.write('\n')
588 f.write(' // From %s\n' % generic_src)
589 f.write('\n')
590 for h in generic_out:
591 f.write(' "%s",\n' % h)
592
593 if arch_out:
594 f.write('\n')
595 f.write(' // From %s\n' % arch_src)
596 f.write('\n')
597 for h in arch_out:
598 f.write(' "%s",\n' % h)
599
600 if techpack_out:
601 f.write('\n')
602 f.write(' // From %s\n' % techpack_src)
603 f.write('\n')
604 for h in techpack_out:
605 f.write(' "%s",\n' % h)
606
607 f.write(']\n')
608 f.write('\n')
609
610 gen_blueprints_module_name = 'qti_generate_gen_headers_%s' % header_arch
611
612 f.write('genrule {\n')
613 f.write(' // This module generates the gen_headers_<arch>.bp file\n')
614 f.write(' // (i.e., a new version of this file) so that it can be\n')
615 f.write(' // checked later to ensure that it matches the checked-\n')
616 f.write(' // in version (this file).\n')
617 f.write(' name: "%s",\n' % gen_blueprints_module_name)
618 f.write(' srcs: ["%s", "%s", "%s"],\n' % (rel_arch_asm_kbuild, rel_asm_generic_kbuild, arch_src))
619 f.write(' tool_files: ["kernel_headers.py"],\n')
620 f.write(' cmd: "python3 $(location kernel_headers.py) " +\n')
621 f.write(' kernel_headers_verbose +\n')
622 f.write(' "--header_arch %s " +\n' % header_arch)
623 f.write(' "--gen_dir $(genDir) " +\n')
624 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
625 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
626 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
627 f.write(' "blueprints",\n')
628 f.write(' out: ["gen_headers_%s.bp"],\n' % header_arch)
629 f.write('}\n')
630 f.write('\n')
631
632 f.write('genrule {\n')
633 f.write(' name: "qti_generate_kernel_headers_%s",\n' % header_arch)
634 f.write(' tools: ["%s"],\n' % headers_install_sh)
635 f.write(' tool_files: [\n')
636 f.write(' "%s",\n' % kernel_headers_py)
637
638 if header_arch == "arm":
639 f.write(' "%s",\n' % arm_syscall_tool)
640
641 f.write(' ],\n')
642 f.write(' srcs: [\n')
643 f.write(' "%s",\n' % rel_arch_asm_kbuild)
644 f.write(' "%s",\n' % rel_asm_generic_kbuild)
645 f.write(' "%s",\n' % old_gen_headers_bp)
646 f.write(' ":%s",\n' % gen_blueprints_module_name)
647 f.write(' "%s",\n' % makefile)
648
649 if header_arch == "arm":
650 f.write(' "%s",\n' % arm_syscall_tbl)
651
652 f.write(' "%s",\n' % generic_src)
653 f.write(' "%s",\n' % arch_src)
654 f.write(' ],\n')
655
656 if exclude_srcs:
657 f.write(' exclude_srcs: [\n')
658 for h in exclude_srcs:
659 f.write(' "%s",\n' % os.path.join(generic_prefix, h))
660 f.write(' ],\n')
661
662 f.write(' cmd: "python3 $(location %s) " +\n' % kernel_headers_py)
663 f.write(' kernel_headers_verbose +\n')
664 f.write(' "--header_arch %s " +\n' % header_arch)
665 f.write(' "--gen_dir $(genDir) " +\n')
666 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
667 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
668 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
669 f.write(' "headers " +\n')
670 f.write(' "--old_gen_headers_bp $(location %s) " +\n' % old_gen_headers_bp)
671 f.write(' "--new_gen_headers_bp $(location :%s) " +\n' % gen_blueprints_module_name)
672 f.write(' "--version_makefile $(location %s) " +\n' % makefile)
673
674 if header_arch == "arm":
675 f.write(' "--arch_syscall_tool $(location %s) " +\n' % arm_syscall_tool)
676 f.write(' "--arch_syscall_tbl $(location %s) " +\n' % arm_syscall_tbl)
677
678 f.write(' "--headers_install $(location %s) " +\n' % headers_install_sh)
679 f.write(' "--include_uapi $(locations %s)",\n' % generic_src)
680 f.write(' out: ["linux/version.h"] + gen_headers_%s,\n' % header_arch)
681 f.write('}\n')
682
683 return 0
684
Siddharth Guptafc242a92020-01-29 17:22:38 -0800685def parse_bp_for_headers(file_name, headers):
686 parsing_headers = False
687 pattern = re.compile("gen_headers_[a-zA-Z0-9]+\s*=\s*\[\s*")
688 with open(file_name, 'r') as f:
689 for line in f:
690 line = line.strip()
691 if pattern.match(line):
692 parsing_headers = True
693 continue
694
695 if line.find("]") != -1 and parsing_headers:
696 break
697
698 if not parsing_headers:
699 continue
700
701 if line.find("//") == 0:
702 continue
703
704 headers.add(line[1:-2])
705
706def headers_diff(old_file, new_file):
707 old_headers = set()
708 new_headers = set()
709 diff_detected = False
710
711 parse_bp_for_headers(old_file, old_headers)
712 parse_bp_for_headers(new_file, new_headers)
713
714 diff = old_headers - new_headers
715 if len(diff):
716 diff_detected = True
717 print("Headers to remove:")
718 for x in diff:
719 print("\t{}".format(x))
720
721 diff = new_headers - old_headers
722 if len(diff):
723 diff_detected = True
724 print("Headers to add:")
725 for x in diff:
726 print("\t{}".format(x))
727
728 return diff_detected
Justin DeMartino32c10882019-11-05 15:59:43 -0800729
730def gen_headers(
731 verbose, header_arch, gen_dir, arch_asm_kbuild, asm_generic_kbuild, module_dir,
732 old_gen_headers_bp, new_gen_headers_bp, version_makefile,
733 arch_syscall_tool, arch_syscall_tbl, headers_install, include_uapi,
734 arch_include_uapi, techpack_include_uapi):
735 """Generate the kernel headers.
736
737 This script generates the version.h file, the arch-specific headers including
738 syscall-related generated files and wrappers around generic files, and uses
739 the headers_install tool to process other generic uapi and arch-specifc uapi
740 files.
741
742 Args:
743 verbose: Set True to print progress messages.
744 header_arch: The arch for which to generate headers.
745 gen_dir: Where to place the generated files.
746 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
747 asm_generic_kbuild: The Kbuild file containing mandatory headers.
748 module_dir: The root directory of the kernel source.
749 old_gen_headers_bp: The old gen_headers_<arch>.bp file to check.
750 new_gen_headers_bp: The new gen_headers_<arch>.bp file to check.
751 version_makefile: The kernel Makefile that contains version info.
752 arch_syscall_tool: The arch script that generates syscall headers.
753 arch_syscall_tbl: The arch script that defines syscall vectors.
754 headers_install: The headers_install tool to process input headers.
755 include_uapi: The list of include/uapi header files.
756 arch_include_uapi: The list of arch/<arch>/include/uapi header files.
757 Return:
758 The number of errors encountered.
759 """
760
Siddharth Guptafc242a92020-01-29 17:22:38 -0800761 if headers_diff(old_gen_headers_bp, new_gen_headers_bp):
Justin DeMartino32c10882019-11-05 15:59:43 -0800762 print('error: gen_headers blueprints file is out of date, suggested fix:')
Siddharth Guptafc242a92020-01-29 17:22:38 -0800763 print('#######Please add or remove the above mentioned headers from %s' % (old_gen_headers_bp))
Justin DeMartino32c10882019-11-05 15:59:43 -0800764 print('then re-run the build')
765 return 1
766
767 error_count = 0
768
769 if not gen_version_h(verbose, gen_dir, version_makefile):
770 error_count += 1
771
772 error_count += gen_arch_headers(
773 verbose, gen_dir, arch_asm_kbuild, asm_generic_kbuild, arch_syscall_tool, arch_syscall_tbl ,arch_include_uapi)
774
775 uapi_include_prefix = os.path.join(module_dir, 'include', 'uapi') + os.sep
776
777 arch_uapi_include_prefix = os.path.join(
778 module_dir, 'arch', header_arch, 'include', 'uapi') + os.sep
779
780 for h in include_uapi:
781 if not run_headers_install(
782 verbose, gen_dir, headers_install,
783 uapi_include_prefix, h):
784 error_count += 1
785
786 for h in arch_include_uapi:
787 if not run_headers_install(
788 verbose, gen_dir, headers_install,
789 arch_uapi_include_prefix, h):
790 error_count += 1
791
792 for h in techpack_include_uapi:
793 techpack_uapi_include_prefix = os.path.join(h.split('/include/uapi')[0], 'include', 'uapi') + os.sep
794 if not run_headers_install(
795 verbose, gen_dir, headers_install,
796 techpack_uapi_include_prefix, h):
797 error_count += 1
798
799 return error_count
800
801def extract_techpack_uapi_headers(verbose, module_dir):
802
803 """EXtract list of uapi headers from techpack/* directories. We need to export
804 these headers to userspace.
805
806 Args:
807 verbose: Verbose option is provided to script
808 module_dir: Base directory
809 Returs:
810 List of uapi headers
811 """
812
813 techpack_subdir = []
814 techpack_dir = os.path.join(module_dir,'techpack')
815 techpack_uapi = []
816 techpack_uapi_sub = []
817
818 #get list of techpack directories under techpack/
819 if os.path.isdir(techpack_dir):
820 items = sorted(os.listdir(techpack_dir))
821 for x in items:
822 p = os.path.join(techpack_dir, x)
823 if os.path.isdir(p):
824 techpack_subdir.append(p)
825
826 #Print list of subdirs obtained
827 if (verbose):
828 for x in techpack_subdir:
829 print(x)
830
831 #For every subdirectory get list of .h files under include/uapi and append to techpack_uapi list
832 for x in techpack_subdir:
833 techpack_uapi_path = os.path.join(x, 'include/uapi')
834 if (os.path.isdir(techpack_uapi_path)):
835 techpack_uapi_sub = []
836 find_out(verbose, x, 'include/uapi', '**/*.h', None, techpack_uapi_sub)
837 tmp = [os.path.join(techpack_uapi_path, y) for y in techpack_uapi_sub]
838 techpack_uapi = techpack_uapi + tmp
839
840 if (verbose):
841 for x in techpack_uapi:
842 print(x)
843
844 return techpack_uapi
845
846def main():
847 """Parse command line arguments and perform top level control."""
848
849 parser = argparse.ArgumentParser(
850 description=__doc__,
851 formatter_class=argparse.RawDescriptionHelpFormatter)
852
853 # Arguments that apply to every invocation of this script.
854
855 parser.add_argument(
856 '--verbose',
857 action='store_true',
858 help='Print output that describes the workings of this script.')
859 parser.add_argument(
860 '--header_arch',
861 required=True,
862 help='The arch for which to generate headers.')
863 parser.add_argument(
864 '--gen_dir',
865 required=True,
866 help='Where to place the generated files.')
867 parser.add_argument(
868 '--arch_asm_kbuild',
869 required=True,
870 help='The Kbuild file containing lists of headers to generate.')
871 parser.add_argument(
872 '--asm_generic_kbuild',
873 required=True,
874 help='The Kbuild file containing lists of mandatory headers.')
875 parser.add_argument(
876 '--arch_include_uapi',
877 required=True,
878 nargs='*',
879 help='The list of arch/<arch>/include/uapi header files.')
880
881 # The modes.
882
883 subparsers = parser.add_subparsers(
884 dest='mode',
885 help='Select mode')
886 parser_blueprints = subparsers.add_parser(
887 'blueprints',
888 help='Generate the gen_headers_<arch>.bp file.')
889 parser_headers = subparsers.add_parser(
890 'headers',
891 help='Check blueprints, then generate kernel headers.')
892
893 # Arguments that apply to headers mode.
894
895 parser_headers.add_argument(
896 '--old_gen_headers_bp',
897 required=True,
898 help='The old gen_headers_<arch>.bp file to check.')
899 parser_headers.add_argument(
900 '--new_gen_headers_bp',
901 required=True,
902 help='The new gen_headers_<arch>.bp file to check.')
903 parser_headers.add_argument(
904 '--version_makefile',
905 required=True,
906 help='The kernel Makefile that contains version info.')
907 parser_headers.add_argument(
908 '--arch_syscall_tool',
909 help='The arch script that generates syscall headers, if applicable.')
910 parser_headers.add_argument(
911 '--arch_syscall_tbl',
912 help='The arch script that defines syscall vectors, if applicable.')
913 parser_headers.add_argument(
914 '--headers_install',
915 required=True,
916 help='The headers_install tool to process input headers.')
917 parser_headers.add_argument(
918 '--include_uapi',
919 required=True,
920 nargs='*',
921 help='The list of include/uapi header files.')
922
923 args = parser.parse_args()
924
925 if args.verbose:
926 print('mode [%s]' % args.mode)
927 print('header_arch [%s]' % args.header_arch)
928 print('gen_dir [%s]' % args.gen_dir)
929 print('arch_asm_kbuild [%s]' % args.arch_asm_kbuild)
930 print('asm_generic_kbuild [%s]' % args.asm_generic_kbuild)
931
932 # Extract the module_dir from args.arch_asm_kbuild and rel_arch_asm_kbuild.
933
934 rel_arch_asm_kbuild = os.path.join(
935 'arch', args.header_arch, 'include/uapi/asm/Kbuild')
936
937 suffix = os.sep + rel_arch_asm_kbuild
938
939 if not args.arch_asm_kbuild.endswith(suffix):
940 print('error: expected %s to end with %s' % (args.arch_asm_kbuild, suffix))
941 return 1
942
943 module_dir = args.arch_asm_kbuild[:-len(suffix)]
944
945 rel_asm_generic_kbuild = os.path.join('include/uapi/asm-generic', os.path.basename(args.asm_generic_kbuild))
946
947
948 if args.verbose:
949 print('module_dir [%s]' % module_dir)
950
951 # Get list of techpack uapi headers to be exported from techpack/* directories.
952 techpack_uapi = extract_techpack_uapi_headers(args.verbose, module_dir)
953
954
955 if args.mode == 'blueprints':
956 return gen_blueprints(
957 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
958 args.asm_generic_kbuild, module_dir, rel_arch_asm_kbuild, rel_asm_generic_kbuild, args.arch_include_uapi, techpack_uapi)
959
960 if args.mode == 'headers':
961 if args.verbose:
962 print('old_gen_headers_bp [%s]' % args.old_gen_headers_bp)
963 print('new_gen_headers_bp [%s]' % args.new_gen_headers_bp)
964 print('version_makefile [%s]' % args.version_makefile)
965 print('arch_syscall_tool [%s]' % args.arch_syscall_tool)
966 print('arch_syscall_tbl [%s]' % args.arch_syscall_tbl)
967 print('headers_install [%s]' % args.headers_install)
968
969 return gen_headers(
970 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
971 args.asm_generic_kbuild, module_dir, args.old_gen_headers_bp, args.new_gen_headers_bp,
972 args.version_makefile, args.arch_syscall_tool, args.arch_syscall_tbl,
973 args.headers_install, args.include_uapi, args.arch_include_uapi, techpack_uapi)
974
975 print('error: unknown mode: %s' % args.mode)
976 return 1
977
978
979if __name__ == '__main__':
980 sys.exit(main())