Summer Xcode Tips
June 22nd, 2006It’s summer! The sun is out and the sky is (leans right to peek outside), well, sort of greyish. While the world celebrates the changing seasons, we’re all leaning over our keyboards and squinting into the screen, working on our LCD tans. All this warm weather puts me in the mood for Xcode tips! I’ve been saving up a few “gotta share” revelations. Are these tips no-brainers? Maybe for some of you. But it took me a while to “get it” and I’m hoping some of you will also giggle with glee when you learn out about them.
Hint #1: Double-Click to Open in External Editor
As my projects become more complex, they inevitably become the gathering place for an assortment of file types that support the production of and testing of the final product. Most of these files are source files, and Xcode is good at editing them. But others, such as scripting definitions and carbon resource files, are best left to external editors. Unfortunately, there are a number of file types that Xcode thinks it’s a good editor for, when it really isn’t. Even some source files might be better edited by external applications, depending on the particular goal.
I’ve spent a lot of time right-clicking such files and selecting “Open in Finder” from the contextual menu. This has the desired effect of opening the file in whatever application you’ve specified as the file’s owner via the Finder. That’s not a bad solution, but it’s slightly annoying, and not nearly as streamlined as double-clicking. But when I double-click a typical file that Xcode claims understanding of, it opens in a separate Xcode editor window. Ugh! I wanted to open in the external application!
From the “File Info” window in Xcode, you can tell Xcode what type you want it to consider the file to be. This is handy for things like making it apply Objective-C++ rules to a “.m” file, but the list of file types it’s prepared to acknowledge is really vast. As I set out to convince Xcode to open my file with another app, I thought I surely needed to teach it more specifically what kind of file it is. It’s not a text file, it’s an XML text file. No dice. Xcode “handles” that, too.
The answer to this problem is surprisingly simple, but it requires counter-intuitive (to me) reasoning. Instead of being more specific about the file’s type, you have to be less specific. Among the myriad choices is an item called simply “file.” When a file’s type is “file,” what do you know, it opens up with the Finder when you double-click it.
Note, if Xcode has already “laid claim” to being editor of your file, it probably has an open file reference to it somewhere. It will not give up its role as editor until you close the file. You can do this by choose “Close File [Blah]” from the File menu while the file is focused, or by pressing the shortcut Cmd-Shift-W.
Hint #2: Eliminate Build Configuration Strain
Since Apple announced the transition to Intel, quite frankly the hardest development aspect for me has been keeping all the darned build settings straight. If you are willing to target 10.4 and later, things are pretty straight-forward. But if you live in the real world and need to continue supporting older release of Mac OS X, things get trickier. To support earlier than 10.3.9 and Intel in a single universal binary, you have to use separate compilers at a minimum, and probably separate SDKs as well.
If you’ve had to do this for one or more of your projects, you probably got used to locating, copying and pasting the build settings from one project to another. Yuck! Not only is this prone to error, but it is “stupid work” that takes up a lot of time and energy. Apple’s answer to this problem is the “.xcconfig” file, which allows you to specify a number of baselines build settings outside the scope of a build configuration.
These “.xcconfig” files are simple text files containing variable names and their desired values. For instance, here are the contents of a baseline file I use for “Universal builds that need to run on 10.2”:
ARCHS = ppc i386 SDKROOT_i386 = /Developer/SDKs/MacOSX10.4u.sdk SDKROOT_ppc = /Developer/SDKs/MacOSX10.3.9.sdk GCC_VERSION_i386 = 4.0 GCC_VERSION_ppc = 3.3 MACOSX_DEPLOYMENT_TARGET = 10.2
I call this file “Universal 10.2+” and keep it in a common location accessible to all of my projects. Now when a particular build configuration in any project needs to “inherit” these settings, I use the “based on” feature of Xcode’s build configuration system. You simply drag a reference to the “.xcconfig” file to your project, whereupon it becomes available in the appropriate popup menu:
Notice that in this case I’ve chosen to name the “inheriting” build configuration “Release 10.2+”. There is a method to this madness: by adopting a naming convention for build configurations that match the system requirements, I can easily ensure that libraries from dependent projects get built under the same settings. By using a consistent naming scheme, and pointing all such build configurations at the same “based on” configuration file, I can rest assured that changing the settings in one place will percolate out to all the affected targets.
Also notice that “Architectures” is not even set by the project (it would be bold if it were). The setting of “ppc intel” comes from the configuration file. The project yields responsibility for defining what “Universal” means. So if Apple adds the rumored support for the Z-80 processor, I’ll only have to change the settings in my “.xcconfig” file.
I’ve barely scratched the surfaces of these files’ power. On top of the “based on” notion from Xcode, the files themselves can also explicitly include other files to stack a great deal of common build-setting definition into your process before the project-specified configurations are even reached.
Hint #3: Install a Directory of Changing Supporting Files
Let’s say you’ve written an application with an awesome templating system. You allow your customers to write their own templates and use them as the basis for new documents. To get your users off to a good start, you include a bunch of built-in templates in your app. In fact, your system is so good that there are literally hundreds of built-in templates and you’re adding more in every release.
All you want Xcode to do is put your directory full of “Built-In Templates” into the resulting application’s “Resources” directory. If you’re like me the first thing you think of doing is simply adding the directory of templates to Xcode, and then dragging the resulting folder icon to the “Install Bundle Resource” build phase. After all, that’s what this standard build phase is for, right? Yes. But the standard build phase does something annoying. Instead of copying the directory to the resources folder, it copies each individual file over to the root of the resources directory. This makes for a very cluttered resources directory.
The good news is that a simple “Copy Files” build phase of our own can get the job the proper way. Just add a custom build phase to your target with target directory “Resources”, and copy your folder reference to that. For some reason the built-in resources phase is “smarter” than it perhaps should be.
Note: When you add your directory filled with templates to the Xcode project, make sure to check the box that requests “folder references” be created. This is how you tell Xcode to take the folder as it is at any moment. Instead of adding the contents of the folder to the project as a group, it will dynamically refer to the contents of the folder as they are at any time. Now when you add new templates to the folder, they’re automatically copied into the app’s resource folder when you next build.