blob: d36ca87d8cb43b29c954ddf1c4c3f59edce33a77 [file] [log] [blame]
Prateek Sood13e5f682019-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 # Mandatory headers need to be generated if they are not already generated.
207 comb_list = generic_list + generated_list + arch_include_uapi_list
208 mandatory_list = [x for x in mandatory_pre_list if x not in comb_list]
209 if verbose:
210 print("generic")
211 for x in generic_list:
212 print(x)
213 print("generated")
214 for x in generated_list:
215 print(x)
216 print("mandatory")
217 for x in mandatory_list:
218 print(x)
219 print("arch_include_uapi_list")
220 for x in arch_include_uapi_list:
221 print(x)
222
223 return (generated_list, generic_list, mandatory_list)
224
225
226def gen_arch_headers(
227 verbose, gen_dir, arch_asm_kbuild, asm_generic_kbuild, arch_syscall_tool, arch_syscall_tbl, arch_include_uapi):
228 """Process arch-specific and asm-generic uapi/asm/Kbuild to generate headers.
229
230 The function consists of a call to scan_arch_kbuild followed by three loops.
231 The first loop generates headers found and placed in the generated_list by
232 scan_arch_kbuild. The second loop generates headers found and placed in the
233 generic_list by the scan_arch_kbuild. The third loop generates headers found
234 in mandatory_list by scan_arch_kbuild.
235
236 The function does some parsing of file names and tool invocations. If that
237 parsing fails for some reason (e.g., we don't know how to generate the
238 header) or a tool invocation fails, then this function will count that as
239 an error but keep processing. In the end, the function returns the number of
240 errors encountered.
241
242 Args:
243 verbose: Set True to print progress messages.
244 gen_dir: Where to place the generated files.
245 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
246 asm_generic_kbuild: The Kbuild file containing lists of mandatory headers.
247 arch_syscall_tool: The arch script that generates syscall headers, or None.
248 arch_syscall_tbl: The arch script that defines syscall vectors, or None.
249 arch_include_uapi: Headers in arch/<arch>/include/uapi directory.
250 Return:
251 The number of parsing errors encountered.
252 """
253
254 error_count = 0
255
256 # First generate the lists
257
258 (generated_list, generic_list, mandatory_list) = scan_arch_kbuild(verbose, arch_asm_kbuild, asm_generic_kbuild ,arch_include_uapi)
259
260 # Now we're at the first loop, which is able to generate syscall headers
261 # found in the first loop, and placed in generated_list. It's okay for this
262 # list to be empty. In that case, of course, the loop does nothing.
263
264 abi_re = re.compile(r'unistd-(\S+)\.h')
265
266 for generated in generated_list:
267 gen_h = os.path.join(gen_dir, 'asm', generated)
268 match = abi_re.match(generated)
269
270 if match:
271 abi = match.group(1)
272
273 cmd = [
274 '/bin/bash',
275 arch_syscall_tool,
276 arch_syscall_tbl,
277 gen_h,
278 abi,
279 '',
280 '__NR_SYSCALL_BASE',
281 ]
282
283 if verbose:
284 print('gen_arch_headers: cmd is %s' % cmd)
285
286 result = subprocess.call(cmd)
287
288 if result != 0:
289 print('error: gen_arch_headers: cmd %s failed %d' % (cmd, result))
290 error_count += 1
291 else:
292 print('error: gen_arch_headers: syscall header has bad filename: %s' % generated)
293 error_count += 1
294
295 # Now we're at the second loop, which generates wrappers from arch-specific
296 # headers listed in generic_list to the corresponding asm-generic header.
297
298 for generic in generic_list:
299 wrap_h = os.path.join(gen_dir, 'asm', generic)
300 with open(wrap_h, 'w') as f:
301 f.write('#include <asm-generic/%s>\n' % generic)
302
303 # Now we're at the third loop, which generates wrappers from asm
304 # headers listed in mandatory_list to the corresponding asm-generic header.
305
306 for mandatory in mandatory_list:
307 wrap_h = os.path.join(gen_dir, 'asm', mandatory)
308 with open(wrap_h, 'w') as f:
309 f.write('#include <asm-generic/%s>\n' % mandatory)
310 return error_count
311
312
313def run_headers_install(verbose, gen_dir, headers_install, prefix, h):
314 """Process a header through the headers_install script.
315
316 The headers_install script does some processing of a header so that it is
317 appropriate for inclusion in a userland program. This function invokes that
318 script for one header file.
319
320 The input file is a header file found in the directory named by prefix. This
321 function stips the prefix from the header to generate the name of the
322 processed header.
323
324 Args:
325 verbose: Set True to print progress messages.
326 gen_dir: Where to place the generated files.
327 headers_install: The script that munges the header.
328 prefix: The prefix to strip from h to generate the output filename.
329 h: The input header to process.
330 Return:
331 If parsing or the tool fails, False. Otherwise, True
332 """
333
334 if not h.startswith(prefix):
335 print('error: expected prefix [%s] on header [%s]' % (prefix, h))
336 return False
337
338 out_h = os.path.join(gen_dir, h[len(prefix):])
339 (out_h_dirname, out_h_basename) = os.path.split(out_h)
340 h_dirname = os.path.dirname(h)
341
342 cmd = [headers_install, out_h_dirname, h_dirname, out_h_basename]
343
344 if verbose:
345 print('run_headers_install: cmd is %s' % cmd)
346
347 result = subprocess.call(cmd)
348
349 if result != 0:
350 print('error: run_headers_install: cmd %s failed %d' % (cmd, result))
351 return False
352
353 return True
354
355
356def glob_headers(prefix, rel_glob, excludes):
357 """Recursively scan the a directory for headers.
358
359 This function recursively scans the directory identified by prefix for
360 headers. We don't yet have a new enough version of python3 to use the
361 better glob function, so right now we assume the glob is '**/*.h'.
362
363 The function filters out any files that match the items in excludes.
364
365 Args:
366 prefix: The directory to recursively scan for headers.
367 rel_glob: The shell-style glob that identifies the header pattern.
368 excludes: A list of headers to exclude from the glob.
369 Return:
370 A list of headers discovered with excludes excluded.
371 """
372
373 # If we had python 3.5+, we could use the fancy new glob.glob.
374 # full_glob = os.path.join(prefix, rel_glob)
375 # full_srcs = glob.glob(full_glob, recursive=True)
376
377 full_dirs = [prefix]
378 full_srcs = []
379
380 while full_dirs:
381 full_dir = full_dirs.pop(0)
382 items = sorted(os.listdir(full_dir))
383
384 for item in items:
385 full_item = os.path.join(full_dir, item)
386
387 if os.path.isdir(full_item):
388 full_dirs.append(full_item)
389 continue
390
391 if full_item in excludes:
392 continue
393
394 if full_item.endswith('.h'):
395 full_srcs.append(full_item)
396
397 return full_srcs
398
399
400def find_out(verbose, module_dir, prefix, rel_glob, excludes, outs):
401 """Build a list of outputs for the genrule that creates kernel headers.
402
403 This function scans for headers in the source tree and produces a list of
404 output (generated) headers.
405
406 Args:
407 verbose: Set True to print progress messages.
408 module_dir: The root directory of the kernel source.
409 prefix: The prefix with in the kernel source tree to search for headers.
410 rel_glob: The pattern to use when matching headers under prefix.
411 excludes: A list of files to exclude from the glob.
412 outs: The list to populdate with the headers that will be generated.
413 Return:
414 The number of errors encountered.
415 """
416
417 # Turn prefix, which is relative to the soong module, to a full prefix that
418 # is relative to the Android source tree.
419
420 full_prefix = os.path.join(module_dir, prefix)
421
422 # Convert the list of excludes, which are relative to the soong module, to a
423 # set of excludes (for easy hashing), relative to the Android source tree.
424
425 full_excludes = set()
426
427 if excludes:
428 for exclude in excludes:
429 full_exclude = os.path.join(full_prefix, exclude)
430 full_excludes.add(full_exclude)
431
432 # Glob those headers.
433
434 full_srcs = glob_headers(full_prefix, rel_glob, full_excludes)
435
436 # Now convert the file names, which are relative to the Android source tree,
437 # to be relative to the gen dir. This means stripping off the module prefix
438 # and the directory within this module.
439
440 module_dir_sep = module_dir + os.sep
441 prefix_sep = prefix + os.sep
442
443 if verbose:
444 print('find_out: module_dir_sep [%s]' % module_dir_sep)
445 print('find_out: prefix_sep [%s]' % prefix_sep)
446
447 error_count = 0
448
449 for full_src in full_srcs:
450 if verbose:
451 print('find_out: full_src [%s]' % full_src)
452
453 if not full_src.startswith(module_dir_sep):
454 print('error: expected %s to start with %s' % (full_src, module_dir_sep))
455 error_count += 1
456 continue
457
458 local_src = full_src[len(module_dir_sep):]
459
460 if verbose:
461 print('find_out: local_src [%s]' % local_src)
462
463 if not local_src.startswith(prefix_sep):
464 print('error: expected %s to start with %s' % (local_src, prefix_sep))
465 error_count += 1
466 continue
467
468 # After stripping the module directory and the prefix, we're left with the
469 # name of a header that we'll generate, relative to the base of of a the
470 # the include path.
471
472 local_out = local_src[len(prefix_sep):]
473
474 if verbose:
475 print('find_out: local_out [%s]' % local_out)
476
477 outs.append(local_out)
478
479 return error_count
480
Naitik Bharadiya7347e052020-02-27 16:39:22 +0530481def scan_no_export_headers(verbose, module_dir, prefix):
482 """Scan include/uapi kbuild for no-export-headers
483
484 This function processes the Kbuild file to scan for no-export files that
485 should not export to usr/include/uapi which is identified by adding
486 to the no-export-headers make variable.
487
488 Args:
489 verbose: Set True to print progress messages.
490 module_dir: The root directory of the kernel source.
491 prefix: The prefix with in the kernel source tree to search for headers.
492 Return:
493 lists of no-export-headers.
494 """
495
496 no_export_headers_re = re.compile(r'no-export-headers\s*\+=\s*(\S+)')
497 header_re = re.compile(r'include/uapi/')
498 full_dirs_ = os.path.join(module_dir, prefix)
499 full_dirs = [full_dirs_]
500
501 if verbose:
502 print('scan_no_export_headers: processing [%s]' % full_dirs)
503
504 full_srcs = []
505 no_export_headers_lists = []
506
507 while full_dirs:
508 full_dir = full_dirs.pop(0)
509 items = sorted(os.listdir(full_dir))
510
511 for item in items:
512 full_item = os.path.join(full_dir, item)
513
514 if os.path.isdir(full_item):
515 full_dirs.append(full_item)
516 continue
517
518 if (full_item.find('Kbuild') != -1):
519 full_srcs.append(full_item)
520
521 for full_src in full_srcs:
522 with open(full_src, 'r') as f:
523 while True:
524 line = f.readline()
525
526 if not line:
527 break
528
529 line = line.rstrip()
530
531 match = no_export_headers_re.match(line)
532
533 if match:
534 if verbose:
535 print('scan_no_export_headers: matched [%s]' % line)
536
537 if (match.group(1) == "kvm.h" or
538 match.group(1) == "kvm_para.h" or
539 match.group(1) == "a.out.h"):
540 continue
541
542 (full_src_dir_name, full_src_base_name) = full_src.split('include/uapi/')
543 no_export_header_file_name = os.path.join(os.path.dirname(full_src_base_name),match.group(1))
544
545 if verbose:
546 print('scan_no_export_headers: no_export_header_file_name = ',no_export_header_file_name)
547
548 no_export_headers_lists.append(no_export_header_file_name)
549 continue
550
551 if verbose:
552 for x in no_export_headers_lists:
553 print('scan_no_export_headers: no_export_headers_lists [%s]' % x)
554
555 return no_export_headers_lists
Prateek Sood13e5f682019-11-05 15:59:43 -0800556
557def gen_blueprints(
558 verbose, header_arch, gen_dir, arch_asm_kbuild, asm_generic_kbuild, module_dir,
559 rel_arch_asm_kbuild, rel_asm_generic_kbuild, arch_include_uapi, techpack_include_uapi):
560 """Generate a blueprints file containing modules that invoke this script.
561
562 This function generates a blueprints file that contains modules that
563 invoke this script to generate kernel headers. We generate the blueprints
564 file as needed, but we don't actually use the generated file. The blueprints
565 file that we generate ends up in the out directory, and we can use it to
566 detect if the checked-in version of the file (in the source directory) is out
567 of date. This pattern occurs in the Android source tree in several places.
568
569 Args:
570 verbose: Set True to print progress messages.
571 header_arch: The arch for which to generate headers.
572 gen_dir: Where to place the generated files.
573 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
574 asm_generic_kbuild: The Kbuild file containing lists of mandatory headers.
575 module_dir: The root directory of the kernel source.
576 rel_arch_asm_kbuild: arch_asm_kbuild relative to module_dir.
577 Return:
578 The number of errors encountered.
579 """
580 error_count = 0
581
582 # The old and new blueprints files. We generate the new one, but we need to
583 # refer to the old one in the modules that we generate.
584 old_gen_headers_bp = 'gen_headers_%s.bp' % header_arch
585 new_gen_headers_bp = os.path.join(gen_dir, old_gen_headers_bp)
586
587 # Tools and tool files.
588 headers_install_sh = 'headers_install.sh'
589 kernel_headers_py = 'kernel_headers.py'
590 arm_syscall_tool = 'arch/arm/tools/syscallhdr.sh'
591
592 # Sources
593 makefile = 'Makefile'
594 arm_syscall_tbl = 'arch/arm/tools/syscall.tbl'
595 rel_glob = '**/*.h'
596 generic_prefix = 'include/uapi'
597 arch_prefix = os.path.join('arch', header_arch, generic_prefix)
598 generic_src = os.path.join(generic_prefix, rel_glob)
599 arch_src = os.path.join(arch_prefix, rel_glob)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800600 techpack_src = os.path.join('techpack/*',generic_prefix, '*',rel_glob)
Prateek Sood13e5f682019-11-05 15:59:43 -0800601
602 # Excluded sources, architecture specific.
603 exclude_srcs = []
604
605 if header_arch == "arm":
606 exclude_srcs = ['linux/a.out.h']
607
608 if header_arch == "arm64":
609 exclude_srcs = ['linux/a.out.h', 'linux/kvm_para.h']
610
Naitik Bharadiya7347e052020-02-27 16:39:22 +0530611 no_export_headers_lists = scan_no_export_headers(verbose, module_dir, generic_prefix)
612
613 for no_export_headers_list in no_export_headers_lists:
614 exclude_srcs.append(no_export_headers_list)
615
616 if verbose:
617 for x in exclude_srcs:
618 print('gen_blueprints : exclude_srcs [%s]' % x)
619
Prateek Sood13e5f682019-11-05 15:59:43 -0800620 # Scan the arch_asm_kbuild file for files that need to be generated and those
621 # that are generic (i.e., need to be wrapped).
622
623 (generated_list, generic_list, mandatory_list) = scan_arch_kbuild(verbose,
624 arch_asm_kbuild, asm_generic_kbuild, arch_include_uapi)
625
626 generic_out = []
627 error_count += find_out(
628 verbose, module_dir, generic_prefix, rel_glob, exclude_srcs, generic_out)
629
630 arch_out = []
631 error_count += find_out(
632 verbose, module_dir, arch_prefix, rel_glob, None, arch_out)
633
634 techpack_out = [x.split('include/uapi/')[1] for x in techpack_include_uapi]
635
636 if error_count != 0:
637 return error_count
638
639 # Generate the blueprints file.
640
641 if verbose:
642 print('gen_blueprints: generating %s' % new_gen_headers_bp)
643
644 with open(new_gen_headers_bp, 'w') as f:
645 f.write('// ***** DO NOT EDIT *****\n')
646 f.write('// This file is generated by %s\n' % kernel_headers_py)
647 f.write('\n')
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800648 f.write('gen_headers_srcs_%s = [\n' % header_arch)
649 f.write(' "%s",\n' % rel_arch_asm_kbuild)
650 f.write(' "%s",\n' % rel_asm_generic_kbuild)
651 f.write(' "%s",\n' % makefile)
652
653 if header_arch == "arm":
654 f.write(' "%s",\n' % arm_syscall_tbl)
655
656 f.write(' "%s",\n' % generic_src)
657 f.write(' "%s",\n' % arch_src)
658 f.write(']\n')
659 f.write('\n')
660
661 if exclude_srcs:
662 f.write('gen_headers_exclude_srcs_%s = [\n' % header_arch)
663 for h in exclude_srcs:
664 f.write(' "%s",\n' % os.path.join(generic_prefix, h))
665 f.write(']\n')
666 f.write('\n')
667
668 f.write('gen_headers_out_%s = [\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800669
670 if generated_list:
671 f.write('\n')
672 f.write(' // Matching generated-y:\n')
673 f.write('\n')
674 for h in generated_list:
675 f.write(' "asm/%s",\n' % h)
676
677 if generic_list:
678 f.write('\n')
679 f.write(' // Matching generic-y:\n')
680 f.write('\n')
681 for h in generic_list:
682 f.write(' "asm/%s",\n' % h)
683
684 if mandatory_list:
685 f.write('\n')
686 f.write(' // Matching mandatory-y:\n')
687 f.write('\n')
688 for h in mandatory_list:
689 f.write(' "asm/%s",\n' % h)
690
691 if generic_out:
692 f.write('\n')
693 f.write(' // From %s\n' % generic_src)
694 f.write('\n')
695 for h in generic_out:
696 f.write(' "%s",\n' % h)
697
698 if arch_out:
699 f.write('\n')
700 f.write(' // From %s\n' % arch_src)
701 f.write('\n')
702 for h in arch_out:
703 f.write(' "%s",\n' % h)
704
705 if techpack_out:
706 f.write('\n')
707 f.write(' // From %s\n' % techpack_src)
708 f.write('\n')
709 for h in techpack_out:
710 f.write(' "%s",\n' % h)
711
712 f.write(']\n')
713 f.write('\n')
714
715 gen_blueprints_module_name = 'qti_generate_gen_headers_%s' % header_arch
716
717 f.write('genrule {\n')
718 f.write(' // This module generates the gen_headers_<arch>.bp file\n')
719 f.write(' // (i.e., a new version of this file) so that it can be\n')
720 f.write(' // checked later to ensure that it matches the checked-\n')
721 f.write(' // in version (this file).\n')
722 f.write(' name: "%s",\n' % gen_blueprints_module_name)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800723 f.write(' srcs: gen_headers_srcs_%s,\n' % header_arch)
724 if exclude_srcs:
725 f.write(' exclude_srcs: gen_headers_exclude_srcs_%s,\n' % header_arch)
726
Prateek Sood13e5f682019-11-05 15:59:43 -0800727 f.write(' tool_files: ["kernel_headers.py"],\n')
728 f.write(' cmd: "python3 $(location kernel_headers.py) " +\n')
729 f.write(' kernel_headers_verbose +\n')
730 f.write(' "--header_arch %s " +\n' % header_arch)
731 f.write(' "--gen_dir $(genDir) " +\n')
732 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
733 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
734 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800735 f.write(' "blueprints " +\n')
736 f.write(' "# $(in)",\n')
Prateek Sood13e5f682019-11-05 15:59:43 -0800737 f.write(' out: ["gen_headers_%s.bp"],\n' % header_arch)
738 f.write('}\n')
739 f.write('\n')
740
741 f.write('genrule {\n')
742 f.write(' name: "qti_generate_kernel_headers_%s",\n' % header_arch)
743 f.write(' tools: ["%s"],\n' % headers_install_sh)
744 f.write(' tool_files: [\n')
745 f.write(' "%s",\n' % kernel_headers_py)
746
747 if header_arch == "arm":
748 f.write(' "%s",\n' % arm_syscall_tool)
749
750 f.write(' ],\n')
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800751 f.write(' srcs: gen_headers_srcs_%s +[\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800752 f.write(' "%s",\n' % old_gen_headers_bp)
753 f.write(' ":%s",\n' % gen_blueprints_module_name)
Prateek Sood13e5f682019-11-05 15:59:43 -0800754 f.write(' ],\n')
755
756 if exclude_srcs:
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800757 f.write(' exclude_srcs: gen_headers_exclude_srcs_%s,\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800758
759 f.write(' cmd: "python3 $(location %s) " +\n' % kernel_headers_py)
760 f.write(' kernel_headers_verbose +\n')
761 f.write(' "--header_arch %s " +\n' % header_arch)
762 f.write(' "--gen_dir $(genDir) " +\n')
763 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
764 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
765 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
766 f.write(' "headers " +\n')
767 f.write(' "--old_gen_headers_bp $(location %s) " +\n' % old_gen_headers_bp)
768 f.write(' "--new_gen_headers_bp $(location :%s) " +\n' % gen_blueprints_module_name)
769 f.write(' "--version_makefile $(location %s) " +\n' % makefile)
770
771 if header_arch == "arm":
772 f.write(' "--arch_syscall_tool $(location %s) " +\n' % arm_syscall_tool)
773 f.write(' "--arch_syscall_tbl $(location %s) " +\n' % arm_syscall_tbl)
774
775 f.write(' "--headers_install $(location %s) " +\n' % headers_install_sh)
776 f.write(' "--include_uapi $(locations %s)",\n' % generic_src)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800777 f.write(' out: ["linux/version.h"] + gen_headers_out_%s,\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800778 f.write('}\n')
779
780 return 0
781
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800782def parse_bp_for_headers(file_name, headers):
783 parsing_headers = False
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800784 pattern = re.compile("gen_headers_out_[a-zA-Z0-9]+\s*=\s*\[\s*")
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800785 with open(file_name, 'r') as f:
786 for line in f:
787 line = line.strip()
788 if pattern.match(line):
789 parsing_headers = True
790 continue
791
792 if line.find("]") != -1 and parsing_headers:
793 break
794
795 if not parsing_headers:
796 continue
797
798 if line.find("//") == 0:
799 continue
800
801 headers.add(line[1:-2])
802
803def headers_diff(old_file, new_file):
804 old_headers = set()
805 new_headers = set()
806 diff_detected = False
807
808 parse_bp_for_headers(old_file, old_headers)
809 parse_bp_for_headers(new_file, new_headers)
810
811 diff = old_headers - new_headers
812 if len(diff):
813 diff_detected = True
814 print("Headers to remove:")
815 for x in diff:
816 print("\t{}".format(x))
817
818 diff = new_headers - old_headers
819 if len(diff):
820 diff_detected = True
821 print("Headers to add:")
822 for x in diff:
823 print("\t{}".format(x))
824
825 return diff_detected
Prateek Sood13e5f682019-11-05 15:59:43 -0800826
827def gen_headers(
828 verbose, header_arch, gen_dir, arch_asm_kbuild, asm_generic_kbuild, module_dir,
829 old_gen_headers_bp, new_gen_headers_bp, version_makefile,
830 arch_syscall_tool, arch_syscall_tbl, headers_install, include_uapi,
831 arch_include_uapi, techpack_include_uapi):
832 """Generate the kernel headers.
833
834 This script generates the version.h file, the arch-specific headers including
835 syscall-related generated files and wrappers around generic files, and uses
836 the headers_install tool to process other generic uapi and arch-specific uapi
837 files.
838
839 Args:
840 verbose: Set True to print progress messages.
841 header_arch: The arch for which to generate headers.
842 gen_dir: Where to place the generated files.
843 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
844 asm_generic_kbuild: The Kbuild file containing mandatory headers.
845 module_dir: The root directory of the kernel source.
846 old_gen_headers_bp: The old gen_headers_<arch>.bp file to check.
847 new_gen_headers_bp: The new gen_headers_<arch>.bp file to check.
848 version_makefile: The kernel Makefile that contains version info.
849 arch_syscall_tool: The arch script that generates syscall headers.
850 arch_syscall_tbl: The arch script that defines syscall vectors.
851 headers_install: The headers_install tool to process input headers.
852 include_uapi: The list of include/uapi header files.
853 arch_include_uapi: The list of arch/<arch>/include/uapi header files.
854 Return:
855 The number of errors encountered.
856 """
857
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800858 if headers_diff(old_gen_headers_bp, new_gen_headers_bp):
Prateek Sood13e5f682019-11-05 15:59:43 -0800859 print('error: gen_headers blueprints file is out of date, suggested fix:')
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800860 print('#######Please add or remove the above mentioned headers from %s' % (old_gen_headers_bp))
Prateek Sood13e5f682019-11-05 15:59:43 -0800861 print('then re-run the build')
862 return 1
863
864 error_count = 0
865
866 if not gen_version_h(verbose, gen_dir, version_makefile):
867 error_count += 1
868
869 error_count += gen_arch_headers(
870 verbose, gen_dir, arch_asm_kbuild, asm_generic_kbuild, arch_syscall_tool, arch_syscall_tbl ,arch_include_uapi)
871
872 uapi_include_prefix = os.path.join(module_dir, 'include', 'uapi') + os.sep
873
874 arch_uapi_include_prefix = os.path.join(
875 module_dir, 'arch', header_arch, 'include', 'uapi') + os.sep
876
877 for h in include_uapi:
878 if not run_headers_install(
879 verbose, gen_dir, headers_install,
880 uapi_include_prefix, h):
881 error_count += 1
882
883 for h in arch_include_uapi:
884 if not run_headers_install(
885 verbose, gen_dir, headers_install,
886 arch_uapi_include_prefix, h):
887 error_count += 1
888
889 for h in techpack_include_uapi:
890 techpack_uapi_include_prefix = os.path.join(h.split('/include/uapi')[0], 'include', 'uapi') + os.sep
891 if not run_headers_install(
892 verbose, gen_dir, headers_install,
893 techpack_uapi_include_prefix, h):
894 error_count += 1
895
896 return error_count
897
898def extract_techpack_uapi_headers(verbose, module_dir):
899
900 """EXtract list of uapi headers from techpack/* directories. We need to export
901 these headers to userspace.
902
903 Args:
904 verbose: Verbose option is provided to script
905 module_dir: Base directory
906 Returs:
907 List of uapi headers
908 """
909
910 techpack_subdir = []
911 techpack_dir = os.path.join(module_dir,'techpack')
912 techpack_uapi = []
913 techpack_uapi_sub = []
914
915 #get list of techpack directories under techpack/
916 if os.path.isdir(techpack_dir):
917 items = sorted(os.listdir(techpack_dir))
918 for x in items:
919 p = os.path.join(techpack_dir, x)
920 if os.path.isdir(p):
921 techpack_subdir.append(p)
922
923 #Print list of subdirs obtained
924 if (verbose):
925 for x in techpack_subdir:
926 print(x)
927
928 #For every subdirectory get list of .h files under include/uapi and append to techpack_uapi list
929 for x in techpack_subdir:
930 techpack_uapi_path = os.path.join(x, 'include/uapi')
931 if (os.path.isdir(techpack_uapi_path)):
932 techpack_uapi_sub = []
933 find_out(verbose, x, 'include/uapi', '**/*.h', None, techpack_uapi_sub)
934 tmp = [os.path.join(techpack_uapi_path, y) for y in techpack_uapi_sub]
935 techpack_uapi = techpack_uapi + tmp
936
937 if (verbose):
938 for x in techpack_uapi:
939 print(x)
940
941 return techpack_uapi
942
943def main():
944 """Parse command line arguments and perform top level control."""
945
946 parser = argparse.ArgumentParser(
947 description=__doc__,
948 formatter_class=argparse.RawDescriptionHelpFormatter)
949
950 # Arguments that apply to every invocation of this script.
951
952 parser.add_argument(
953 '--verbose',
954 action='store_true',
955 help='Print output that describes the workings of this script.')
956 parser.add_argument(
957 '--header_arch',
958 required=True,
959 help='The arch for which to generate headers.')
960 parser.add_argument(
961 '--gen_dir',
962 required=True,
963 help='Where to place the generated files.')
964 parser.add_argument(
965 '--arch_asm_kbuild',
966 required=True,
967 help='The Kbuild file containing lists of headers to generate.')
968 parser.add_argument(
969 '--asm_generic_kbuild',
970 required=True,
971 help='The Kbuild file containing lists of mandatory headers.')
972 parser.add_argument(
973 '--arch_include_uapi',
974 required=True,
975 nargs='*',
976 help='The list of arch/<arch>/include/uapi header files.')
977
978 # The modes.
979
980 subparsers = parser.add_subparsers(
981 dest='mode',
982 help='Select mode')
983 parser_blueprints = subparsers.add_parser(
984 'blueprints',
985 help='Generate the gen_headers_<arch>.bp file.')
986 parser_headers = subparsers.add_parser(
987 'headers',
988 help='Check blueprints, then generate kernel headers.')
989
990 # Arguments that apply to headers mode.
991
992 parser_headers.add_argument(
993 '--old_gen_headers_bp',
994 required=True,
995 help='The old gen_headers_<arch>.bp file to check.')
996 parser_headers.add_argument(
997 '--new_gen_headers_bp',
998 required=True,
999 help='The new gen_headers_<arch>.bp file to check.')
1000 parser_headers.add_argument(
1001 '--version_makefile',
1002 required=True,
1003 help='The kernel Makefile that contains version info.')
1004 parser_headers.add_argument(
1005 '--arch_syscall_tool',
1006 help='The arch script that generates syscall headers, if applicable.')
1007 parser_headers.add_argument(
1008 '--arch_syscall_tbl',
1009 help='The arch script that defines syscall vectors, if applicable.')
1010 parser_headers.add_argument(
1011 '--headers_install',
1012 required=True,
1013 help='The headers_install tool to process input headers.')
1014 parser_headers.add_argument(
1015 '--include_uapi',
1016 required=True,
1017 nargs='*',
1018 help='The list of include/uapi header files.')
1019
1020 args = parser.parse_args()
1021
1022 if args.verbose:
1023 print('mode [%s]' % args.mode)
1024 print('header_arch [%s]' % args.header_arch)
1025 print('gen_dir [%s]' % args.gen_dir)
1026 print('arch_asm_kbuild [%s]' % args.arch_asm_kbuild)
1027 print('asm_generic_kbuild [%s]' % args.asm_generic_kbuild)
1028
1029 # Extract the module_dir from args.arch_asm_kbuild and rel_arch_asm_kbuild.
1030
1031 rel_arch_asm_kbuild = os.path.join(
1032 'arch', args.header_arch, 'include/uapi/asm/Kbuild')
1033
1034 suffix = os.sep + rel_arch_asm_kbuild
1035
1036 if not args.arch_asm_kbuild.endswith(suffix):
1037 print('error: expected %s to end with %s' % (args.arch_asm_kbuild, suffix))
1038 return 1
1039
1040 module_dir = args.arch_asm_kbuild[:-len(suffix)]
1041
1042 rel_asm_generic_kbuild = os.path.join('include/uapi/asm-generic', os.path.basename(args.asm_generic_kbuild))
1043
1044
1045 if args.verbose:
1046 print('module_dir [%s]' % module_dir)
1047
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -08001048 techpack_include_uapi = []
1049
Prateek Sood13e5f682019-11-05 15:59:43 -08001050
1051 if args.mode == 'blueprints':
1052 return gen_blueprints(
1053 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -08001054 args.asm_generic_kbuild, module_dir, rel_arch_asm_kbuild, rel_asm_generic_kbuild, args.arch_include_uapi, techpack_include_uapi)
Prateek Sood13e5f682019-11-05 15:59:43 -08001055
1056 if args.mode == 'headers':
1057 if args.verbose:
1058 print('old_gen_headers_bp [%s]' % args.old_gen_headers_bp)
1059 print('new_gen_headers_bp [%s]' % args.new_gen_headers_bp)
1060 print('version_makefile [%s]' % args.version_makefile)
1061 print('arch_syscall_tool [%s]' % args.arch_syscall_tool)
1062 print('arch_syscall_tbl [%s]' % args.arch_syscall_tbl)
1063 print('headers_install [%s]' % args.headers_install)
1064
1065 return gen_headers(
1066 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
1067 args.asm_generic_kbuild, module_dir, args.old_gen_headers_bp, args.new_gen_headers_bp,
1068 args.version_makefile, args.arch_syscall_tool, args.arch_syscall_tbl,
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -08001069 args.headers_install, args.include_uapi, args.arch_include_uapi, techpack_include_uapi)
Prateek Sood13e5f682019-11-05 15:59:43 -08001070
1071 print('error: unknown mode: %s' % args.mode)
1072 return 1
1073
1074
1075if __name__ == '__main__':
1076 sys.exit(main())