blob: 6a704eb2e0b52d74886196934536d94b7be91d51 [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):
ncteisen0cd6cfe2017-12-11 16:56:44 -080072 if name.startswith('absl/'): return True
73 # print target['name'], name
74 if name in target['headers']:
75 return True
76 for dep in target['deps']:
77 if target_has_header(get_target(dep), name):
78 return True
79 if name in [
80 'src/core/lib/profiling/stap_probes.h',
81 'src/proto/grpc/reflection/v1alpha/reflection.grpc.pb.h'
82 ]:
83 return True
84 return False
85
Craig Tillerf75fc122015-06-25 06:58:00 -070086
Craig Tiller732a8752016-02-22 15:59:19 -080087def produces_object(name):
ncteisen0cd6cfe2017-12-11 16:56:44 -080088 return os.path.splitext(name)[1] in ['.c', '.cc']
89
Craig Tiller732a8752016-02-22 15:59:19 -080090
Craig Tiller102fa962016-08-22 13:56:36 -070091c_ish = {}
92obj_producer_to_source = {'c': c_ish, 'c++': c_ish, 'csharp': {}}
Craig Tiller732a8752016-02-22 15:59:19 -080093
Craig Tillerf75fc122015-06-25 06:58:00 -070094errors = 0
95for target in js:
ncteisen0cd6cfe2017-12-11 16:56:44 -080096 if not target['third_party']:
97 for fn in target['src']:
98 with open(os.path.join(root, fn)) as f:
99 src = f.read().splitlines()
100 for line in src:
101 m = re_inc1.match(line)
102 if m:
103 if not target_has_header(target, m.group(1)):
104 print(
105 'target %s (%s) does not name header %s as a dependency'
106 % (target['name'], fn, m.group(1)))
107 errors += 1
108 m = re_inc2.match(line)
109 if m:
110 if not target_has_header(target, 'include/' + m.group(1)):
111 print(
112 'target %s (%s) does not name header %s as a dependency'
113 % (target['name'], fn, m.group(1)))
114 errors += 1
115 if target['type'] in ['lib', 'filegroup']:
116 for fn in target['src']:
117 language = target['language']
118 if produces_object(fn):
119 obj_base = os.path.splitext(os.path.basename(fn))[0]
120 if obj_base in obj_producer_to_source[language]:
121 if obj_producer_to_source[language][obj_base] != fn:
122 print(
123 'target %s (%s) produces an aliased object file with %s'
124 % (target['name'], fn,
125 obj_producer_to_source[language][obj_base]))
126 else:
127 obj_producer_to_source[language][obj_base] = fn
Craig Tillerf75fc122015-06-25 06:58:00 -0700128
David Garcia Quintas45484b32016-01-14 18:59:20 -0800129assert errors == 0