xref: /minix3/external/bsd/llvm/dist/clang/tools/scan-build/set-xcode-analyzer (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1f4a2713aSLionel Sambuc#!/usr/bin/python
2f4a2713aSLionel Sambuc
3f4a2713aSLionel Sambuc# [PR 11661] Note that we hardwire to /usr/bin/python because we
4f4a2713aSLionel Sambuc# want to the use the system version of Python on Mac OS X.
5f4a2713aSLionel Sambuc# This one has the scripting bridge enabled.
6f4a2713aSLionel Sambuc
7f4a2713aSLionel Sambucimport sys
8f4a2713aSLionel Sambucif sys.version_info < (2, 7):
9f4a2713aSLionel Sambuc    print "set-xcode-analyzer requires Python 2.7 or later"
10f4a2713aSLionel Sambuc    sys.exit(1)
11f4a2713aSLionel Sambuc
12f4a2713aSLionel Sambucimport os
13f4a2713aSLionel Sambucimport subprocess
14f4a2713aSLionel Sambucimport re
15f4a2713aSLionel Sambucimport tempfile
16f4a2713aSLionel Sambucimport shutil
17f4a2713aSLionel Sambucimport stat
18f4a2713aSLionel Sambucfrom AppKit import *
19f4a2713aSLionel Sambuc
20f4a2713aSLionel Sambucdef FindClangSpecs(path):
21f4a2713aSLionel Sambuc  print "(+) Searching for xcspec file in: ", path
22f4a2713aSLionel Sambuc  for root, dirs, files in os.walk(path):
23f4a2713aSLionel Sambuc    for f in files:
24f4a2713aSLionel Sambuc      if f.endswith(".xcspec") and f.startswith("Clang LLVM"):
25f4a2713aSLionel Sambuc        yield os.path.join(root, f)
26f4a2713aSLionel Sambuc
27f4a2713aSLionel Sambucdef ModifySpec(path, isBuiltinAnalyzer, pathToChecker):
28f4a2713aSLionel Sambuc  t = tempfile.NamedTemporaryFile(delete=False)
29f4a2713aSLionel Sambuc  foundAnalyzer = False
30f4a2713aSLionel Sambuc  with open(path) as f:
31f4a2713aSLionel Sambuc    if isBuiltinAnalyzer:
32f4a2713aSLionel Sambuc      # First search for CLANG_ANALYZER_EXEC.  Newer
33f4a2713aSLionel Sambuc      # versions of Xcode set EXEC_PATH to be CLANG_ANALYZER_EXEC.
34f4a2713aSLionel Sambuc      with open(path) as f2:
35f4a2713aSLionel Sambuc        for line in f2:
36f4a2713aSLionel Sambuc          if line.find("CLANG_ANALYZER_EXEC") >= 0:
37f4a2713aSLionel Sambuc            pathToChecker = "$(CLANG_ANALYZER_EXEC)"
38f4a2713aSLionel Sambuc            break
39f4a2713aSLionel Sambuc    # Now create a new file.
40f4a2713aSLionel Sambuc    for line in f:
41f4a2713aSLionel Sambuc      if not foundAnalyzer:
42f4a2713aSLionel Sambuc        if line.find("Static Analyzer") >= 0:
43f4a2713aSLionel Sambuc          foundAnalyzer = True
44f4a2713aSLionel Sambuc      else:
45f4a2713aSLionel Sambuc        m = re.search('^(\s*ExecPath\s*=\s*")', line)
46f4a2713aSLionel Sambuc        if m:
47f4a2713aSLionel Sambuc          line = "".join([m.group(0), pathToChecker, '";\n'])
48f4a2713aSLionel Sambuc          # Do not modify further ExecPath's later in the xcspec.
49f4a2713aSLionel Sambuc          foundAnalyzer = False
50f4a2713aSLionel Sambuc      t.write(line)
51f4a2713aSLionel Sambuc  t.close()
52f4a2713aSLionel Sambuc  print "(+) processing:", path
53f4a2713aSLionel Sambuc  try:
54f4a2713aSLionel Sambuc    shutil.copy(t.name, path)
55f4a2713aSLionel Sambuc    os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)
56f4a2713aSLionel Sambuc  except IOError, why:
57f4a2713aSLionel Sambuc    print "    (-) Cannot update file:", why, "\n"
58f4a2713aSLionel Sambuc  except OSError, why:
59f4a2713aSLionel Sambuc    print "    (-) Cannot update file:", why, "\n"
60f4a2713aSLionel Sambuc  os.unlink(t.name)
61f4a2713aSLionel Sambuc
62f4a2713aSLionel Sambucdef main():
63f4a2713aSLionel Sambuc  from optparse import OptionParser
64f4a2713aSLionel Sambuc  parser = OptionParser('usage: %prog [options]')
65f4a2713aSLionel Sambuc  parser.set_description(__doc__)
66f4a2713aSLionel Sambuc  parser.add_option("--use-checker-build", dest="path",
67f4a2713aSLionel Sambuc                    help="Use the Clang located at the provided absolute path, e.g. /Users/foo/checker-1")
68f4a2713aSLionel Sambuc  parser.add_option("--use-xcode-clang", action="store_const",
69f4a2713aSLionel Sambuc                    const="$(CLANG)", dest="default",
70f4a2713aSLionel Sambuc                    help="Use the Clang bundled with Xcode")
71f4a2713aSLionel Sambuc  (options, args) = parser.parse_args()
72f4a2713aSLionel Sambuc  if options.path is None and options.default is None:
73f4a2713aSLionel Sambuc    parser.error("You must specify a version of Clang to use for static analysis.  Specify '-h' for details")
74f4a2713aSLionel Sambuc
75f4a2713aSLionel Sambuc  # determine if Xcode is running
76f4a2713aSLionel Sambuc  for x in NSWorkspace.sharedWorkspace().runningApplications():
77f4a2713aSLionel Sambuc    if x.localizedName().find("Xcode") >= 0:
78f4a2713aSLionel Sambuc      print "(-) You must quit Xcode first before modifying its configuration files."
79f4a2713aSLionel Sambuc      sys.exit(1)
80f4a2713aSLionel Sambuc
81f4a2713aSLionel Sambuc  isBuiltinAnalyzer = False
82f4a2713aSLionel Sambuc  if options.path:
83f4a2713aSLionel Sambuc    # Expand tildes.
84f4a2713aSLionel Sambuc    path = os.path.expanduser(options.path)
85f4a2713aSLionel Sambuc    if not path.endswith("clang"):
86f4a2713aSLionel Sambuc      print "(+) Using Clang bundled with checker build:", path
87f4a2713aSLionel Sambuc      path = os.path.join(path, "bin", "clang");
88f4a2713aSLionel Sambuc    else:
89f4a2713aSLionel Sambuc      print "(+) Using Clang located at:", path
90f4a2713aSLionel Sambuc  else:
91f4a2713aSLionel Sambuc    print "(+) Using the Clang bundled with Xcode"
92f4a2713aSLionel Sambuc    path = options.default
93f4a2713aSLionel Sambuc    isBuiltinAnalyzer = True
94f4a2713aSLionel Sambuc
95f4a2713aSLionel Sambuc  try:
96f4a2713aSLionel Sambuc    xcode_path = subprocess.check_output(["xcode-select", "-print-path"])
97f4a2713aSLionel Sambuc  except AttributeError:
98f4a2713aSLionel Sambuc    # Fall back to the default install location when using Python < 2.7.0
99f4a2713aSLionel Sambuc    xcode_path = "/Developer"
100f4a2713aSLionel Sambuc  if (xcode_path.find(".app/") != -1):
101f4a2713aSLionel Sambuc    # Cut off the 'Developer' dir, as the xcspec lies in another part
102f4a2713aSLionel Sambuc    # of the Xcode.app subtree.
103*0a6a1f1dSLionel Sambuc    xcode_path = xcode_path.rsplit('/Developer', 1)[0]
104f4a2713aSLionel Sambuc
105f4a2713aSLionel Sambuc  foundSpec = False
106f4a2713aSLionel Sambuc  for x in FindClangSpecs(xcode_path):
107f4a2713aSLionel Sambuc    foundSpec = True
108f4a2713aSLionel Sambuc    ModifySpec(x, isBuiltinAnalyzer, path)
109f4a2713aSLionel Sambuc
110f4a2713aSLionel Sambuc  if foundSpec == False:
111f4a2713aSLionel Sambuc      print "(-) No compiler configuration file was found.  Xcode's analyzer has not been updated."
112f4a2713aSLionel Sambuc
113f4a2713aSLionel Sambucif __name__ == '__main__':
114f4a2713aSLionel Sambuc  main()
115