15a15d92206f8ef357c49d6993a6ec4a85bde7b8fTed Kremenek#!/usr/bin/python 25a15d92206f8ef357c49d6993a6ec4a85bde7b8fTed Kremenek 35a15d92206f8ef357c49d6993a6ec4a85bde7b8fTed Kremenek# [PR 11661] Note that we hardwire to /usr/bin/python because we 45a15d92206f8ef357c49d6993a6ec4a85bde7b8fTed Kremenek# want to the use the system version of Python on Mac OS X. 55a15d92206f8ef357c49d6993a6ec4a85bde7b8fTed Kremenek# This one has the scripting bridge enabled. 67aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek 77aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekimport os 82775b935fbd68b150d432338f0f316f6fc81674aTed Kremenekimport subprocess 97aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekimport sys 107aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekimport re 117aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekimport tempfile 127aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekimport shutil 137aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekimport stat 14962da0baff023e3dfa5e79908ac033aed5b5311fTed Kremenekfrom AppKit import * 157aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek 167aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekdef FindClangSpecs(path): 172775b935fbd68b150d432338f0f316f6fc81674aTed Kremenek print "(+) Searching for xcspec file in: ", path 187aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek for root, dirs, files in os.walk(path): 197aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek for f in files: 207aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek if f.endswith(".xcspec") and f.startswith("Clang LLVM"): 217aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek yield os.path.join(root, f) 227aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek 237aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekdef ModifySpec(path, pathToChecker): 247aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek t = tempfile.NamedTemporaryFile(delete=False) 257aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek foundAnalyzer = False 267aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek with open(path) as f: 277aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek for line in f: 287aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek if not foundAnalyzer: 297aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek if line.find("Static Analyzer") >= 0: 307aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek foundAnalyzer = True 317aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek else: 327aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek m = re.search('^(\s*ExecPath\s*=\s*")', line) 337aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek if m: 347aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek line = "".join([m.group(0), pathToChecker, '";\n']) 357aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek t.write(line) 367aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek t.close() 378d69937281b790666f48f71ac8ad7821e60baceeTed Kremenek print "(+) processing:", path 38757a9d1f005ffb8a628a247a11a9869cf8f336c0Ted Kremenek try: 39757a9d1f005ffb8a628a247a11a9869cf8f336c0Ted Kremenek shutil.copy(t.name, path) 40757a9d1f005ffb8a628a247a11a9869cf8f336c0Ted Kremenek os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH) 41757a9d1f005ffb8a628a247a11a9869cf8f336c0Ted Kremenek except IOError, why: 428d69937281b790666f48f71ac8ad7821e60baceeTed Kremenek print " (-) Cannot update file:", why, "\n" 43757a9d1f005ffb8a628a247a11a9869cf8f336c0Ted Kremenek except OSError, why: 448d69937281b790666f48f71ac8ad7821e60baceeTed Kremenek print " (-) Cannot update file:", why, "\n" 457aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek os.unlink(t.name) 467aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek 477aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekdef main(): 487aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek from optparse import OptionParser 497aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek parser = OptionParser('usage: %prog [options]') 507aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek parser.set_description(__doc__) 517aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek parser.add_option("--use-checker-build", dest="path", 527aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek help="Use the Clang located at the provided absolute path, e.g. /Users/foo/checker-1") 537aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek parser.add_option("--use-xcode-clang", action="store_const", 547aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek const="$(CLANG)", dest="default", 557aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek help="Use the Clang bundled with Xcode") 567aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek (options, args) = parser.parse_args() 577aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek if options.path is None and options.default is None: 587aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek parser.error("You must specify a version of Clang to use for static analysis. Specify '-h' for details") 597aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek 60962da0baff023e3dfa5e79908ac033aed5b5311fTed Kremenek # determine if Xcode is running 61962da0baff023e3dfa5e79908ac033aed5b5311fTed Kremenek for x in NSWorkspace.sharedWorkspace().runningApplications(): 62962da0baff023e3dfa5e79908ac033aed5b5311fTed Kremenek if x.localizedName().find("Xcode") >= 0: 638d69937281b790666f48f71ac8ad7821e60baceeTed Kremenek print "(-) You must quit Xcode first before modifying its configuration files." 64962da0baff023e3dfa5e79908ac033aed5b5311fTed Kremenek return 65962da0baff023e3dfa5e79908ac033aed5b5311fTed Kremenek 667aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek if options.path: 677aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek # Expand tildes. 687aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek path = os.path.expanduser(options.path) 697aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek if not path.endswith("clang"): 708d69937281b790666f48f71ac8ad7821e60baceeTed Kremenek print "(+) Using Clang bundled with checker build:", path 717aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek path = os.path.join(path, "bin", "clang"); 727aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek else: 738d69937281b790666f48f71ac8ad7821e60baceeTed Kremenek print "(+) Using Clang located at:", path 747aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek else: 758d69937281b790666f48f71ac8ad7821e60baceeTed Kremenek print "(+) Using the Clang bundled with Xcode" 767aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek path = options.default 77962da0baff023e3dfa5e79908ac033aed5b5311fTed Kremenek 78b8971b27817608bd268dda18ff3e0b4e61377cd0Ted Kremenek try: 79b8971b27817608bd268dda18ff3e0b4e61377cd0Ted Kremenek xcode_path = subprocess.check_output(["xcode-select", "-print-path"]) 80b8971b27817608bd268dda18ff3e0b4e61377cd0Ted Kremenek except AttributeError: 81b8971b27817608bd268dda18ff3e0b4e61377cd0Ted Kremenek # Fall back to the default install location when using Python < 2.7.0 82b8971b27817608bd268dda18ff3e0b4e61377cd0Ted Kremenek xcode_path = "/Developer" 832775b935fbd68b150d432338f0f316f6fc81674aTed Kremenek if (re.search("Xcode.app", xcode_path)): 842775b935fbd68b150d432338f0f316f6fc81674aTed Kremenek # Cut off the 'Developer' dir, as the xcspec lies in another part 852775b935fbd68b150d432338f0f316f6fc81674aTed Kremenek # of the Xcode.app subtree. 862775b935fbd68b150d432338f0f316f6fc81674aTed Kremenek xcode_path = os.path.dirname(xcode_path) 872775b935fbd68b150d432338f0f316f6fc81674aTed Kremenek 882775b935fbd68b150d432338f0f316f6fc81674aTed Kremenek for x in FindClangSpecs(xcode_path): 897aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek ModifySpec(x, path) 907aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek 917aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenekif __name__ == '__main__': 927aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek main() 937aaa9535815a9423e2574a524022c8118cc1aa3bTed Kremenek 94