1f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch#!/usr/bin/env python
2f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Copyright 2014 The Chromium Authors. All rights reserved.
3f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# Use of this source code is governed by a BSD-style license that can be
4f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch# found in the LICENSE file.
5f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
6f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch"""
7f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen MurdochClang tools on Windows are still a bit busted. The tooling can't handle
8f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochbackslashes in paths, doesn't understand how to read .rsp files, etc. In
9f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochaddition, ninja generates compile commands prefixed with the ninja msvc helper,
10f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochwhich also confuses clang. This script generates a compile DB that should mostly
11f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochwork until clang tooling can be improved upstream.
12f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch"""
13f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
14f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport os
15f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport re
16f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport json
17f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport shlex
18f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport subprocess
19f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochimport sys
20f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
21f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
22f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch_NINJA_MSVC_WRAPPER = re.compile('ninja -t msvc -e .+? -- ')
23f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch_RSP_RE = re.compile(r' (@(.+?\.rsp)) ')
24f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
25f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
26f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef _ProcessEntry(e):
27f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # Strip off the ninja -t msvc wrapper.
28f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  e['command'] = _NINJA_MSVC_WRAPPER.sub('', e['command'])
29f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
30f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # Prepend --driver-mode=cl to the command's arguments.
31f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # Escape backslashes so shlex doesn't try to interpret them.
32f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  escaped_command = e['command'].replace('\\', '\\\\')
33f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  split_command = shlex.split(escaped_command)
34f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  e['command'] = ' '.join(
35f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      split_command[:1] + ['--driver-mode=cl'] + split_command[1:])
36f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
37f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # Expand the contents of the response file, if any.
38f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # http://llvm.org/bugs/show_bug.cgi?id=21634
39f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  try:
40f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    match = _RSP_RE.search(e['command'])
41f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    rsp_path = os.path.join(e['directory'], match.group(2))
42f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    rsp_contents = file(rsp_path).read()
43f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    e['command'] = ''.join([
44f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        e['command'][:match.start(1)],
45f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        rsp_contents,
46f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch        e['command'][match.end(1):]])
47f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  except IOError:
48f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch    pass
49f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
50f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # TODO(dcheng): This should be implemented in Clang tooling.
51f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # http://llvm.org/bugs/show_bug.cgi?id=19687
52f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # Finally, use slashes instead of backslashes to avoid bad escaping by the
53f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # tooling. This should really only matter for command, but we do it for all
54f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # keys for consistency.
55f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  e['directory'] = e['directory'].replace('\\', '/')
56f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  e['command'] = e['command'].replace('\\', '/')
57f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  e['file'] = e['file'].replace('\\', '/')
58f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
59f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  return e
60f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
61f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
62f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochdef main(argv):
63f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # First, generate the compile database.
64f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  print 'Generating compile DB with ninja...'
65f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  compile_db_as_json = subprocess.check_output(shlex.split(
66f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      'ninja -C out/Debug -t compdb cc cxx objc objcxx'))
67f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
68f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  compile_db = json.loads(compile_db_as_json)
69f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  print 'Read in %d entries from the compile db' % len(compile_db)
70f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  compile_db = [_ProcessEntry(e) for e in compile_db]
71f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  original_length = len(compile_db)
72f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
73f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  # Filter out NaCl stuff. The clang tooling chokes on them.
74f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  compile_db = [e for e in compile_db if '_nacl.cc.pdb' not in e['command']
75f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      and '_nacl_win64.cc.pdb' not in e['command']]
76f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  print 'Filtered out %d entries...' % (original_length - len(compile_db))
77f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  f = file('out/Debug/compile_commands.json', 'w')
78f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  f.write(json.dumps(compile_db, indent=2))
79f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  print 'Done!'
80f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
81f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch
82f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdochif __name__ == '__main__':
83f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch  sys.exit(main(sys.argv[1:]))
84