1#!/usr/bin/python3 2# Check that a wrapper header exist for each non-sysdeps header. 3# Copyright (C) 2019-2022 Free Software Foundation, Inc. 4# This file is part of the GNU C Library. 5# 6# The GNU C Library is free software; you can redistribute it and/or 7# modify it under the terms of the GNU Lesser General Public 8# License as published by the Free Software Foundation; either 9# version 2.1 of the License, or (at your option) any later version. 10# 11# The GNU C Library is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14# Lesser General Public License for more details. 15# 16# You should have received a copy of the GNU Lesser General Public 17# License along with the GNU C Library; if not, see 18# <https://www.gnu.org/licenses/>. 19 20# Non-sysdeps subdirectories are not on the C include path, so 21# installed headers need to have a sysdep wrapper header. 22# 23# usage: scripts/checl-wrapper-headers.py \ 24# --root=$(..) --subdir=$(subdir) $(headers) \ 25# [--generated $(common-generated)] 26# 27# If invoked with --root=., the script is invoked from the root of the 28# source tree, so paths starting with "include/" are skipped (because 29# those do not require wrappers). 30 31import argparse 32import os 33import sys 34 35# Some subdirectories are only compiled for essentially one target. 36# In this case, we do not need to check for consistent wrapper 37# headers. Hurd uses a custom way to Hurd-specific inject wrapper 38# headers; see sysdeps/mach/Makefiles under "ifdef in-Makerules". 39SINGLE_TARGET_SUBDIRS = frozenset(("hurd", "mach")) 40 41# Name of the special subdirectory with the wrapper headers. 42INCLUDE = "include" 43 44def check_sysdeps_bits(args): 45 """Check that the directory sysdeps/generic/bits does not exist.""" 46 bits = os.path.join(args.root, 'sysdeps', 'generic', 'bits') 47 if os.path.exists(bits): 48 # See commit c72565e5f1124c2dc72573e83406fe999e56091f and 49 # <https://sourceware.org/ml/libc-alpha/2016-05/msg00189.html>. 50 print('error: directory {} has been added, use bits/ instead'.format( 51 os.path.relpath(os.path.realpath(bits), args.root))) 52 return False 53 return True 54 55def check_headers_root(args): 56 """Check headers located at the top level of the source tree.""" 57 good = True 58 generated = frozenset(args.generated) 59 for header in args.headers: 60 if not (header.startswith('bits/') 61 or os.path.exists(os.path.join(args.root, INCLUDE, header)) 62 or header in generated): 63 print('error: top-level header {} must be in bits/ or {}/' 64 .format(header, INCLUDE)) 65 good = False 66 return good 67 68def check_headers(args): 69 """Check headers located in a subdirectory.""" 70 good = True 71 for header in args.headers: 72 # Whitelist .x files, which never have include wrappers. 73 if header.endswith(".x"): 74 continue 75 76 is_nonsysdep_header = os.access(header, os.R_OK) 77 if is_nonsysdep_header: 78 # Skip Fortran header files. 79 if header.startswith("finclude/"): 80 continue 81 82 include_path = os.path.join(args.root, INCLUDE, header) 83 if not os.access(include_path, os.R_OK): 84 print('error: missing wrapper header {} for {}'.format( 85 os.path.join(INCLUDE, header), 86 os.path.relpath(os.path.realpath(header), args.root))) 87 good = False 88 return good 89 90def main(): 91 """The main entry point.""" 92 parser = argparse.ArgumentParser( 93 description='Check for missing wrapper headers in include/.') 94 parser.add_argument('--root', metavar='DIRECTORY', required=True, 95 help='Path to the top-level of the source tree') 96 parser.add_argument('--subdir', metavar='DIRECTORY', required=True, 97 help='Name of the subdirectory being processed') 98 parser.add_argument('--generated', metavar='FILE', default="", nargs="*", 99 help="Generated files (which are ignored)") 100 parser.add_argument('headers', help='Header files to process', nargs='+') 101 args = parser.parse_args() 102 103 good = (args.root == '.') == (args.subdir == '.') 104 if not good: 105 print('error: --root/--subdir disagree about top-of-tree location') 106 107 if args.subdir == '.': 108 good &= check_sysdeps_bits(args) 109 good &= check_headers_root(args) 110 elif args.subdir not in SINGLE_TARGET_SUBDIRS: 111 good &= check_headers(args) 112 113 if not good: 114 sys.exit(1) 115 116if __name__ == '__main__': 117 main() 118