Hour 24. Xcode CLI Utilities


What You’ll Learn in this Hour:

How to use tools from Xcode from the command line

How to get more information about command-line tools

How to automate the Xcode build process using command-line tools


Xcode is rapidly evolving into a first-class integrated development environment (IDE) for OS X and iOS applications. For many users, it serves its purpose perfectly in that capacity, providing an environment where users can go to develop and test applications. However, some users, and some uses, need to develop and build projects without wrapping the process in the development environment. Some of these uses are purely preferential because some programmers prefer to maintain code using command-line tools such as emacs. Other such uses are entirely practical, such as the collaborative development of cross-platform projects where some developers are not even using Xcode.

Conveniently for either use, Xcode exposes almost all of its GUI IDE functionality to the command line, enabling you to perform the same actions that you can using clicks in the interface by using commands in the Terminal instead. The primary tools you work with to use Xcode functions from the command line are xcode-select, xcodebuild, and xcrun. Several others are also available, including commands for code signing and product signing.


Did You Know?

To use command-line tools, you can launch Terminal.app (located in /Applications/Utilities) on your workstation, or if you’re not at your workstation you can connect to it using an ssh (Secure Shell) program, enabling you to work with your Xcode projects from almost anywhere that you can find a network.


With a little creativity, you can set up a system so that a development team working on a heterogeneous collection of hardware can all submit code changes to a central Xcode build server, which can continuously compile their work, construct Enterprise distribution ad hoc builds of an iOS app based on it, and email out app-download links for your development team, all automatically and without you needing to interact with the Xcode IDE other than for initial configuration.

Using xcode-select

To use the Xcode command-line tools, the first thing you have to do is tell the command-line tools where the Xcode folder is. You configure the location of the Xcode folder using the xcode-select tool with a command such as this:

xcode-select -switch /Applications/Xcode.app


By the Way

Depending on your user and machine configuration, you might need to run xcode-select with administrative privileges. Use sudo xcode-select ... if the command complains that you do not have permission to use it.


If you move your Xcode installation, rerun this command to reflect the new path. If you have multiple versions of Xcode, you can also use xcode-select to switch between them.

To verify that xcode-select is set to the Xcode that you are expecting, run the following:

xcode-select -print-path
/Applications/Developer/Xcode.app/Contents/Developer

Note that the path that this command returns is an expansion of what was actually set. From this, we can also see that I have moved my Xcode installation from the default location.


Did You Know?

If you set your Xcode path as shown here, but when you run the check you do not see the expansion, your system might have the wrong version of xcode-select. So far, this most commonly occurs if a system has OS X 10.7.3 and then Xcode 4.2 is installed. OS X 10.7.3 comes with xcode-select by default, but installing Xcode 4.2 overwrites the system xcode-select. You can fix this by installing the 10.7.3 combo update.



By the Way

You do not really need to install the command-line tools package to use the Xcode command-line tools discussed in this hour. However, if you want to make common UNIX developer tools like the gnu compiler suite readily available systemwide, install the command-line tools package either via the Downloads in the Preferences or via Xcode, Open Developer Tool, More Developer Tools.


The man page for xcode-select is included in Table 24.1.

Table 24.1. xcode-select Man Page

Image

By the Way

For those developers who might be a bit old fashioned and who really appreciate having decent printed documentation that they can read, mark up in the margins, and on which they can highlight examples of successful uses to reference, here you go. This hour reproduces a few relevant man pages so that you don’t have to print them out later and stuff them in here as your own personal (and binder-breaking) addenda.


Using xcodebuild

xcodebuild is the command-line tool that builds targets from Xcode projects and workspaces. It has access to the schemes and build configurations of the project or workspace and to some of the build actions (Build [the default], Clean, Archive, and Test).

xcodebuild for Projects

To build a project, use Terminal.app to run xcodebuild in the directory with your project.xcodeproj file, and if you have multiple projects in the directory, specify which project to build with the -project option:

xcodebuild -project some-project -target target -scheme schemename [build action]

For example, to build and archive our original BeeLine application target from within its directory, I can issue the following commands:

cd /Volumes/Lump/SGFApps
cd BeeLine
xcodebuild -target BeeLine -scheme BeeLine archive

Xcode takes some time and prints a considerable amount of detail to the terminal. All of this same action is taking place behind the scenes when Xcode is running a build in response to a click in the IDE interface. When it is finished, it prints ** Archive Succeeded ** to the terminal and returns you to the command prompt.


Did You Know?

If you do not specify the build action, xcodebuild compiles the target as per the Build for Archive settings, but does not actually construct the archive.



By the Way

The target and the scheme do not need to be the same; they just happen to be in this instance, and many others, because schemes are often autocreated with a name shared with their target.


