blob: 3df0915431847abdf1e1fa732de845ef8107746d [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)
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800524 techpack_src = os.path.join('techpack/*',generic_prefix, '*',rel_glob)
Justin DeMartino32c10882019-11-05 15:59:43 -0800525
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')
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800563 f.write('gen_headers_srcs_%s = [\n' % header_arch)
564 f.write(' "%s",\n' % rel_arch_asm_kbuild)
565 f.write(' "%s",\n' % rel_asm_generic_kbuild)
566 f.write(' "%s",\n' % makefile)
567
568 if header_arch == "arm":
569 f.write(' "%s",\n' % arm_syscall_tbl)
570
571 f.write(' "%s",\n' % generic_src)
572 f.write(' "%s",\n' % arch_src)
573 f.write(' "%s",\n' % techpack_src)
574 f.write(']\n')
575 f.write('\n')
576
577 if exclude_srcs:
578 f.write('gen_headers_exclude_srcs_%s = [\n' % header_arch)
579 for h in exclude_srcs:
580 f.write(' "%s",\n' % os.path.join(generic_prefix, h))
581 f.write(']\n')
582 f.write('\n')
583
584 f.write('gen_headers_out_%s = [\n' % header_arch)
Justin DeMartino32c10882019-11-05 15:59:43 -0800585
586 if generated_list:
587 f.write('\n')
588 f.write(' // Matching generated-y:\n')
589 f.write('\n')
590 for h in generated_list:
591 f.write(' "asm/%s",\n' % h)
592
593 if generic_list:
594 f.write('\n')
595 f.write(' // Matching generic-y:\n')
596 f.write('\n')
597 for h in generic_list:
598 f.write(' "asm/%s",\n' % h)
599
600 if mandatory_list:
601 f.write('\n')
602 f.write(' // Matching mandatory-y:\n')
603 f.write('\n')
604 for h in mandatory_list:
605 f.write(' "asm/%s",\n' % h)
606
607 if generic_out:
608 f.write('\n')
609 f.write(' // From %s\n' % generic_src)
610 f.write('\n')
611 for h in generic_out:
612 f.write(' "%s",\n' % h)
613
614 if arch_out:
615 f.write('\n')
616 f.write(' // From %s\n' % arch_src)
617 f.write('\n')
618 for h in arch_out:
619 f.write(' "%s",\n' % h)
620
621 if techpack_out:
622 f.write('\n')
623 f.write(' // From %s\n' % techpack_src)
624 f.write('\n')
625 for h in techpack_out:
626 f.write(' "%s",\n' % h)
627
628 f.write(']\n')
629 f.write('\n')
630
631 gen_blueprints_module_name = 'qti_generate_gen_headers_%s' % header_arch
632
633 f.write('genrule {\n')
634 f.write(' // This module generates the gen_headers_<arch>.bp file\n')
635 f.write(' // (i.e., a new version of this file) so that it can be\n')
636 f.write(' // checked later to ensure that it matches the checked-\n')
637 f.write(' // in version (this file).\n')
638 f.write(' name: "%s",\n' % gen_blueprints_module_name)
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800639 f.write(' srcs: gen_headers_srcs_%s,\n' % header_arch)
640 if exclude_srcs:
641 f.write(' exclude_srcs: gen_headers_exclude_srcs_%s,\n' % header_arch)
642
Justin DeMartino32c10882019-11-05 15:59:43 -0800643 f.write(' tool_files: ["kernel_headers.py"],\n')
644 f.write(' cmd: "python3 $(location kernel_headers.py) " +\n')
645 f.write(' kernel_headers_verbose +\n')
646 f.write(' "--header_arch %s " +\n' % header_arch)
647 f.write(' "--gen_dir $(genDir) " +\n')
648 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
649 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800650 f.write(' "--techpack_include_uapi $(locations %s) " +\n' % techpack_src)
Justin DeMartino32c10882019-11-05 15:59:43 -0800651 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800652 f.write(' "blueprints " +\n')
653 f.write(' "# $(in)",\n')
Justin DeMartino32c10882019-11-05 15:59:43 -0800654 f.write(' out: ["gen_headers_%s.bp"],\n' % header_arch)
655 f.write('}\n')
656 f.write('\n')
657
658 f.write('genrule {\n')
659 f.write(' name: "qti_generate_kernel_headers_%s",\n' % header_arch)
660 f.write(' tools: ["%s"],\n' % headers_install_sh)
661 f.write(' tool_files: [\n')
662 f.write(' "%s",\n' % kernel_headers_py)
663
664 if header_arch == "arm":
665 f.write(' "%s",\n' % arm_syscall_tool)
666
667 f.write(' ],\n')
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800668 f.write(' srcs: gen_headers_srcs_%s +[\n' % header_arch)
Justin DeMartino32c10882019-11-05 15:59:43 -0800669 f.write(' "%s",\n' % old_gen_headers_bp)
670 f.write(' ":%s",\n' % gen_blueprints_module_name)
Justin DeMartino32c10882019-11-05 15:59:43 -0800671 f.write(' ],\n')
672
673 if exclude_srcs:
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800674 f.write(' exclude_srcs: gen_headers_exclude_srcs_%s,\n' % header_arch)
Justin DeMartino32c10882019-11-05 15:59:43 -0800675
676 f.write(' cmd: "python3 $(location %s) " +\n' % kernel_headers_py)
677 f.write(' kernel_headers_verbose +\n')
678 f.write(' "--header_arch %s " +\n' % header_arch)
679 f.write(' "--gen_dir $(genDir) " +\n')
680 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
681 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800682 f.write(' "--techpack_include_uapi $(locations %s) " +\n' % techpack_src)
Justin DeMartino32c10882019-11-05 15:59:43 -0800683 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
684 f.write(' "headers " +\n')
685 f.write(' "--old_gen_headers_bp $(location %s) " +\n' % old_gen_headers_bp)
686 f.write(' "--new_gen_headers_bp $(location :%s) " +\n' % gen_blueprints_module_name)
687 f.write(' "--version_makefile $(location %s) " +\n' % makefile)
688
689 if header_arch == "arm":
690 f.write(' "--arch_syscall_tool $(location %s) " +\n' % arm_syscall_tool)
691 f.write(' "--arch_syscall_tbl $(location %s) " +\n' % arm_syscall_tbl)
692
693 f.write(' "--headers_install $(location %s) " +\n' % headers_install_sh)
694 f.write(' "--include_uapi $(locations %s)",\n' % generic_src)
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800695 f.write(' out: ["linux/version.h"] + gen_headers_out_%s,\n' % header_arch)
Justin DeMartino32c10882019-11-05 15:59:43 -0800696 f.write('}\n')
697
698 return 0
699
Siddharth Guptafc242a92020-01-29 17:22:38 -0800700def parse_bp_for_headers(file_name, headers):
701 parsing_headers = False
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800702 pattern = re.compile("gen_headers_out_[a-zA-Z0-9]+\s*=\s*\[\s*")
Siddharth Guptafc242a92020-01-29 17:22:38 -0800703 with open(file_name, 'r') as f:
704 for line in f:
705 line = line.strip()
706 if pattern.match(line):
707 parsing_headers = True
708 continue
709
710 if line.find("]") != -1 and parsing_headers:
711 break
712
713 if not parsing_headers:
714 continue
715
716 if line.find("//") == 0:
717 continue
718
719 headers.add(line[1:-2])
720
721def headers_diff(old_file, new_file):
722 old_headers = set()
723 new_headers = set()
724 diff_detected = False
725
726 parse_bp_for_headers(old_file, old_headers)
727 parse_bp_for_headers(new_file, new_headers)
728
729 diff = old_headers - new_headers
730 if len(diff):
731 diff_detected = True
732 print("Headers to remove:")
733 for x in diff:
734 print("\t{}".format(x))
735
736 diff = new_headers - old_headers
737 if len(diff):
738 diff_detected = True
739 print("Headers to add:")
740 for x in diff:
741 print("\t{}".format(x))
742
743 return diff_detected
Justin DeMartino32c10882019-11-05 15:59:43 -0800744
745def gen_headers(
746 verbose, header_arch, gen_dir, arch_asm_kbuild, asm_generic_kbuild, module_dir,
747 old_gen_headers_bp, new_gen_headers_bp, version_makefile,
748 arch_syscall_tool, arch_syscall_tbl, headers_install, include_uapi,
749 arch_include_uapi, techpack_include_uapi):
750 """Generate the kernel headers.
751
752 This script generates the version.h file, the arch-specific headers including
753 syscall-related generated files and wrappers around generic files, and uses
754 the headers_install tool to process other generic uapi and arch-specifc uapi
755 files.
756
757 Args:
758 verbose: Set True to print progress messages.
759 header_arch: The arch for which to generate headers.
760 gen_dir: Where to place the generated files.
761 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
762 asm_generic_kbuild: The Kbuild file containing mandatory headers.
763 module_dir: The root directory of the kernel source.
764 old_gen_headers_bp: The old gen_headers_<arch>.bp file to check.
765 new_gen_headers_bp: The new gen_headers_<arch>.bp file to check.
766 version_makefile: The kernel Makefile that contains version info.
767 arch_syscall_tool: The arch script that generates syscall headers.
768 arch_syscall_tbl: The arch script that defines syscall vectors.
769 headers_install: The headers_install tool to process input headers.
770 include_uapi: The list of include/uapi header files.
771 arch_include_uapi: The list of arch/<arch>/include/uapi header files.
772 Return:
773 The number of errors encountered.
774 """
775
Siddharth Guptafc242a92020-01-29 17:22:38 -0800776 if headers_diff(old_gen_headers_bp, new_gen_headers_bp):
Justin DeMartino32c10882019-11-05 15:59:43 -0800777 print('error: gen_headers blueprints file is out of date, suggested fix:')
Siddharth Guptafc242a92020-01-29 17:22:38 -0800778 print('#######Please add or remove the above mentioned headers from %s' % (old_gen_headers_bp))
Justin DeMartino32c10882019-11-05 15:59:43 -0800779 print('then re-run the build')
Rishabh Bhatnagar20004262020-04-14 21:47:30 -0700780 #return 1
Justin DeMartino32c10882019-11-05 15:59:43 -0800781
782 error_count = 0
783
784 if not gen_version_h(verbose, gen_dir, version_makefile):
785 error_count += 1
786
787 error_count += gen_arch_headers(
788 verbose, gen_dir, arch_asm_kbuild, asm_generic_kbuild, arch_syscall_tool, arch_syscall_tbl ,arch_include_uapi)
789
790 uapi_include_prefix = os.path.join(module_dir, 'include', 'uapi') + os.sep
791
792 arch_uapi_include_prefix = os.path.join(
793 module_dir, 'arch', header_arch, 'include', 'uapi') + os.sep
794
795 for h in include_uapi:
796 if not run_headers_install(
797 verbose, gen_dir, headers_install,
798 uapi_include_prefix, h):
799 error_count += 1
800
801 for h in arch_include_uapi:
802 if not run_headers_install(
803 verbose, gen_dir, headers_install,
804 arch_uapi_include_prefix, h):
805 error_count += 1
806
807 for h in techpack_include_uapi:
808 techpack_uapi_include_prefix = os.path.join(h.split('/include/uapi')[0], 'include', 'uapi') + os.sep
809 if not run_headers_install(
810 verbose, gen_dir, headers_install,
811 techpack_uapi_include_prefix, h):
812 error_count += 1
813
814 return error_count
815
816def extract_techpack_uapi_headers(verbose, module_dir):
817
818 """EXtract list of uapi headers from techpack/* directories. We need to export
819 these headers to userspace.
820
821 Args:
822 verbose: Verbose option is provided to script
823 module_dir: Base directory
824 Returs:
825 List of uapi headers
826 """
827
828 techpack_subdir = []
829 techpack_dir = os.path.join(module_dir,'techpack')
830 techpack_uapi = []
831 techpack_uapi_sub = []
832
833 #get list of techpack directories under techpack/
834 if os.path.isdir(techpack_dir):
835 items = sorted(os.listdir(techpack_dir))
836 for x in items:
837 p = os.path.join(techpack_dir, x)
838 if os.path.isdir(p):
839 techpack_subdir.append(p)
840
841 #Print list of subdirs obtained
842 if (verbose):
843 for x in techpack_subdir:
844 print(x)
845
846 #For every subdirectory get list of .h files under include/uapi and append to techpack_uapi list
847 for x in techpack_subdir:
848 techpack_uapi_path = os.path.join(x, 'include/uapi')
849 if (os.path.isdir(techpack_uapi_path)):
850 techpack_uapi_sub = []
851 find_out(verbose, x, 'include/uapi', '**/*.h', None, techpack_uapi_sub)
852 tmp = [os.path.join(techpack_uapi_path, y) for y in techpack_uapi_sub]
853 techpack_uapi = techpack_uapi + tmp
854
855 if (verbose):
856 for x in techpack_uapi:
857 print(x)
858
859 return techpack_uapi
860
861def main():
862 """Parse command line arguments and perform top level control."""
863
864 parser = argparse.ArgumentParser(
865 description=__doc__,
866 formatter_class=argparse.RawDescriptionHelpFormatter)
867
868 # Arguments that apply to every invocation of this script.
869
870 parser.add_argument(
871 '--verbose',
872 action='store_true',
873 help='Print output that describes the workings of this script.')
874 parser.add_argument(
875 '--header_arch',
876 required=True,
877 help='The arch for which to generate headers.')
878 parser.add_argument(
879 '--gen_dir',
880 required=True,
881 help='Where to place the generated files.')
882 parser.add_argument(
883 '--arch_asm_kbuild',
884 required=True,
885 help='The Kbuild file containing lists of headers to generate.')
886 parser.add_argument(
887 '--asm_generic_kbuild',
888 required=True,
889 help='The Kbuild file containing lists of mandatory headers.')
890 parser.add_argument(
891 '--arch_include_uapi',
892 required=True,
893 nargs='*',
894 help='The list of arch/<arch>/include/uapi header files.')
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800895 parser.add_argument(
896 '--techpack_include_uapi',
897 required=True,
898 nargs='*',
899 help='The list of techpack/*/include/uapi header files.')
Justin DeMartino32c10882019-11-05 15:59:43 -0800900
901 # The modes.
902
903 subparsers = parser.add_subparsers(
904 dest='mode',
905 help='Select mode')
906 parser_blueprints = subparsers.add_parser(
907 'blueprints',
908 help='Generate the gen_headers_<arch>.bp file.')
909 parser_headers = subparsers.add_parser(
910 'headers',
911 help='Check blueprints, then generate kernel headers.')
912
913 # Arguments that apply to headers mode.
914
915 parser_headers.add_argument(
916 '--old_gen_headers_bp',
917 required=True,
918 help='The old gen_headers_<arch>.bp file to check.')
919 parser_headers.add_argument(
920 '--new_gen_headers_bp',
921 required=True,
922 help='The new gen_headers_<arch>.bp file to check.')
923 parser_headers.add_argument(
924 '--version_makefile',
925 required=True,
926 help='The kernel Makefile that contains version info.')
927 parser_headers.add_argument(
928 '--arch_syscall_tool',
929 help='The arch script that generates syscall headers, if applicable.')
930 parser_headers.add_argument(
931 '--arch_syscall_tbl',
932 help='The arch script that defines syscall vectors, if applicable.')
933 parser_headers.add_argument(
934 '--headers_install',
935 required=True,
936 help='The headers_install tool to process input headers.')
937 parser_headers.add_argument(
938 '--include_uapi',
939 required=True,
940 nargs='*',
941 help='The list of include/uapi header files.')
942
943 args = parser.parse_args()
944
945 if args.verbose:
946 print('mode [%s]' % args.mode)
947 print('header_arch [%s]' % args.header_arch)
948 print('gen_dir [%s]' % args.gen_dir)
949 print('arch_asm_kbuild [%s]' % args.arch_asm_kbuild)
950 print('asm_generic_kbuild [%s]' % args.asm_generic_kbuild)
951
952 # Extract the module_dir from args.arch_asm_kbuild and rel_arch_asm_kbuild.
953
954 rel_arch_asm_kbuild = os.path.join(
955 'arch', args.header_arch, 'include/uapi/asm/Kbuild')
956
957 suffix = os.sep + rel_arch_asm_kbuild
958
959 if not args.arch_asm_kbuild.endswith(suffix):
960 print('error: expected %s to end with %s' % (args.arch_asm_kbuild, suffix))
961 return 1
962
963 module_dir = args.arch_asm_kbuild[:-len(suffix)]
964
965 rel_asm_generic_kbuild = os.path.join('include/uapi/asm-generic', os.path.basename(args.asm_generic_kbuild))
966
967
968 if args.verbose:
969 print('module_dir [%s]' % module_dir)
970
Justin DeMartino32c10882019-11-05 15:59:43 -0800971
972 if args.mode == 'blueprints':
973 return gen_blueprints(
974 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800975 args.asm_generic_kbuild, module_dir, rel_arch_asm_kbuild, rel_asm_generic_kbuild, args.arch_include_uapi, args.techpack_include_uapi)
Justin DeMartino32c10882019-11-05 15:59:43 -0800976
977 if args.mode == 'headers':
978 if args.verbose:
979 print('old_gen_headers_bp [%s]' % args.old_gen_headers_bp)
980 print('new_gen_headers_bp [%s]' % args.new_gen_headers_bp)
981 print('version_makefile [%s]' % args.version_makefile)
982 print('arch_syscall_tool [%s]' % args.arch_syscall_tool)
983 print('arch_syscall_tbl [%s]' % args.arch_syscall_tbl)
984 print('headers_install [%s]' % args.headers_install)
985
986 return gen_headers(
987 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
988 args.asm_generic_kbuild, module_dir, args.old_gen_headers_bp, args.new_gen_headers_bp,
989 args.version_makefile, args.arch_syscall_tool, args.arch_syscall_tbl,
Rishabh Bhatnagar8878f182020-02-12 13:50:44 -0800990 args.headers_install, args.include_uapi, args.arch_include_uapi, args.techpack_include_uapi)
Justin DeMartino32c10882019-11-05 15:59:43 -0800991
992 print('error: unknown mode: %s' % args.mode)
993 return 1
994
995
996if __name__ == '__main__':
997 sys.exit(main())