summaryrefslogtreecommitdiff
path: root/deps/v8/tools/verify_source_deps.py
blob: e3a39c1d17c481ffadc75149397867ad860babca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
#!/usr/bin/env python
# Copyright 2015 the V8 project authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""
Script to print potentially missing source dependencies based on the actual
.h and .cc files in the source tree and which files are included in the gyp
and gn files. The latter inclusion is overapproximated.

TODO(machenbach): If two source files with the same name exist, but only one
is referenced from a gyp/gn file, we won't necessarily detect it.
"""

import itertools
import re
import os
import subprocess
import sys


V8_BASE = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

GYP_FILES = [
  os.path.join(V8_BASE, 'src', 'd8.gyp'),
  os.path.join(V8_BASE, 'src', 'v8.gyp'),
  os.path.join(V8_BASE, 'src', 'inspector', 'inspector.gypi'),
  os.path.join(V8_BASE, 'src', 'third_party', 'vtune', 'v8vtune.gyp'),
  os.path.join(V8_BASE, 'samples', 'samples.gyp'),
  os.path.join(V8_BASE, 'test', 'cctest', 'cctest.gyp'),
  os.path.join(V8_BASE, 'test', 'fuzzer', 'fuzzer.gyp'),
  os.path.join(V8_BASE, 'test', 'unittests', 'unittests.gyp'),
  os.path.join(V8_BASE, 'test', 'inspector', 'inspector.gyp'),
  os.path.join(V8_BASE, 'test', 'mkgrokdump', 'mkgrokdump.gyp'),
  os.path.join(V8_BASE, 'testing', 'gmock.gyp'),
  os.path.join(V8_BASE, 'testing', 'gtest.gyp'),
  os.path.join(V8_BASE, 'tools', 'parser-shell.gyp'),
]

ALL_GYP_PREFIXES = [
  '..',
  'common',
  os.path.join('src', 'third_party', 'vtune'),
  'src',
  'samples',
  'testing',
  'tools',
  os.path.join('test', 'cctest'),
  os.path.join('test', 'common'),
  os.path.join('test', 'fuzzer'),
  os.path.join('test', 'unittests'),
  os.path.join('test', 'inspector'),
  os.path.join('test', 'mkgrokdump'),
]

GYP_UNSUPPORTED_FEATURES = [
  'gcmole',
  'setup-isolate-deserialize.cc',
  'v8-version.h'
]

GN_FILES = [
  os.path.join(V8_BASE, 'BUILD.gn'),
  os.path.join(V8_BASE, 'build', 'secondary', 'testing', 'gmock', 'BUILD.gn'),
  os.path.join(V8_BASE, 'build', 'secondary', 'testing', 'gtest', 'BUILD.gn'),
  os.path.join(V8_BASE, 'src', 'inspector', 'BUILD.gn'),
  os.path.join(V8_BASE, 'test', 'cctest', 'BUILD.gn'),
  os.path.join(V8_BASE, 'test', 'unittests', 'BUILD.gn'),
  os.path.join(V8_BASE, 'test', 'inspector', 'BUILD.gn'),
  os.path.join(V8_BASE, 'test', 'mkgrokdump', 'BUILD.gn'),
  os.path.join(V8_BASE, 'tools', 'BUILD.gn'),
]

GN_UNSUPPORTED_FEATURES = [
  'aix',
  'cygwin',
  'freebsd',
  'gcmole',
  'openbsd',
  'ppc',
  'qnx',
  'solaris',
  'vtune',
  'v8-version.h',
  'x87',
]

ALL_GN_PREFIXES = [
  '..',
  os.path.join('src', 'inspector'),
  'src',
  'testing',
  os.path.join('test', 'cctest'),
  os.path.join('test', 'unittests'),
  os.path.join('test', 'inspector'),
  os.path.join('test', 'mkgrokdump'),
]

def pathsplit(path):
  return re.split('[/\\\\]', path)

def path_no_prefix(path, prefixes):
  for prefix in prefixes:
    if path.startswith(prefix + os.sep):
      return path_no_prefix(path[len(prefix) + 1:], prefixes)
  return path


def isources(prefixes):
  cmd = ['git', 'ls-tree', '-r', 'HEAD', '--full-name', '--name-only']
  for f in subprocess.check_output(cmd, universal_newlines=True).split('\n'):
    if not (f.endswith('.h') or f.endswith('.cc')):
      continue
    yield path_no_prefix(os.path.join(*pathsplit(f)), prefixes)


def iflatten(obj):
  if isinstance(obj, dict):
    for value in obj.values():
      for i in iflatten(value):
        yield i
  elif isinstance(obj, list):
    for value in obj:
      for i in iflatten(value):
        yield i
  elif isinstance(obj, basestring):
    yield path_no_prefix(os.path.join(*pathsplit(obj)), ALL_GYP_PREFIXES)


def iflatten_gyp_file(gyp_file):
  """Overaproximates all values in the gyp file.

  Iterates over all string values recursively. Removes '../' path prefixes.
  """
  with open(gyp_file) as f:
    return iflatten(eval(f.read()))


def iflatten_gn_file(gn_file):
  """Overaproximates all values in the gn file.

  Iterates over all double quoted strings.
  """
  with open(gn_file) as f:
    for line in f.read().splitlines():
      match = re.match(r'.*"([^"]*)".*', line)
      if match:
        yield path_no_prefix(
            os.path.join(*pathsplit(match.group(1))), ALL_GN_PREFIXES)


def icheck_values(values, prefixes):
  for source_file in isources(prefixes):
    if source_file not in values:
      yield source_file


def missing_gyp_files():
  gyp_values = set(itertools.chain(
    *[iflatten_gyp_file(gyp_file) for gyp_file in GYP_FILES]
    ))
  gyp_files = sorted(icheck_values(gyp_values, ALL_GYP_PREFIXES))
  return filter(
      lambda x: not any(i in x for i in GYP_UNSUPPORTED_FEATURES), gyp_files)


def missing_gn_files():
  gn_values = set(itertools.chain(
    *[iflatten_gn_file(gn_file) for gn_file in GN_FILES]
    ))

  gn_files = sorted(icheck_values(gn_values, ALL_GN_PREFIXES))
  return filter(
      lambda x: not any(i in x for i in GN_UNSUPPORTED_FEATURES), gn_files)


def main():
  print "----------- Files not in gyp: ------------"
  for i in missing_gyp_files():
    print i

  print "\n----------- Files not in gn: -------------"
  for i in missing_gn_files():
    print i
  return 0

if '__main__' == __name__:
  sys.exit(main())