If I have multiple .xcodeproj files in the same directory, I can identify the one that I want xcodebuild to use by adding the -project option to the xcodebuild invocation:

xcodebuild -project BeeLine.xcodeproj -target BeeLine -scheme BeeLine archive

Both of these commands compile any source required to build the BeeLine target, using the BeeLine scheme, and submit the compiled BeeLine.app product into the Archives section of the Organizer.

If I want to build the project only to check for compile errors, and not build an archive, I can simply omit the archive build action keyword. In that case, BeeLine.app is built but not copied into the Organizer as an archive.


Did You Know?

The documentation says that you can omit the -scheme parameter for project builds and just use the -target parameter, but builds do not seem to work properly in some situations when the scheme is omitted. It is possible that there are other situations where it breaks if it is included. If your builds produce errors rather than successful archives, try removing or adding the parameter for the appropriate scheme.


xcodebuild for Workspaces

To build a workspace, you must first change directories to the directory containing the .xcworkspace file. Then you invoke xcodebuild adding a -workspace option to the xcodebuild invocation and dropping the -project option.

xcodebuild -workspace some-workspace -scheme schemename [-configuration Release|Debug] [-sdk thesdk] [-arch thearch] [build action]

For example:

xcodebuild -workspace BsNees.xcworkspace -scheme iBLine -configuration Release -sdk iphoneos -arch armv7 archive

Xcode will build iBLine, and a bit oddly, if you have not yet told it to Always Allow access to the code-signing keys, it opens a dialog box at the end of the build requesting your permission to access the keychain for code signing. If you do not want to have to deal with clicking the button to allow access, you can either grant default access or compile your app without code signing into an archive for the Organizer and then code-sign the result when you actually export it for distribution.


Did You Know?

Don’t be alarmed if you see a list of errors pop up first, before seeing a successful build at the end. Xcode’s ability to correctly identify implicit dependencies does not seem to work quite properly when using the xcodebuild command, and for the BsNees workspace, it erroneously attempts to build the BetterList framework as a prerequisite for iBLine builds and for the libBetterListLib static library.

Despite these errors on the (irrelevant) target, xcodebuild will eventually get to the correct targets and build them properly. It’s likely that you can avoid the creation of these unnecessary errors by explicitly specifying the dependencies for your target, but that defeats the purpose of the workspace implicit dependency mechanism, so it’s probably better to just live with them.


xcodebuild for Release Builds

If you need to save the build products directly to the file system rather than into the Organizer archives, you can also use xcodebuild for that. To use this option, you use xcodebuild and explicitly specify the build action Build:

xcodebuild -workspace BsNees.xcworkspace -scheme iBLine -configuration Release -sdk iphoneos -arch armv7 build


By the Way

Yes, the Build build action is the default, but for this specific type of invocation, you get different behavior if you omit it, even though it is the default. This is probably yet another Xcode bug.


When xcodebuild returns control to the command line, look at the last line of output. There will be a path to your derived data location ending in appName.app, which is the on-disk location where the output is stored. Keep track of this path; you will need to provide it to other tools for automatic packaging or autodistribution of your product.

Other Uses for xcodebuild

You can also use xcodebuild to display which software development kits (SDKs) are available in the current version of Xcode that has been set with xcode-select.

For example, in the current version of Xcode, we see that both macosx10.6 and macosx10.7 SDKs are available:

xcodebuild -showsdks

Mac OS X SDKs:
        Mac OS X 10.6         -sdk macosx10.6
        Mac OS X 10.7         -sdk macosx10.7

iOS SDKs:
        iOS 5.0               -sdk iphoneos5.0

iOS Simulator SDKs:
        Simulator - iOS 5.0   -sdk iphonesimulator5.0

Upon switching to a different Xcode, we see that macosx10.7 and macosx10.8 SDKs are available:

xcodebuild -showsdks

Mac OS X SDKs:
        Mac OS X 10.7        -sdk macosx10.7
        Mac OS X 10.8        -sdk macosx10.8

iOS SDKs:
        iOS 5.0              -sdk iphoneos5.0

iOS Simulator SDKs:
        Simulator - iOS 5.0  -sdk iphonesimulator5.0

As of this writing, Xcode changes regularly. If you find that you are forgetting which versions of Xcode you have installed, you can use xcodebuild to find out what version of Xcode is the current version.

It turns out that Xcode 4.2.1 is what gave us the first batch of SDKs shown:

xcodebuild -version

Xcode 4.2.1
Build version 4D502

Xcode 4.4. gave us the second batch of SDKs:

xcodebuild -version

Xcode 4.4
Build version 4F90

Table 24.2 provides the man page for xcodebuild.

Table 24.2. xcodebuild Man Page

Image
Image
Image
Image

