111 lines · plain
1#!/usr/bin/env python2 3# [PR 11661] Note that we hardwire to /usr/bin/python because we4# want to the use the system version of Python on Mac OS X.5# This one has the scripting bridge enabled.6 7import sys8import os9import subprocess10import re11import tempfile12import shutil13import stat14from AppKit import *15 16def FindClangSpecs(path):17 print("(+) Searching for xcspec file in: ", path)18 for root, dirs, files in os.walk(path):19 for f in files:20 if f.endswith(".xcspec") and f.startswith("Clang LLVM"):21 yield os.path.join(root, f)22 23def ModifySpec(path, isBuiltinAnalyzer, pathToChecker):24 t = tempfile.NamedTemporaryFile(delete=False)25 foundAnalyzer = False26 with open(path) as f:27 if isBuiltinAnalyzer:28 # First search for CLANG_ANALYZER_EXEC. Newer29 # versions of Xcode set EXEC_PATH to be CLANG_ANALYZER_EXEC.30 with open(path) as f2:31 for line in f2:32 if line.find("CLANG_ANALYZER_EXEC") >= 0:33 pathToChecker = "$(CLANG_ANALYZER_EXEC)"34 break35 # Now create a new file.36 for line in f:37 if not foundAnalyzer:38 if line.find("Static Analyzer") >= 0:39 foundAnalyzer = True40 else:41 m = re.search(r'^(\s*ExecPath\s*=\s*")', line)42 if m:43 line = "".join([m.group(0), pathToChecker, '";\n'])44 # Do not modify further ExecPath's later in the xcspec.45 foundAnalyzer = False46 t.write(line)47 t.close()48 print("(+) processing:", path)49 try:50 shutil.copy(t.name, path)51 os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH)52 except IOError as why:53 print(" (-) Cannot update file:", why, "\n")54 except OSError as why:55 print(" (-) Cannot update file:", why, "\n")56 os.unlink(t.name)57 58def main():59 from optparse import OptionParser60 parser = OptionParser('usage: %prog [options]')61 parser.set_description(__doc__)62 parser.add_option("--use-checker-build", dest="path",63 help="Use the Clang located at the provided absolute path, e.g. /Users/foo/checker-1")64 parser.add_option("--use-xcode-clang", action="store_const",65 const="$(CLANG)", dest="default",66 help="Use the Clang bundled with Xcode")67 (options, args) = parser.parse_args()68 if options.path is None and options.default is None:69 parser.error("You must specify a version of Clang to use for static analysis. Specify '-h' for details")70 71 # determine if Xcode is running72 for x in NSWorkspace.sharedWorkspace().runningApplications():73 if x.localizedName().find("Xcode") >= 0:74 print("(-) You must quit Xcode first before modifying its configuration files.")75 sys.exit(1)76 77 isBuiltinAnalyzer = False78 if options.path:79 # Expand tildes.80 path = os.path.expanduser(options.path)81 if not path.endswith("clang"):82 print("(+) Using Clang bundled with checker build:", path)83 path = os.path.join(path, "bin", "clang");84 else:85 print("(+) Using Clang located at:", path)86 else:87 print("(+) Using the Clang bundled with Xcode")88 path = options.default89 isBuiltinAnalyzer = True90 91 try:92 xcode_path = subprocess.check_output(["xcode-select", "-print-path"])93 except AttributeError:94 # Fall back to the default install location when using Python < 2.7.095 xcode_path = "/Developer"96 if (xcode_path.find(".app/") != -1):97 # Cut off the 'Developer' dir, as the xcspec lies in another part98 # of the Xcode.app subtree.99 xcode_path = xcode_path.rsplit('/Developer', 1)[0]100 101 foundSpec = False102 for x in FindClangSpecs(xcode_path):103 foundSpec = True104 ModifySpec(x, isBuiltinAnalyzer, path)105 106 if not foundSpec:107 print("(-) No compiler configuration file was found. Xcode's analyzer has not been updated.")108 109if __name__ == '__main__':110 main()111