1#!/usr/bin/env python3 2 3# Copyright 2021 gRPC authors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import collections 18import os 19 20 21def to_inc(filename): 22 """Given filename, synthesize what should go in an include statement to get that file""" 23 if filename.startswith("include/"): 24 return '<%s>' % filename[len("include/"):] 25 return '"%s"' % filename 26 27 28def set_pragma(filename, pragma): 29 """Set the file-level IWYU pragma in filename""" 30 lines = [] 31 saw_first_define = False 32 for line in open(filename).read().splitlines(): 33 if line.startswith('// IWYU pragma: '): 34 continue 35 lines.append(line) 36 if not saw_first_define and line.startswith('#define '): 37 saw_first_define = True 38 lines.append('') 39 lines.append('// IWYU pragma: %s' % pragma) 40 lines.append('') 41 open(filename, 'w').write('\n'.join(lines) + '\n') 42 43 44def set_exports(pub, cg): 45 """In file pub, mark the include for cg with IWYU pragma: export""" 46 lines = [] 47 for line in open(pub).read().splitlines(): 48 if line.startswith('#include %s' % to_inc(cg)): 49 lines.append('#include %s // IWYU pragma: export' % to_inc(cg)) 50 else: 51 lines.append(line) 52 open(pub, 'w').write('\n'.join(lines) + '\n') 53 54 55CG_ROOTS_GRPC = ( 56 (r'sync', 'grpc/support/sync.h'), 57 (r'atm', 'grpc/support/atm.h'), 58) 59 60CG_ROOTS_GRPCPP = [] 61 62 63def fix_tree(tree, cg_roots): 64 """Fix one include tree""" 65 # Map of filename --> paths including that filename 66 reverse_map = collections.defaultdict(list) 67 # The same, but for things with '/impl/codegen' in their names 68 cg_reverse_map = collections.defaultdict(list) 69 for root, dirs, files in os.walk(tree): 70 root_map = cg_reverse_map if '/impl/codegen' in root else reverse_map 71 for filename in files: 72 root_map[filename].append(root) 73 # For each thing in '/impl/codegen' figure out what exports it 74 for filename, paths in cg_reverse_map.items(): 75 # Exclude non-headers 76 if not filename.endswith('.h'): 77 continue 78 pragma = None 79 # Check for our 'special' headers: if we see one of these, we just 80 # hardcode where they go to because there's some complicated rules. 81 for root, target in cg_roots: 82 if filename.startswith(root): 83 pragma = 'private, include <%s>' % target 84 if len(paths) == 1: 85 path = paths[0] 86 if filename.startswith(root + '.'): 87 set_exports('include/' + target, path + '/' + filename) 88 if filename.startswith(root + '_'): 89 set_exports(path + '/' + root + '.h', 90 path + '/' + filename) 91 # If the path for a file in /impl/codegen is ambiguous, just don't bother 92 if not pragma and len(paths) == 1: 93 path = paths[0] 94 # Check if we have an exporting candidate 95 if filename in reverse_map: 96 proper = reverse_map[filename] 97 # And that it too is unambiguous 98 if len(proper) == 1: 99 # Build the two relevant pathnames 100 cg = path + '/' + filename 101 pub = proper[0] + '/' + filename 102 # And see if the public file actually includes the /impl/codegen file 103 if ('#include %s' % to_inc(cg)) in open(pub).read(): 104 # Finally, if it does, we'll set that pragma 105 pragma = 'private, include %s' % to_inc(pub) 106 # And mark the export 107 set_exports(pub, cg) 108 # If we can't find a good alternative include to point people to, 109 # mark things private anyway... we don't want to recommend people include 110 # from impl/codegen 111 if not pragma: 112 pragma = 'private' 113 for path in paths: 114 set_pragma(path + '/' + filename, pragma) 115 116 117fix_tree('include/grpc', CG_ROOTS_GRPC) 118fix_tree('include/grpcpp', CG_ROOTS_GRPCPP) 119