• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# Copyright 2016 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import json
7import os
8import re
9import shlex
10import sys
11import subprocess
12
13
14_RSP_RE = re.compile(r' (@(.+?\.rsp)) ')
15_debugging = False
16
17
18def _ProcessEntry(entry):
19  """Transforms one entry in the compile database to be clang-tool friendly."""
20  split_command = shlex.split(entry['command'], posix=(sys.platform != 'win32'))
21
22  # Drop gomacc.exe from the front, if present.
23  if split_command[0].endswith('gomacc.exe'):
24    split_command = split_command[1:]
25  # Insert --driver-mode=cl as the first argument.
26  split_command = split_command[:1] + ['--driver-mode=cl'] + split_command[1:]
27  entry['command'] = subprocess.list2cmdline(split_command)
28
29  # Expand the contents of the response file, if any.
30  # http://llvm.org/bugs/show_bug.cgi?id=21634
31  try:
32    match = _RSP_RE.search(entry['command'])
33    if match:
34      rsp_path = os.path.join(entry['directory'], match.group(2))
35      rsp_contents = file(rsp_path).read()
36      entry['command'] = ''.join([
37          entry['command'][:match.start(1)],
38          rsp_contents,
39          entry['command'][match.end(1):]])
40  except IOError:
41    if _debugging:
42      print 'Couldn\'t read response file for %s' % entry['file']
43
44  return entry
45
46
47def ProcessCompileDatabaseIfNeeded(compile_db):
48  """Make the compile db generated by ninja on Windows more clang-tool friendly.
49
50  Args:
51    compile_db: The compile database parsed as a Python dictionary.
52
53  Returns:
54    A postprocessed compile db that clang tooling can use.
55  """
56  # TODO(dcheng): Ideally this would check target_os... but not sure there's an
57  # easy way to do that, and (for now) cross-compiles don't work without custom
58  # patches anyway.
59  if sys.platform != 'win32':
60    return compile_db
61
62  if _debugging > 0:
63    print 'Read in %d entries from the compile db' % len(compile_db)
64  compile_db = [_ProcessEntry(e) for e in compile_db]
65  original_length = len(compile_db)
66
67  # Filter out NaCl stuff. The clang tooling chokes on them.
68  # TODO(dcheng): This doesn't appear to do anything anymore, remove?
69  compile_db = [e for e in compile_db if '_nacl.cc.pdb' not in e['command']
70      and '_nacl_win64.cc.pdb' not in e['command']]
71  if _debugging > 0:
72    print 'Filtered out %d entries...' % (original_length - len(compile_db))
73
74  # TODO(dcheng): Also filter out multiple commands for the same file. Not sure
75  # how that happens, but apparently it's an issue on Windows.
76  return compile_db
77
78
79def GetNinjaPath():
80  ninja_executable = 'ninja.exe' if sys.platform == 'win32' else 'ninja'
81  return os.path.join(
82      os.path.dirname(os.path.realpath(__file__)),
83        '..', '..', '..', '..', 'third_party', 'depot_tools', ninja_executable)
84
85
86# FIXME: This really should be a build target, rather than generated at runtime.
87def GenerateWithNinja(path, targets=[]):
88  """Generates a compile database using ninja.
89
90  Args:
91    path: The build directory to generate a compile database for.
92    targets: Additional targets to pass to ninja.
93
94  Returns:
95    List of the contents of the compile database.
96  """
97  # TODO(dcheng): Ensure that clang is enabled somehow.
98
99  # First, generate the compile database.
100  json_compile_db = subprocess.check_output(
101      [GetNinjaPath(), '-C', path] + targets +
102      ['-t', 'compdb', 'cc', 'cxx', 'objc', 'objcxx'])
103  return json.loads(json_compile_db)
104
105
106def Read(path):
107  """Reads a compile database into memory.
108
109  Args:
110    path: Directory that contains the compile database.
111  """
112  with open(os.path.join(path, 'compile_commands.json'), 'rb') as db:
113    return json.load(db)
114