blob: 57ae5c5acc47fc97a5729e73ef4da4b1a71cef93 [file] [log] [blame]
Siddharth Shukla8e64d902017-03-12 19:50:18 +01001#!/usr/bin/env python
Jan Tattermusch7897ae92017-06-07 22:57:36 +02002# Copyright 2015 gRPC authors.
Craig Tiller897e4fe2015-12-22 15:03:40 -08003#
Jan Tattermusch7897ae92017-06-07 22:57:36 +02004# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
Craig Tiller897e4fe2015-12-22 15:03:40 -08007#
Jan Tattermusch7897ae92017-06-07 22:57:36 +02008# http://www.apache.org/licenses/LICENSE-2.0
Craig Tiller897e4fe2015-12-22 15:03:40 -08009#
Jan Tattermusch7897ae92017-06-07 22:57:36 +020010# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
Craig Tillerf75fc122015-06-25 06:58:00 -070015
Siddharth Shuklad194f592017-03-11 19:12:43 +010016from __future__ import print_function
17
Craig Tillerf75fc122015-06-25 06:58:00 -070018import json
19import os
20import re
21import sys
22
Jan Tattermusch788ee232016-01-26 12:19:44 -080023root = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '../../..'))
ncteisen0cd6cfe2017-12-11 16:56:44 -080024with open(
25 os.path.join(root, 'tools', 'run_tests', 'generated',
26 'sources_and_headers.json')) as f:
27 js = json.loads(f.read())
Craig Tillerf75fc122015-06-25 06:58:00 -070028
29re_inc1 = re.compile(r'^#\s*include\s*"([^"]*)"')
30assert re_inc1.match('#include "foo"').group(1) == 'foo'
31re_inc2 = re.compile(r'^#\s*include\s*<((grpc|grpc\+\+)/[^"]*)>')
32assert re_inc2.match('#include <grpc++/foo>').group(1) == 'grpc++/foo'
33
ncteisen0cd6cfe2017-12-11 16:56:44 -080034
Craig Tillerf75fc122015-06-25 06:58:00 -070035def get_target(name):
ncteisen0cd6cfe2017-12-11 16:56:44 -080036 for target in js:
37 if target['name'] == name:
38 return target
39 assert False, 'no target %s' % name
40
Craig Tillerf75fc122015-06-25 06:58:00 -070041
Jan Tattermusch38466bc2017-12-09 09:13:47 -080042def get_headers_transitive():
ncteisenca1548f2017-12-12 07:50:20 -080043 """Computes set of headers transitively provided by each target"""
44 target_headers_transitive = {}
Jan Tattermusch38466bc2017-12-09 09:13:47 -080045 for target in js:
ncteisenca1548f2017-12-12 07:50:20 -080046 target_name = target['name']
47 assert not target_headers_transitive.has_key(target_name)
48 target_headers_transitive[target_name] = set(target['headers'])
49
50 # Make sure each target's transitive headers contain those
51 # of their dependencies. If not, add them and continue doing
52 # so until we get a full pass over all targets without any updates.
53 closure_changed = True
54 while closure_changed:
55 closure_changed = False
56 for target in js:
57 target_name = target['name']
58 for dep in target['deps']:
59 headers = target_headers_transitive[target_name]
60 old_count = len(headers)
61 headers.update(target_headers_transitive[dep])
62 if old_count != len(headers):
63 closure_changed = True
64 return target_headers_transitive
Jan Tattermusch38466bc2017-12-09 09:13:47 -080065
66
67# precompute transitive closure of headers provided by each target
68target_headers_transitive = get_headers_transitive()
69
70
Craig Tillerf75fc122015-06-25 06:58:00 -070071def target_has_header(target, name):
Jan Tattermusch0b62b2f2018-01-10 11:38:37 +010072 if name in target_headers_transitive[target['name']]:
ncteisen0cd6cfe2017-12-11 16:56:44 -080073 return True
Jan Tattermusch0b62b2f2018-01-10 11:38:37 +010074 if name.startswith('absl/'):
75 return True
ncteisen0cd6cfe2017-12-11 16:56:44 -080076 if name in [
77 'src/core/lib/profiling/stap_probes.h',
78 'src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h'
79 ]:
80 return True
81 return False
82
Craig Tillerf75fc122015-06-25 06:58:00 -070083
Craig Tiller732a8752016-02-22 15:59:19 -080084def produces_object(name):
ncteisen0cd6cfe2017-12-11 16:56:44 -080085 return os.path.splitext(name)[1] in ['.c', '.cc']
86
Craig Tiller732a8752016-02-22 15:59:19 -080087
Craig Tiller102fa962016-08-22 13:56:36 -070088c_ish = {}
89obj_producer_to_source = {'c': c_ish, 'c++': c_ish, 'csharp': {}}
Craig Tiller732a8752016-02-22 15:59:19 -080090
Craig Tillerf75fc122015-06-25 06:58:00 -070091errors = 0
92for target in js:
ncteisen0cd6cfe2017-12-11 16:56:44 -080093 if not target['third_party']:
94 for fn in target['src']:
95 with open(os.path.join(root, fn)) as f:
96 src = f.read().splitlines()
97 for line in src:
98 m = re_inc1.match(line)
99 if m:
100 if not target_has_header(target, m.group(1)):
101 print(
102 'target %s (%s) does not name header %s as a dependency'
103 % (target['name'], fn, m.group(1)))
104 errors += 1
105 m = re_inc2.match(line)
106 if m:
107 if not target_has_header(target, 'include/' + m.group(1)):
108 print(
109 'target %s (%s) does not name header %s as a dependency'
110 % (target['name'], fn, m.group(1)))
111 errors += 1
112 if target['type'] in ['lib', 'filegroup']:
113 for fn in target['src']:
114 language = target['language']
115 if produces_object(fn):
116 obj_base = os.path.splitext(os.path.basename(fn))[0]
117 if obj_base in obj_producer_to_source[language]:
118 if obj_producer_to_source[language][obj_base] != fn:
119 print(
120 'target %s (%s) produces an aliased object file with %s'
121 % (target['name'], fn,
122 obj_producer_to_source[language][obj_base]))
123 else:
124 obj_producer_to_source[language][obj_base] = fn
Craig Tillerf75fc122015-06-25 06:58:00 -0700125
David Garcia Quintas45484b32016-01-14 18:59:20 -0800126assert errors == 0