Using xcrun

You can use xcrun to run or locate other necessary development tools. One of its most important uses is invoking the PackageApplication tool, to create distributable packages from the output of xcodebuild.

Packaging Applications with xcrun

The basic syntax for xcrun is as follows:

xcrun [-sdk thesdk] toolname arguments

For example, to package the iBLine.app output created by the xcodebuild...build command earlier, I can use xcrun like this:

xcrun -sdk iphoneos PackageApplication -v full path to Release-iphoneos dir /iBLine.app -o ~/Desktop/iiBBLine.ipa --sign “iPhone Distribution Cert” --embed full path to mobileprovisioning profile

The full path to Release-iphoneos dir component is taken from the last line of the xcodebuild invocation that built iBLine.app in build mode.

You can find the iPhone Distribution Cert value by using Keychain Access and looking in your Login keychain certificates for a certificate starting with the words iPhone Distribution. The search for this key is slightly smart, and it is sufficient to specify only a portion of the name of the certificate, as long as that portion is unique among all of your certificates. For example, if you have only one distribution certificate, it is sufficient to use Distribution Certificate for your search. In my case, iPhone Distribution is adequately unique.

The full path to mobileprovisioning profile value can be the full path to an Ad Hoc distribution certificate that you downloaded from the Provisioning Portal, if you’ve saved these somewhere convenient on disk. It cannot currently look these up from Xcode’s stored copies of the provisioning profiles.

If you did not save a copy outside of Xcode, you can find Xcode’s stored copy as follows:

1. Open the Xcode Organizer and display the Devices tab.

2. Select Provisioning Profiles under the Library group in the sidebar.

3. Right-click the desired Ad Hoc distribution provisioning profile and choose Reveal Profile in Finder.

4. If you drag and drop the revealed .mobileprovision file into a Terminal window, it places a copy of the path to that file in the Terminal.

Fully filled in with the values that my system produces for iBLine, this command looks like this:

xcrun -sdk iphoneos PackageApplication -v /Users/ray/Library/Developer/Xcode/DerivedData/BsNees- bnbedrkgivgpkjbnjdolvofyhygn/Build/Products/Release-iphoneos/iBLine.app -o ~/Desktop/iiBBLine.ipa --sign “iPhone Distribution” -embed /Users/ray/Library/MobileDevice/Provisioning Profiles/6BC2A945-5A7D-4336-83AE-2D43A33E50F3.mobileprovision

Other Uses for xcrun

You can also use xcrun to locate tools that are stored within Xcode and that you might need to use at the command line. For example, to locate ibtool (the application for validating and compiling Interface Builder documents), you can use xcrun like this:

xcrun -find ibtool

It responds with the following:

/Applications/Xcode.app/Contents/Developer/usr/bin/ibtool

Table 24.3 shows the man page for xcrun.

Table 24.3. xcrun Man Page

Image
Image

Other Xcode Command-Line Tools

Some other Xcode command-line tools that might prove useful include agvtool, ibtool, opendiff, instruments, codesign, and productsign. We do not discuss these commands in depth, but knowing about them will be helpful, and you can always access their documentation through the built-in man pages:

agvtool is the Apple-generic versioning tool. You can use it to manage version numbers, if you have versioning enabled in your project:

To display the current build version, you can use agvtool to query the project version, as follows:

 agvtool what-version

To increment the CFBundleVersion across all your Info.plist files, you can use agvtool like this:

 agvtool next-version -all

Alternatively, if you want to update your CFBundleVersion to a specific value, rather than increment it, you can use agvtool, as follows:

 agvtool new-version -all 2.0

You can also query your marketing version (the CFBundleShortVersionString in your Info.plist file) like this:

 agvtool what-marketing-version

And you can update your marketing version in all of your Info.plist files simultaneously using agvtool like this:

 agvtool new-marketing-version 4.0

Unfortunately, if you need different marketing versions in different Info.plist files, you will need to update these manually.

ibtool compiles, prints, updates and verifies Interface Builder documents. It is commonly used when localizing applications.

opendiff launches FileMerge from the command line to graphically compare or merge files or directories.

instruments reads an Instruments template from the command line.

productbuilder creates a deployable product archive that can be used with the OS X Installer.

codesign and productsign are components needed for working with the Developer ID program. Man pages for these tools might still be in flux as Apple refines the Developer ID program.

codedesign creates and manipulates code signatures.

productsign signs an OS X Installer product archive. It can be used in three different modes:

• Creating a product archive using a distribution file

• Creating a product archive from one or more bundles (or component packages)

• Creating a distribution for one or more component packages

PackageMaker is another utility that is needed for the Developer ID program. It is included in the Auxiliary Tools download from the Developer site. You can open it in the Finder or run open path-to-auxiliary-tools/PackageMaker.app to launch it from the command line.

