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