Using Clang from SVN in Xcode

In my free time, I work on the Clang open source project, mostly on the static analyzer. This is the backend behind Xcode’s wonderful “Analyze” tool, which catches path-sensitive problems like memory leaks and then shows you the path where the leak happens.

Using custom builds of the analyzer in Xcode has always been fairly easy with the set-xcode-analyzer tool, distributed with packaged builds of the checker or hidden in the tools/scan-build directory in the Clang source repository. But what if you want to use a custom build as your compiler?…say, to play with Automatic Reference Counting (which I’ve discussed). It’s a little bit harder and requires some reverse engineering of the Xcode plug-in format.

NOTE: I was an intern on the Xcode frontend team two years ago, experimenting with the early stages of what became Xcode 4. I swear this post does not in any way take advantage of any internal knowledge of Xcode or the Apple Developer Tools in general, only my usual penchant for reverse-engineeering and the relative transparency of the xcspec plist format, which is shared by Xcode 3 and Xcode 4.

Now, we could hack Xcode’s own LLVM bundle to replace their version of Clang with ours. But I’d rather add my custom build of Clang as an additional compiler, and still have the option to use the possibly-more-stable one that came with Xcode. That means making our own Xcode plug-in.

Warning: the following procedure is completely unsupported by Apple and may break with future Xcode updates. On the other hand, it is unlikely to cause any project corruption, and has almost zero chance of damaging your source files. So, full steam ahead!

Xcode looks for plug-ins in Library/Application Support/Developer/VERSION/Xcode/Plug-ins, where VERSION is the version of Xcode you’re running. Or, you can put Shared to have the plug-ins loaded by any version of Xcode…which is handy if you have Xcode 3.2 alongside Xcode 4.1.

The template you want is Clang 1.0 LLVM.xcplugin, which lives at one of the two following paths, depending on whether you have Xcode 3 or Xcode 4 installed. Use “Go to Location” in the Finder to get there quickly. (We’re going to be deleting most of it, so if you have both you can use either.)

Xcode 3:
/Developer/Library/Xcode/Plug-ins/

Xcode 4:
/Developer/Library/Xcode/PrivatePlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/

Step 1: Copy Clang LLVM 1.0.xcplugin to your own Xcode plug-ins folder and rename it Clang LLVM Trunk.xcplugin. You’ll probably have to create the plug-in folder inside your Library folder, using the expected location above.

It turns out Xcode plug-ins are just bundles. Let’s strip out all the unnecessary information and focus on what’s necessary.

Step 2: Delete everything inside Clang LLVM Trunk.xcplugin except Info.plist and the .xcspec file in the Resources folder.

It’s probably not a good idea for two plug-ins to conflict in registration information.

Step 3: Edit the Info.plist file. At the very least, change the bundle identifier.

Step 4: Rename Clang LLVM 1.0.xcspec to Clang LLVM Trunk.xcspec. I’m not sure if this is necessary, but it seems like a good idea anyway.

Finally, we have to actually register our new compiler. Here I’ll just give you the file:

Step 5: Replace the contents of Clang LLVM Trunk.xcspec with the ASCII plist below. Make sure to put in your own path where it says /PATH/TO/llvm!

(
	{
		Identifier = "com.apple.compilers.llvm.clang.trunk";
		Type = Compiler;
		BasedOn = "com.apple.compilers.llvm.clang.1_0";
		Class = "XCCompilerSpecificationClang";
		Name = "LLVM-Clang from SVN";
		Description = "LLVM/Clang from SVN";
		Vendor = LLVM;
		Version = "2.9";
		ExecPath = "$(CLANG_BIN_DIR)/clang";
		Architectures = (
			i386,
			ppc,
			"x86_64",
		);
		"ExecCPlusPlusLinkerPath" = "$(CLANG_BIN_DIR)/clang++";
		Options = (
			{
				Name = LLVM_DIR;
				Type = Path;
				DefaultValue = "/PATH/TO/llvm";
				Category = Version;
			},
			{
				Name = LLVM_BUILD_TYPE;
				Type = String;
				DefaultValue = "Release+Asserts";
				Category = Version;
			},
			{
				Name = CLANG_BIN_DIR;
				Type = Path;
				DefaultValue = "$(LLVM_DIR)/$(LLVM_BUILD_TYPE)/bin";
				Category = Version;
			},
		);
	},
)

A note on the “Options” there: I’ve set it up so that you can customize both your build type (Release, Release+Asserts, Debug+Asserts, etc.) with LLVM_BUILD_TYPE, and your build path separately with LLVM_DIR. Or you can just override everything with CLANG_BIN_DIR.

That’s all that’s necessary to get it working! Now if you want to try out ARC on your own machine, just add -fobjc-arc to your “Other C Flags”. (Remember that since there is no runtime support, you won’t be able to use ARC’s zeroing weak references.)

If you’re a UI stickler like me, you might want your build settings to show up more nicely. As you might expect, this is accomplished as a localization.

(Optional) Step 6: Create a LLVM-Clang from SVN.strings file in an en.lproj folder for pretty build settings. Note that the name matches the Name we specified inside the xcspec file, rather than the name of the plug-in.

"[Version]-category" = "Version";

"[CLANG_BIN_DIR]-name" = "Clang bin Directory";
"[CLANG_BIN_DIR]-description" = "Defaults to $(LLVM_DIR)/$(LLVM_BUILD_TYPE)/bin";

"[LLVM_DIR]-name" = "LLVM Source Root";

"[LLVM_BUILD_TYPE]-name" = "LLVM Build Type";
"[LLVM_BUILD_TYPE]-description" = "Common values include \"Debug+Asserts\" and \"Release\". The default is \"Release+Asserts\".";

That’s it!


Coda: Since I was able to figure out how to add options for LLVM_BUILD_TYPE, etc., you might wonder why I didn’t add a boolean option for “Use Objective-C ARC”. I actually tried this and got it to work. The trouble was, the option isn’t part of the analyzer’s xcspec, and so the analyzer ignores it even if the compiler doesn’t. And this is even if you’ve set a custom analyzer for Xcode! Moreover, you can’t swap out the analyzer like you can with a compiler, so to make this work you’d have to modify the original analyzer’s specification.

Since this guide did not require modifying any of the files in the Developer folder, I decided that “Other C Flags” was the way to go for now. I’m sure Apple will release ARC-on-Mac soon enough.

blog comments powered by Disqus