Bigger and Better Command-Line Uses

While simply managing and building projects from the command line can give you enhanced development flexibility and convenience, a much more sophisticated use of the tools, and one that can take your development efforts to a whole new level, is using these tools to put your projects under the control of a continuous integration server. Using a continuous integration server (CIS) pushes the job of building your application, and even potentially distributing it to your users, into the hands of a continuously running back-end process that can compile, verify, package, and deliver your application, even if your workstation is turned off.

Under this scenario, your entire development team would submit their changes to the project to a centralized CIS server, which would handle the build process, independent of any of their workstations. Xcode, on each of their workstations, would become a front end to developing the code and project, rather than the mechanism of building it and distributing it.

Although you can build a sort of CIS yourself, using the UNIX cron command to periodically execute shell scripts containing the appropriate xcodebuild and xcrun commands, a plethora of quite sophisticated CIS tools already exists. If you are interested in pursuing this option, we recommend that you look into Jenkins (http://jenkins-ci.org/) and TestFlight (http://testflightapp.com/), although many of their competitors are also worthy of your consideration.

Summary

In this hour, you learned how to use the Xcode suite of command-line tools to build targets without having to launch into the Xcode IDE itself. You also learned how to package those built targets into actually distributable versions of your applications.

These capabilities can be immensely useful for several reasons. At the simplest, these command-line tools enable you to check the validity of code changes in your project, regardless of whether you are at the keyboard of your workstation or connected to it from a remote terminal on the other side of the world. At their most sophisticated, they can be used to completely customize your build environment and process to work the way that you want it to.

Q&A

Q. Why should I use xcrun sometool rather than just using the tool directly?

A. Because xcrun knows about your currently selected Xcode version and will always point to the correct tool binary.

Q. Is there some way to make that (horrible) path to the Release build of an app less of a pain to work with?

A. It doesn’t seem like Xcode provides a neat solution at this point, but you can always use other UNIX tools to make your life easier. For example, you could create a Perl script like this:

#!/usr/bin/perl

$apploc = “”;
while($inline=)
{
  if($inline =~m/Validation (.+.app)/) { $apploc = $1; }
}
print $apploc;

Put it somewhere that your shell can find it and make it executable, and then run the xcodebuild like this:

export apploc=’xcodebuild -workspace BsNees.xcworkspace -scheme iBLine -configuration Release -sdk iphoneos -arch armv7 -target iBLine build | xcodebuildparse.pl’

The final directory and appName.app result will now be stored in the shell variable $apploc, which you could use in your xcrun command like this:

xcrun -sdk iphoneos PackageApplication -v $apploc -o ~/Desktop/iBLine.ipa --sign “iPhone Distribution” --embed /Users/ray/Library/MobileDevice/ Provisioning Profiles/6BC2A945-5A7D-4336-83AE-2D43A33E50F3. mobileprovision

Q. I set up a cron job to run my xcodebuild commands. It works for some, but not for others. What’s the problem?

A. The builds for which it is breaking are ones that require access to your key-chain. When you’re working in a terminal, inside a logged-in session directly at your workstation, you have full authentication to your Login keychain. For security reasons, when you log in to the machine remotely, the shell you’re working in, at least with OS X 10.7.3, doesn’t have access to your Login key-chain. If you want to make this work, copy your development/distribution certificates from your Login keychain into one that’s available to a remotely connected shell. The process for doing this is the same as Apple documents for moving your identities around between different machines (see TN2250 at http://developer.apple.com/library/ios/#technotes/tn2250/). You have to identify the correct keychain by adding the command security list-keychains to a cron job and capturing the output to see which keychains are available. They probably include one for named /Library/Keychains/System.keychain, where you could store your credentials if you do not mind them being available to the entire system. If you prefer to keep your credentials more private, you can use the security command in your script to unlock additional key-chains. See the man page for the security command (man security in the terminal) for complete details on accessing keychain resources.

Workshop

Quiz

1. How can you find out which of your installed Xcode versions is being used by the command-line tools?

2. xcodebuild for projects uses the -target parameter to specify what’s going to be built. What controls the build target for xcodebuild for workspaces?

3. How can you learn more about the syntax, typical uses, and other documentation for these (and other) command-line commands?

Answers

1. xcode-select -print-path

2. xcodebuild for workspaces uses the targets specified by the scheme for the provided build action.

3. From the man pages: man commandname at the command line.

Activities

1. Test build your apps using the command-line tools.

2. Write a shell script that invokes both xcodebuild and xcrun to produce a final packaged app.

3. Write the next killer app for the App Store, change the world, and don’t forget to say nice things about us when you’re rich and famous!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.226.150.219