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

tools / include_tracer.py [blame]

#!/usr/bin/env python
# Copyright 2011 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# based on an almost identical script by: jyrki@google.com (Jyrki Alakuijala)

"""Prints out include dependencies in chrome.

Since it ignores defines, it gives just a rough estimation of file size.

Usage:
  tools/include_tracer.py -Iout/Default/gen chrome/browser/ui/browser.h
"""

from __future__ import print_function

import argparse
import os
import re
import sys

# Created by copying the command line for prerender_browsertest.cc, replacing
# spaces with newlines, and dropping everything except -F and -I switches.
# TODO(port): Add windows, linux directories.
INCLUDE_PATHS = [
  '',
  'gpu',
  'skia/config',
  'skia/ext',
  'testing/gmock/include',
  'testing/gtest/include',
  'third_party/google_toolbox_for_mac/src',
  'third_party/icu/public/common',
  'third_party/icu/public/i18n',
  'third_party/protobuf',
  'third_party/protobuf/src',
  'third_party/skia/gpu/include',
  'third_party/skia/include/config',
  'third_party/skia/include/core',
  'third_party/skia/include/effects',
  'third_party/skia/include/gpu',
  'third_party/skia/include/pdf',
  'third_party/skia/include/ports',
  'v8/include',
]


def Walk(include_dirs, seen, filename, parent, indent):
  """Returns the size of |filename| plus the size of all files included by
  |filename| and prints the include tree of |filename| to stdout. Every file
  is visited at most once.
  """
  total_bytes = 0

  # .proto(devel) filename translation
  if filename.endswith('.pb.h'):
    basename = filename[:-5]
    if os.path.exists(basename + '.proto'):
      filename = basename + '.proto'
    else:
      print('could not find ', filename)

  # Show and count files only once.
  if filename in seen:
    return total_bytes
  seen.add(filename)

  # Display the paths.
  print(' ' * indent + filename)

  # Skip system includes.
  if filename[0] == '<':
    return total_bytes

  # Find file in all include paths.
  resolved_filename = filename
  for root in INCLUDE_PATHS + [os.path.dirname(parent)] + include_dirs:
    if os.path.exists(os.path.join(root, filename)):
      resolved_filename = os.path.join(root, filename)
      break

  # Recurse.
  if os.path.exists(resolved_filename):
    lines = open(resolved_filename).readlines()
  else:
    print(' ' * (indent + 2) + "-- not found")
    lines = []
  for line in lines:
    line = line.strip()
    match = re.match(r'#include\s+(\S+).*', line)
    if match:
      include = match.group(1)
      if include.startswith('"'):
        include = include[1:-1]
      total_bytes += Walk(
        include_dirs, seen, include, resolved_filename, indent + 2)
    elif line.startswith('import '):
      total_bytes += Walk(
        include_dirs, seen, line.split('"')[1], resolved_filename, indent + 2)
  return total_bytes + len("".join(lines))


def main():
  parser = argparse.ArgumentParser()
  parser.add_argument('-I', action='append', dest='include_dirs')
  parser.add_argument('source_file')
  options = parser.parse_args(sys.argv[1:])
  if not options.include_dirs:
    options.include_dirs = []

  bytes = Walk(options.include_dirs, set(), options.source_file, '', 0)
  print()
  print(float(bytes) / (1 << 20), "megabytes of chrome source")


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