blob: 483f8de4f23732b669b6fe47a243149638e2857e [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
Bill Peckhama6248a12021-01-26 13:06:41 -0800313def run_headers_install(verbose, gen_dir, headers_install, unifdef, prefix, h):
Prateek Sood13e5f682019-11-05 15:59:43 -0800314 """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.
Bill Peckhama6248a12021-01-26 13:06:41 -0800328 unifdef: The unifdef tool used by headers_install.
Prateek Sood13e5f682019-11-05 15:59:43 -0800329 prefix: The prefix to strip from h to generate the output filename.
330 h: The input header to process.
331 Return:
332 If parsing or the tool fails, False. Otherwise, True
333 """
334
335 if not h.startswith(prefix):
336 print('error: expected prefix [%s] on header [%s]' % (prefix, h))
337 return False
338
339 out_h = os.path.join(gen_dir, h[len(prefix):])
340 (out_h_dirname, out_h_basename) = os.path.split(out_h)
341 h_dirname = os.path.dirname(h)
342
343 cmd = [headers_install, out_h_dirname, h_dirname, out_h_basename]
344
345 if verbose:
346 print('run_headers_install: cmd is %s' % cmd)
347
Bill Peckhama6248a12021-01-26 13:06:41 -0800348 env = os.environ.copy()
349 env["LOC_UNIFDEF"] = unifdef
Bharat Pawar8b41ca32021-05-05 22:43:20 +0530350 result = subprocess.call(['sh', headers_install, out_h_dirname, h_dirname, out_h_basename], env=env)
Prateek Sood13e5f682019-11-05 15:59:43 -0800351
352 if result != 0:
353 print('error: run_headers_install: cmd %s failed %d' % (cmd, result))
354 return False
355
356 return True
357
358
359def glob_headers(prefix, rel_glob, excludes):
360 """Recursively scan the a directory for headers.
361
362 This function recursively scans the directory identified by prefix for
363 headers. We don't yet have a new enough version of python3 to use the
364 better glob function, so right now we assume the glob is '**/*.h'.
365
366 The function filters out any files that match the items in excludes.
367
368 Args:
369 prefix: The directory to recursively scan for headers.
370 rel_glob: The shell-style glob that identifies the header pattern.
371 excludes: A list of headers to exclude from the glob.
372 Return:
373 A list of headers discovered with excludes excluded.
374 """
375
376 # If we had python 3.5+, we could use the fancy new glob.glob.
377 # full_glob = os.path.join(prefix, rel_glob)
378 # full_srcs = glob.glob(full_glob, recursive=True)
379
380 full_dirs = [prefix]
381 full_srcs = []
382
383 while full_dirs:
384 full_dir = full_dirs.pop(0)
385 items = sorted(os.listdir(full_dir))
386
387 for item in items:
388 full_item = os.path.join(full_dir, item)
389
390 if os.path.isdir(full_item):
391 full_dirs.append(full_item)
392 continue
393
394 if full_item in excludes:
395 continue
396
397 if full_item.endswith('.h'):
398 full_srcs.append(full_item)
399
400 return full_srcs
401
402
403def find_out(verbose, module_dir, prefix, rel_glob, excludes, outs):
404 """Build a list of outputs for the genrule that creates kernel headers.
405
406 This function scans for headers in the source tree and produces a list of
407 output (generated) headers.
408
409 Args:
410 verbose: Set True to print progress messages.
411 module_dir: The root directory of the kernel source.
412 prefix: The prefix with in the kernel source tree to search for headers.
413 rel_glob: The pattern to use when matching headers under prefix.
414 excludes: A list of files to exclude from the glob.
415 outs: The list to populdate with the headers that will be generated.
416 Return:
417 The number of errors encountered.
418 """
419
420 # Turn prefix, which is relative to the soong module, to a full prefix that
421 # is relative to the Android source tree.
422
423 full_prefix = os.path.join(module_dir, prefix)
424
425 # Convert the list of excludes, which are relative to the soong module, to a
426 # set of excludes (for easy hashing), relative to the Android source tree.
427
428 full_excludes = set()
429
430 if excludes:
431 for exclude in excludes:
432 full_exclude = os.path.join(full_prefix, exclude)
433 full_excludes.add(full_exclude)
434
435 # Glob those headers.
436
437 full_srcs = glob_headers(full_prefix, rel_glob, full_excludes)
438
439 # Now convert the file names, which are relative to the Android source tree,
440 # to be relative to the gen dir. This means stripping off the module prefix
441 # and the directory within this module.
442
443 module_dir_sep = module_dir + os.sep
444 prefix_sep = prefix + os.sep
445
446 if verbose:
447 print('find_out: module_dir_sep [%s]' % module_dir_sep)
448 print('find_out: prefix_sep [%s]' % prefix_sep)
449
450 error_count = 0
451
452 for full_src in full_srcs:
453 if verbose:
454 print('find_out: full_src [%s]' % full_src)
455
456 if not full_src.startswith(module_dir_sep):
457 print('error: expected %s to start with %s' % (full_src, module_dir_sep))
458 error_count += 1
459 continue
460
461 local_src = full_src[len(module_dir_sep):]
462
463 if verbose:
464 print('find_out: local_src [%s]' % local_src)
465
466 if not local_src.startswith(prefix_sep):
467 print('error: expected %s to start with %s' % (local_src, prefix_sep))
468 error_count += 1
469 continue
470
471 # After stripping the module directory and the prefix, we're left with the
472 # name of a header that we'll generate, relative to the base of of a the
473 # the include path.
474
475 local_out = local_src[len(prefix_sep):]
476
477 if verbose:
478 print('find_out: local_out [%s]' % local_out)
479
480 outs.append(local_out)
481
482 return error_count
483
Naitik Bharadiya7347e052020-02-27 16:39:22 +0530484def scan_no_export_headers(verbose, module_dir, prefix):
485 """Scan include/uapi kbuild for no-export-headers
486
487 This function processes the Kbuild file to scan for no-export files that
488 should not export to usr/include/uapi which is identified by adding
489 to the no-export-headers make variable.
490
491 Args:
492 verbose: Set True to print progress messages.
493 module_dir: The root directory of the kernel source.
494 prefix: The prefix with in the kernel source tree to search for headers.
495 Return:
496 lists of no-export-headers.
497 """
498
499 no_export_headers_re = re.compile(r'no-export-headers\s*\+=\s*(\S+)')
500 header_re = re.compile(r'include/uapi/')
501 full_dirs_ = os.path.join(module_dir, prefix)
502 full_dirs = [full_dirs_]
503
504 if verbose:
505 print('scan_no_export_headers: processing [%s]' % full_dirs)
506
507 full_srcs = []
508 no_export_headers_lists = []
509
510 while full_dirs:
511 full_dir = full_dirs.pop(0)
512 items = sorted(os.listdir(full_dir))
513
514 for item in items:
515 full_item = os.path.join(full_dir, item)
516
517 if os.path.isdir(full_item):
518 full_dirs.append(full_item)
519 continue
520
521 if (full_item.find('Kbuild') != -1):
522 full_srcs.append(full_item)
523
524 for full_src in full_srcs:
525 with open(full_src, 'r') as f:
526 while True:
527 line = f.readline()
528
529 if not line:
530 break
531
532 line = line.rstrip()
533
534 match = no_export_headers_re.match(line)
535
536 if match:
537 if verbose:
538 print('scan_no_export_headers: matched [%s]' % line)
539
540 if (match.group(1) == "kvm.h" or
541 match.group(1) == "kvm_para.h" or
542 match.group(1) == "a.out.h"):
543 continue
544
545 (full_src_dir_name, full_src_base_name) = full_src.split('include/uapi/')
546 no_export_header_file_name = os.path.join(os.path.dirname(full_src_base_name),match.group(1))
547
548 if verbose:
549 print('scan_no_export_headers: no_export_header_file_name = ',no_export_header_file_name)
550
551 no_export_headers_lists.append(no_export_header_file_name)
552 continue
553
554 if verbose:
555 for x in no_export_headers_lists:
556 print('scan_no_export_headers: no_export_headers_lists [%s]' % x)
557
558 return no_export_headers_lists
Prateek Sood13e5f682019-11-05 15:59:43 -0800559
560def gen_blueprints(
561 verbose, header_arch, gen_dir, arch_asm_kbuild, asm_generic_kbuild, module_dir,
562 rel_arch_asm_kbuild, rel_asm_generic_kbuild, arch_include_uapi, techpack_include_uapi):
563 """Generate a blueprints file containing modules that invoke this script.
564
565 This function generates a blueprints file that contains modules that
566 invoke this script to generate kernel headers. We generate the blueprints
567 file as needed, but we don't actually use the generated file. The blueprints
568 file that we generate ends up in the out directory, and we can use it to
569 detect if the checked-in version of the file (in the source directory) is out
570 of date. This pattern occurs in the Android source tree in several places.
571
572 Args:
573 verbose: Set True to print progress messages.
574 header_arch: The arch for which to generate headers.
575 gen_dir: Where to place the generated files.
576 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
577 asm_generic_kbuild: The Kbuild file containing lists of mandatory headers.
578 module_dir: The root directory of the kernel source.
579 rel_arch_asm_kbuild: arch_asm_kbuild relative to module_dir.
580 Return:
581 The number of errors encountered.
582 """
583 error_count = 0
584
585 # The old and new blueprints files. We generate the new one, but we need to
586 # refer to the old one in the modules that we generate.
587 old_gen_headers_bp = 'gen_headers_%s.bp' % header_arch
588 new_gen_headers_bp = os.path.join(gen_dir, old_gen_headers_bp)
589
590 # Tools and tool files.
591 headers_install_sh = 'headers_install.sh'
Bill Peckhama6248a12021-01-26 13:06:41 -0800592 unifdef = 'unifdef'
Prateek Sood13e5f682019-11-05 15:59:43 -0800593 kernel_headers_py = 'kernel_headers.py'
594 arm_syscall_tool = 'arch/arm/tools/syscallhdr.sh'
595
596 # Sources
597 makefile = 'Makefile'
598 arm_syscall_tbl = 'arch/arm/tools/syscall.tbl'
599 rel_glob = '**/*.h'
600 generic_prefix = 'include/uapi'
601 arch_prefix = os.path.join('arch', header_arch, generic_prefix)
602 generic_src = os.path.join(generic_prefix, rel_glob)
603 arch_src = os.path.join(arch_prefix, rel_glob)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800604 techpack_src = os.path.join('techpack/*',generic_prefix, '*',rel_glob)
Prateek Sood13e5f682019-11-05 15:59:43 -0800605
606 # Excluded sources, architecture specific.
607 exclude_srcs = []
608
609 if header_arch == "arm":
610 exclude_srcs = ['linux/a.out.h']
611
612 if header_arch == "arm64":
613 exclude_srcs = ['linux/a.out.h', 'linux/kvm_para.h']
614
Naitik Bharadiya7347e052020-02-27 16:39:22 +0530615 no_export_headers_lists = scan_no_export_headers(verbose, module_dir, generic_prefix)
616
617 for no_export_headers_list in no_export_headers_lists:
618 exclude_srcs.append(no_export_headers_list)
619
620 if verbose:
621 for x in exclude_srcs:
622 print('gen_blueprints : exclude_srcs [%s]' % x)
623
Prateek Sood13e5f682019-11-05 15:59:43 -0800624 # Scan the arch_asm_kbuild file for files that need to be generated and those
625 # that are generic (i.e., need to be wrapped).
626
627 (generated_list, generic_list, mandatory_list) = scan_arch_kbuild(verbose,
628 arch_asm_kbuild, asm_generic_kbuild, arch_include_uapi)
629
630 generic_out = []
631 error_count += find_out(
632 verbose, module_dir, generic_prefix, rel_glob, exclude_srcs, generic_out)
633
634 arch_out = []
635 error_count += find_out(
636 verbose, module_dir, arch_prefix, rel_glob, None, arch_out)
637
638 techpack_out = [x.split('include/uapi/')[1] for x in techpack_include_uapi]
639
640 if error_count != 0:
641 return error_count
642
643 # Generate the blueprints file.
644
645 if verbose:
646 print('gen_blueprints: generating %s' % new_gen_headers_bp)
647
648 with open(new_gen_headers_bp, 'w') as f:
649 f.write('// ***** DO NOT EDIT *****\n')
650 f.write('// This file is generated by %s\n' % kernel_headers_py)
651 f.write('\n')
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800652 f.write('gen_headers_srcs_%s = [\n' % header_arch)
653 f.write(' "%s",\n' % rel_arch_asm_kbuild)
654 f.write(' "%s",\n' % rel_asm_generic_kbuild)
655 f.write(' "%s",\n' % makefile)
656
657 if header_arch == "arm":
658 f.write(' "%s",\n' % arm_syscall_tbl)
659
660 f.write(' "%s",\n' % generic_src)
661 f.write(' "%s",\n' % arch_src)
662 f.write(']\n')
663 f.write('\n')
664
665 if exclude_srcs:
666 f.write('gen_headers_exclude_srcs_%s = [\n' % header_arch)
667 for h in exclude_srcs:
668 f.write(' "%s",\n' % os.path.join(generic_prefix, h))
669 f.write(']\n')
670 f.write('\n')
671
672 f.write('gen_headers_out_%s = [\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800673
674 if generated_list:
675 f.write('\n')
676 f.write(' // Matching generated-y:\n')
677 f.write('\n')
678 for h in generated_list:
679 f.write(' "asm/%s",\n' % h)
680
681 if generic_list:
682 f.write('\n')
683 f.write(' // Matching generic-y:\n')
684 f.write('\n')
685 for h in generic_list:
686 f.write(' "asm/%s",\n' % h)
687
688 if mandatory_list:
689 f.write('\n')
690 f.write(' // Matching mandatory-y:\n')
691 f.write('\n')
692 for h in mandatory_list:
693 f.write(' "asm/%s",\n' % h)
694
695 if generic_out:
696 f.write('\n')
697 f.write(' // From %s\n' % generic_src)
698 f.write('\n')
699 for h in generic_out:
700 f.write(' "%s",\n' % h)
701
702 if arch_out:
703 f.write('\n')
704 f.write(' // From %s\n' % arch_src)
705 f.write('\n')
706 for h in arch_out:
707 f.write(' "%s",\n' % h)
708
709 if techpack_out:
710 f.write('\n')
711 f.write(' // From %s\n' % techpack_src)
712 f.write('\n')
713 for h in techpack_out:
714 f.write(' "%s",\n' % h)
715
716 f.write(']\n')
717 f.write('\n')
718
719 gen_blueprints_module_name = 'qti_generate_gen_headers_%s' % header_arch
720
721 f.write('genrule {\n')
722 f.write(' // This module generates the gen_headers_<arch>.bp file\n')
723 f.write(' // (i.e., a new version of this file) so that it can be\n')
724 f.write(' // checked later to ensure that it matches the checked-\n')
725 f.write(' // in version (this file).\n')
726 f.write(' name: "%s",\n' % gen_blueprints_module_name)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800727 f.write(' srcs: gen_headers_srcs_%s,\n' % header_arch)
728 if exclude_srcs:
729 f.write(' exclude_srcs: gen_headers_exclude_srcs_%s,\n' % header_arch)
730
Prateek Sood13e5f682019-11-05 15:59:43 -0800731 f.write(' tool_files: ["kernel_headers.py"],\n')
732 f.write(' cmd: "python3 $(location kernel_headers.py) " +\n')
733 f.write(' kernel_headers_verbose +\n')
734 f.write(' "--header_arch %s " +\n' % header_arch)
735 f.write(' "--gen_dir $(genDir) " +\n')
736 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
737 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
738 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800739 f.write(' "blueprints " +\n')
740 f.write(' "# $(in)",\n')
Prateek Sood13e5f682019-11-05 15:59:43 -0800741 f.write(' out: ["gen_headers_%s.bp"],\n' % header_arch)
742 f.write('}\n')
743 f.write('\n')
744
745 f.write('genrule {\n')
746 f.write(' name: "qti_generate_kernel_headers_%s",\n' % header_arch)
Bill Peckhama6248a12021-01-26 13:06:41 -0800747 f.write(' tools: [\n')
748 f.write(' "%s",\n' % headers_install_sh)
749 f.write(' "%s",\n' % unifdef)
750 f.write(' ],\n')
Prateek Sood13e5f682019-11-05 15:59:43 -0800751 f.write(' tool_files: [\n')
752 f.write(' "%s",\n' % kernel_headers_py)
753
754 if header_arch == "arm":
755 f.write(' "%s",\n' % arm_syscall_tool)
756
757 f.write(' ],\n')
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800758 f.write(' srcs: gen_headers_srcs_%s +[\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800759 f.write(' "%s",\n' % old_gen_headers_bp)
760 f.write(' ":%s",\n' % gen_blueprints_module_name)
Prateek Sood13e5f682019-11-05 15:59:43 -0800761 f.write(' ],\n')
762
763 if exclude_srcs:
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800764 f.write(' exclude_srcs: gen_headers_exclude_srcs_%s,\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800765
766 f.write(' cmd: "python3 $(location %s) " +\n' % kernel_headers_py)
767 f.write(' kernel_headers_verbose +\n')
768 f.write(' "--header_arch %s " +\n' % header_arch)
769 f.write(' "--gen_dir $(genDir) " +\n')
770 f.write(' "--arch_asm_kbuild $(location %s) " +\n' % rel_arch_asm_kbuild)
771 f.write(' "--arch_include_uapi $(locations %s) " +\n' % arch_src)
772 f.write(' "--asm_generic_kbuild $(location %s) " +\n' % rel_asm_generic_kbuild)
773 f.write(' "headers " +\n')
774 f.write(' "--old_gen_headers_bp $(location %s) " +\n' % old_gen_headers_bp)
775 f.write(' "--new_gen_headers_bp $(location :%s) " +\n' % gen_blueprints_module_name)
776 f.write(' "--version_makefile $(location %s) " +\n' % makefile)
777
778 if header_arch == "arm":
779 f.write(' "--arch_syscall_tool $(location %s) " +\n' % arm_syscall_tool)
780 f.write(' "--arch_syscall_tbl $(location %s) " +\n' % arm_syscall_tbl)
781
782 f.write(' "--headers_install $(location %s) " +\n' % headers_install_sh)
Bill Peckhama6248a12021-01-26 13:06:41 -0800783 f.write(' "--unifdef $(location %s) " +\n' % unifdef)
Prateek Sood13e5f682019-11-05 15:59:43 -0800784 f.write(' "--include_uapi $(locations %s)",\n' % generic_src)
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800785 f.write(' out: ["linux/version.h"] + gen_headers_out_%s,\n' % header_arch)
Prateek Sood13e5f682019-11-05 15:59:43 -0800786 f.write('}\n')
787
788 return 0
789
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800790def parse_bp_for_headers(file_name, headers):
791 parsing_headers = False
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -0800792 pattern = re.compile("gen_headers_out_[a-zA-Z0-9]+\s*=\s*\[\s*")
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800793 with open(file_name, 'r') as f:
794 for line in f:
795 line = line.strip()
796 if pattern.match(line):
797 parsing_headers = True
798 continue
799
800 if line.find("]") != -1 and parsing_headers:
801 break
802
803 if not parsing_headers:
804 continue
805
806 if line.find("//") == 0:
807 continue
808
809 headers.add(line[1:-2])
810
811def headers_diff(old_file, new_file):
812 old_headers = set()
813 new_headers = set()
814 diff_detected = False
815
816 parse_bp_for_headers(old_file, old_headers)
817 parse_bp_for_headers(new_file, new_headers)
818
819 diff = old_headers - new_headers
820 if len(diff):
821 diff_detected = True
822 print("Headers to remove:")
823 for x in diff:
824 print("\t{}".format(x))
825
826 diff = new_headers - old_headers
827 if len(diff):
828 diff_detected = True
829 print("Headers to add:")
830 for x in diff:
831 print("\t{}".format(x))
832
833 return diff_detected
Prateek Sood13e5f682019-11-05 15:59:43 -0800834
835def gen_headers(
836 verbose, header_arch, gen_dir, arch_asm_kbuild, asm_generic_kbuild, module_dir,
837 old_gen_headers_bp, new_gen_headers_bp, version_makefile,
Bill Peckhama6248a12021-01-26 13:06:41 -0800838 arch_syscall_tool, arch_syscall_tbl, headers_install, unifdef, include_uapi,
Prateek Sood13e5f682019-11-05 15:59:43 -0800839 arch_include_uapi, techpack_include_uapi):
840 """Generate the kernel headers.
841
842 This script generates the version.h file, the arch-specific headers including
843 syscall-related generated files and wrappers around generic files, and uses
844 the headers_install tool to process other generic uapi and arch-specific uapi
845 files.
846
847 Args:
848 verbose: Set True to print progress messages.
849 header_arch: The arch for which to generate headers.
850 gen_dir: Where to place the generated files.
851 arch_asm_kbuild: The Kbuild file containing lists of headers to generate.
852 asm_generic_kbuild: The Kbuild file containing mandatory headers.
853 module_dir: The root directory of the kernel source.
854 old_gen_headers_bp: The old gen_headers_<arch>.bp file to check.
855 new_gen_headers_bp: The new gen_headers_<arch>.bp file to check.
856 version_makefile: The kernel Makefile that contains version info.
857 arch_syscall_tool: The arch script that generates syscall headers.
858 arch_syscall_tbl: The arch script that defines syscall vectors.
859 headers_install: The headers_install tool to process input headers.
Bill Peckhama6248a12021-01-26 13:06:41 -0800860 unifdef: The unifdef tool used by headers_install.
Prateek Sood13e5f682019-11-05 15:59:43 -0800861 include_uapi: The list of include/uapi header files.
862 arch_include_uapi: The list of arch/<arch>/include/uapi header files.
863 Return:
864 The number of errors encountered.
865 """
866
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800867 if headers_diff(old_gen_headers_bp, new_gen_headers_bp):
Prateek Sood13e5f682019-11-05 15:59:43 -0800868 print('error: gen_headers blueprints file is out of date, suggested fix:')
Siddharth Guptacbb01b52020-01-29 17:22:38 -0800869 print('#######Please add or remove the above mentioned headers from %s' % (old_gen_headers_bp))
Prateek Sood13e5f682019-11-05 15:59:43 -0800870 print('then re-run the build')
871 return 1
872
873 error_count = 0
874
875 if not gen_version_h(verbose, gen_dir, version_makefile):
876 error_count += 1
877
878 error_count += gen_arch_headers(
879 verbose, gen_dir, arch_asm_kbuild, asm_generic_kbuild, arch_syscall_tool, arch_syscall_tbl ,arch_include_uapi)
880
881 uapi_include_prefix = os.path.join(module_dir, 'include', 'uapi') + os.sep
882
883 arch_uapi_include_prefix = os.path.join(
884 module_dir, 'arch', header_arch, 'include', 'uapi') + os.sep
885
886 for h in include_uapi:
887 if not run_headers_install(
Bill Peckhama6248a12021-01-26 13:06:41 -0800888 verbose, gen_dir, headers_install, unifdef,
Prateek Sood13e5f682019-11-05 15:59:43 -0800889 uapi_include_prefix, h):
890 error_count += 1
891
892 for h in arch_include_uapi:
893 if not run_headers_install(
Bill Peckhama6248a12021-01-26 13:06:41 -0800894 verbose, gen_dir, headers_install, unifdef,
Prateek Sood13e5f682019-11-05 15:59:43 -0800895 arch_uapi_include_prefix, h):
896 error_count += 1
897
898 for h in techpack_include_uapi:
899 techpack_uapi_include_prefix = os.path.join(h.split('/include/uapi')[0], 'include', 'uapi') + os.sep
900 if not run_headers_install(
Bill Peckhama6248a12021-01-26 13:06:41 -0800901 verbose, gen_dir, headers_install, unifdef,
Prateek Sood13e5f682019-11-05 15:59:43 -0800902 techpack_uapi_include_prefix, h):
903 error_count += 1
904
905 return error_count
906
907def extract_techpack_uapi_headers(verbose, module_dir):
908
909 """EXtract list of uapi headers from techpack/* directories. We need to export
910 these headers to userspace.
911
912 Args:
913 verbose: Verbose option is provided to script
914 module_dir: Base directory
915 Returs:
916 List of uapi headers
917 """
918
919 techpack_subdir = []
920 techpack_dir = os.path.join(module_dir,'techpack')
921 techpack_uapi = []
922 techpack_uapi_sub = []
923
924 #get list of techpack directories under techpack/
925 if os.path.isdir(techpack_dir):
926 items = sorted(os.listdir(techpack_dir))
927 for x in items:
928 p = os.path.join(techpack_dir, x)
929 if os.path.isdir(p):
930 techpack_subdir.append(p)
931
932 #Print list of subdirs obtained
933 if (verbose):
934 for x in techpack_subdir:
935 print(x)
936
937 #For every subdirectory get list of .h files under include/uapi and append to techpack_uapi list
938 for x in techpack_subdir:
939 techpack_uapi_path = os.path.join(x, 'include/uapi')
940 if (os.path.isdir(techpack_uapi_path)):
941 techpack_uapi_sub = []
942 find_out(verbose, x, 'include/uapi', '**/*.h', None, techpack_uapi_sub)
943 tmp = [os.path.join(techpack_uapi_path, y) for y in techpack_uapi_sub]
944 techpack_uapi = techpack_uapi + tmp
945
946 if (verbose):
947 for x in techpack_uapi:
948 print(x)
949
950 return techpack_uapi
951
952def main():
953 """Parse command line arguments and perform top level control."""
954
955 parser = argparse.ArgumentParser(
956 description=__doc__,
957 formatter_class=argparse.RawDescriptionHelpFormatter)
958
959 # Arguments that apply to every invocation of this script.
960
961 parser.add_argument(
962 '--verbose',
963 action='store_true',
964 help='Print output that describes the workings of this script.')
965 parser.add_argument(
966 '--header_arch',
967 required=True,
968 help='The arch for which to generate headers.')
969 parser.add_argument(
970 '--gen_dir',
971 required=True,
972 help='Where to place the generated files.')
973 parser.add_argument(
974 '--arch_asm_kbuild',
975 required=True,
976 help='The Kbuild file containing lists of headers to generate.')
977 parser.add_argument(
978 '--asm_generic_kbuild',
979 required=True,
980 help='The Kbuild file containing lists of mandatory headers.')
981 parser.add_argument(
982 '--arch_include_uapi',
983 required=True,
984 nargs='*',
985 help='The list of arch/<arch>/include/uapi header files.')
986
987 # The modes.
988
989 subparsers = parser.add_subparsers(
990 dest='mode',
991 help='Select mode')
992 parser_blueprints = subparsers.add_parser(
993 'blueprints',
994 help='Generate the gen_headers_<arch>.bp file.')
995 parser_headers = subparsers.add_parser(
996 'headers',
997 help='Check blueprints, then generate kernel headers.')
998
999 # Arguments that apply to headers mode.
1000
1001 parser_headers.add_argument(
1002 '--old_gen_headers_bp',
1003 required=True,
1004 help='The old gen_headers_<arch>.bp file to check.')
1005 parser_headers.add_argument(
1006 '--new_gen_headers_bp',
1007 required=True,
1008 help='The new gen_headers_<arch>.bp file to check.')
1009 parser_headers.add_argument(
1010 '--version_makefile',
1011 required=True,
1012 help='The kernel Makefile that contains version info.')
1013 parser_headers.add_argument(
1014 '--arch_syscall_tool',
1015 help='The arch script that generates syscall headers, if applicable.')
1016 parser_headers.add_argument(
1017 '--arch_syscall_tbl',
1018 help='The arch script that defines syscall vectors, if applicable.')
1019 parser_headers.add_argument(
1020 '--headers_install',
1021 required=True,
1022 help='The headers_install tool to process input headers.')
1023 parser_headers.add_argument(
Bill Peckhama6248a12021-01-26 13:06:41 -08001024 '--unifdef',
1025 required=True,
1026 help='The unifdef tool used by headers_install.')
1027 parser_headers.add_argument(
Prateek Sood13e5f682019-11-05 15:59:43 -08001028 '--include_uapi',
1029 required=True,
1030 nargs='*',
1031 help='The list of include/uapi header files.')
1032
1033 args = parser.parse_args()
1034
1035 if args.verbose:
1036 print('mode [%s]' % args.mode)
1037 print('header_arch [%s]' % args.header_arch)
1038 print('gen_dir [%s]' % args.gen_dir)
1039 print('arch_asm_kbuild [%s]' % args.arch_asm_kbuild)
1040 print('asm_generic_kbuild [%s]' % args.asm_generic_kbuild)
1041
1042 # Extract the module_dir from args.arch_asm_kbuild and rel_arch_asm_kbuild.
1043
1044 rel_arch_asm_kbuild = os.path.join(
1045 'arch', args.header_arch, 'include/uapi/asm/Kbuild')
1046
1047 suffix = os.sep + rel_arch_asm_kbuild
1048
1049 if not args.arch_asm_kbuild.endswith(suffix):
1050 print('error: expected %s to end with %s' % (args.arch_asm_kbuild, suffix))
1051 return 1
1052
1053 module_dir = args.arch_asm_kbuild[:-len(suffix)]
1054
1055 rel_asm_generic_kbuild = os.path.join('include/uapi/asm-generic', os.path.basename(args.asm_generic_kbuild))
1056
1057
1058 if args.verbose:
1059 print('module_dir [%s]' % module_dir)
1060
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -08001061 techpack_include_uapi = []
1062
Prateek Sood13e5f682019-11-05 15:59:43 -08001063
1064 if args.mode == 'blueprints':
1065 return gen_blueprints(
1066 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
Rishabh Bhatnagar9e1c45e2020-02-12 13:50:44 -08001067 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 -08001068
1069 if args.mode == 'headers':
1070 if args.verbose:
1071 print('old_gen_headers_bp [%s]' % args.old_gen_headers_bp)
1072 print('new_gen_headers_bp [%s]' % args.new_gen_headers_bp)
1073 print('version_makefile [%s]' % args.version_makefile)
1074 print('arch_syscall_tool [%s]' % args.arch_syscall_tool)
1075 print('arch_syscall_tbl [%s]' % args.arch_syscall_tbl)
1076 print('headers_install [%s]' % args.headers_install)
Bill Peckhama6248a12021-01-26 13:06:41 -08001077 print('unifdef [%s]' % args.unifdef)
Prateek Sood13e5f682019-11-05 15:59:43 -08001078
1079 return gen_headers(
1080 args.verbose, args.header_arch, args.gen_dir, args.arch_asm_kbuild,
1081 args.asm_generic_kbuild, module_dir, args.old_gen_headers_bp, args.new_gen_headers_bp,
1082 args.version_makefile, args.arch_syscall_tool, args.arch_syscall_tbl,
Bill Peckhama6248a12021-01-26 13:06:41 -08001083 args.headers_install, args.unifdef, args.include_uapi, args.arch_include_uapi,
1084 techpack_include_uapi)
Prateek Sood13e5f682019-11-05 15:59:43 -08001085
1086 print('error: unknown mode: %s' % args.mode)
1087 return 1
1088
1089
1090if __name__ == '__main__':
1091 sys.exit(main())