<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Clarkcox.com &#187; Macintosh</title>
	<atom:link href="http://www.clarkcox.com/blog/tag/macintosh/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.clarkcox.com/blog</link>
	<description>Clark’s musings</description>
	<lastBuildDate>Mon, 15 Feb 2010 18:58:34 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>SDKs and Deployment Targets</title>
		<link>http://www.clarkcox.com/blog/2009/06/23/sdks-and-deployment-targets/</link>
		<comments>http://www.clarkcox.com/blog/2009/06/23/sdks-and-deployment-targets/#comments</comments>
		<pubDate>Tue, 23 Jun 2009 20:17:54 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=108</guid>
		<description><![CDATA[Xcode has two build settings that are very important when supporting multiple versions of the OS (whether we’re talking about the Mac or the iPhone, it’s all the same to Xcode) with a single application binary. These settings are SDKROOT (a.k.a Base SDK) and MACOSX_DEPLOYMENT_TARGET[1] (a.k.a. Mac OS X Deployment Target). Base SDK Most people [...]]]></description>
			<content:encoded><![CDATA[<p>Xcode has two build settings that are very important when supporting multiple versions of the OS (whether we’re talking about the Mac or the iPhone, it’s all the same to Xcode) with a single application binary. These settings are <code>SDKROOT</code> (a.k.a <em>Base SDK</em>) and <code>MACOSX_DEPLOYMENT_TARGET</code><sup>[1]</sup> (a.k.a. <em>Mac OS X Deployment Target</em>).</p>
<h4>Base SDK</h4>
<p>Most people are familiar with the Base SDK setting. This setting defines which SDK to build against, and therefore, which APIs are available for your use. If, for instance, you want to build an application that uses an API that was introduced in 10.5, you <em>must</em> have a Base SDK set to <code>macosx10.5</code> or later<sup>[2]</sup>.</p>
<h4>Deployment Target</h4>
<p>Were Base SDK the only setting, you would be limited to three options:</p>
<ol>
<li>Build multiple versions of your application, one fore each OS version that you want to support</li>
<li>Build a single application that uses features from the newer OS, and ignore users of the previous version.</li>
<li>Build a single application that runs on the previous version of the OS, but miss out on the new features of the newer OS.</li>
</ol>
<p>None of those choices seems particularly appealing. Fortunately, that is where the deployment target setting comes in. The deployment target setting, which seems to confuse people a bit, is much more subtle, and is often overlooked. It tells Xcode the version number of the earliest OS you wish to support, and adjusts the linkage of your application to make it possible.</p>
<p>Take the following example:</p>
<ul>
<li>There are two versions of a hypothetical OS: OS 1.0 and OS 2.0</li>
<li>I have an application that I’ve been developing for OS 1.0, but I <em>really</em> want to take advantage of a new, amazing OS 2.0 feature.</li>
<li>I have enough users that still run OS 1.0, and I don&#8217;t want to deprive them of my application.</li>
</ul>
<p>All I need to do to accomplish this is to set my Base SDK to “OS 2.0”, which will allow my application to use the new feature, and set my deployment target to &#8220;1.0&#8243;, which will allow my application to launch on OS 1.0.</p>
<h4>At Runtime</h4>
<p>But there’s a catch: I can <em>launch</em> on 1.0, but if I use a function, class or method that doesn’t exist (like those required to use the new, amazing feature), my application will crash. So, the last thing that I need do is to check, at runtime, for the availability of the particular function (or class, or method, etc.).</p>
<h5>Functions</h5>
<p>For functions, I can accomplish this by comparing the address of the function to NULL:</p>
<p><code>if(APIForAmazingNewFeature != NULL) {<br />
//I can call APIForAmazingNewFeature() here<br />
} else {<br />
//I can't call it here, but I can fallback to doing something sensible<br />
}</code></p>
<h5>Classes</h5>
<p>Since Objective-C is more dynamic than C, I can use higher-level constructs when the feature I&#8217;m testing for is a class:</p>
<p><code>Class myClass = NSClassFromString(@"AmazingNewClass");</p>
<p>if(myClass) {<br />
//I can use “myClass” in place of AmazingNewClass when calling class methods:<br />
AmazingNewClass *instance = [[myClass alloc] init];<br />
…<br />
} else {<br />
//The class doesn’t exist<br />
…<br />
}</code></p>
<h6>Added 11. Feb, 2010:</h6>
<p><ins datetime="2010-02-11T08:25:04+00:00"><br />
<blockquote>If you&#8217;re developing for an OS that supports <a href="http://www.sealiesoftware.com/blog/archive/2009/09/09/objc_explain_Weak-import_classes.html">Weak-import classes</a> (currently only iPhone OS 3.1 and later), dealing with classes that may or may not exist is even easier—you can even subclass such classes (something that isn&#8217;t possible in previous versions of the Mac and iPhone operating systems).</blockquote ></ins></p>
<h5>Methods</h5>
<p>…or a method:<br />
<code>if([someObject respondsToSelector: @selector(methodAddedInVersion2)) {<br />
[someObject methodAddedInVersion2];<br />
} else {<br />
…<br />
}</code></p>
<h4>In Conclusion</h4>
<p>Using these two build settings you can easily build a single binary of your application that supports the latest and the greatest, yet gracefully degrades when running on older OSes. The basic rules of thumb:</p>
<ul>
<li>Set the Base SDK to the lowest value that will still support all of the features that you use</li>
<li>Set the deployment target to the lowest OS version on which you plan to run.</li>
<li>Check, at runtime, for any features that you use that don&#8217;t exist in the version of the OS that matches your deployment target.</li>
</ul>
<ol class="footnotes"><li id="footnote_0_108" class="footnote">or <code>IPHONEOS_DEPLOYMENT_TARGET</code>/<em>iPhone OS Deployment Target</em></li><li id="footnote_1_108" class="footnote">There is one exception to this. If you leave this setting blank, it will build against the host system. So such an application would be properly built if, and only if, you were building it on a Mac running 10.5. Needless to say, it is impossible to build an iPhone application in this manner</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2009/06/23/sdks-and-deployment-targets/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>4-Way Fat Binaries, 10.4 through 10.5</title>
		<link>http://www.clarkcox.com/blog/2009/06/02/4-way-fat-binaries-104-through-105/</link>
		<comments>http://www.clarkcox.com/blog/2009/06/02/4-way-fat-binaries-104-through-105/#comments</comments>
		<pubDate>Wed, 03 Jun 2009 05:26:02 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=102</guid>
		<description><![CDATA[I&#8217;ve seen this question come up several times in the past week: “How do I build a single Cocoa application that runs on both 10.4 and 10.5, and runs 64-bit where possible.” Easy. Copy and paste the following settings into your project or target settings as appropriate: SDKROOT = macosx10.5 MACOSX_DEPLOYMENT_TARGET = 10.5 MACOSX_DEPLOYMENT_TARGET[arch=ppc] = [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve seen this question come up several times in the past week: “How do I build a single Cocoa application that runs on both 10.4 and 10.5, and runs 64-bit where possible.”</p>
<p>Easy. Copy and paste the following settings into your project or target settings as appropriate:<br />
<code><br />
SDKROOT = macosx10.5<br />
MACOSX_DEPLOYMENT_TARGET = 10.5<br />
MACOSX_DEPLOYMENT_TARGET[arch=ppc] = 10.4<br />
MACOSX_DEPLOYMENT_TARGET[arch=i386] = 10.4<br />
</code></p>
<p>That&#8217;s all you need. In plain English, these build settings mean:</p>
<ol>
<li>Use the 10.5 SDK</li>
<li>Set the deployment target to 10.5</li>
<li>…except for ppc </li>
<li>… and i386, both of which use a deployment target of 10.4</li>
</ol>
<p>It’s that simple. The resulting application will run with the “best” architecture, everywhere. The one caveat is that, at least in the 32-bit case, you have to check at runtime if you happen to be using 10.5-only APIs. If you&#8217;re sure that you don&#8217;t need to use any 10.5-only functionality, and can stick to 10.4-only APIs, you can use the following build settings instead:</p>
<p><code><br />
SDKROOT = macosx10.5<br />
SDKROOT[arch=ppc] = macosx10.4<br />
SDKROOT[arch=i386] = macosx10.4<br />
MACOSX_DEPLOYMENT_TARGET = 10.5<br />
MACOSX_DEPLOYMENT_TARGET[arch=ppc] = 10.4<br />
MACOSX_DEPLOYMENT_TARGET[arch=i386] = 10.4<br />
</code></p>
<p>These settings mean the same as the previous snippet, except that the ppc and i386 slices use the 10.4 SDK.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2009/06/02/4-way-fat-binaries-104-through-105/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Inspecting Obj-C parameters in gdb</title>
		<link>http://www.clarkcox.com/blog/2009/02/04/inspecting-obj-c-parameters-in-gdb/</link>
		<comments>http://www.clarkcox.com/blog/2009/02/04/inspecting-obj-c-parameters-in-gdb/#comments</comments>
		<pubDate>Wed, 04 Feb 2009 19:55:55 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[GDB]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=12</guid>
		<description><![CDATA[Since the addition of i386 and x86_64 to the Mac OS&#8217;s repertoire several years back, remembering which registers are used for what has become difficult, and this can complicate the debugging of code for which you have no symbols. So here is my cheat-sheet (posted here, mostly so that I can find it again without [...]]]></description>
			<content:encoded><![CDATA[<p>Since the addition of i386 and x86_64 to the Mac OS&#8217;s repertoire several years back, remembering which registers are used for what has become difficult, and this can complicate the debugging of code for which you have no symbols. So here is my cheat-sheet (posted here, mostly so that I can find it again without google-ing for old mailing list posts; but, I figure someone else may find it useful as well):</p>
<h4>ppc/ppc64</h4>
<ul>
<li><code>$r3</code> ➡ arg0 (self)</li>
<li><code>$r4</code> ➡ arg1 (_cmd)</li>
<li><code>$r5</code> ➡ arg2</li>
<li><code>$r6</code> ➡ arg3</li>
<li><code>$r7</code> ➡ arg4</li>
<li><code>$r8</code> ➡ arg5</li>
</ul>
<h4>i386 (before prolog)</h4>
<ul>
<li><code>*($esp+4n)</code> ➡ arg(n)</li>
<li><code>*($esp)</code> ➡ arg0 (self)</li>
<li><code>*($esp+4)</code> ➡ arg1 (_cmd)</li>
<li><code>*($esp+8)</code> ➡ arg2</li>
<li><code>*($esp+12)</code> ➡ arg3</li>
<li><code>*($esp+16)</code> ➡ arg4</li>
<li><code>*($esp+20)</code> ➡ arg5</li>
</ul>
<h4>i386 (after prolog)</h4>
<ul>
<li><code>*($ebp+8+4n)</code> ➡ arg(n)</li>
<li><code>*($ebp+4)</code> ➡ Return addr</li>
<li><code>*($ebp+8)</code> ➡ arg0 (self)</li>
<li><code>*($ebp+12)</code> ➡ arg1 (_cmd)</li>
<li><code>*($ebp+16)</code> ➡ arg2</li>
<li><code>*($ebp+20)</code> ➡ arg3</li>
<li><code>*($ebp+24)</code> ➡ arg4</li>
<li><code>*($ebp+28)</code> ➡ arg5</li>
<li><code>*($ebp)</code> ➡ Previous $ebp</li>
</ul>
<h4>x86_64</h4>
<ul>
<li><code>$rdi</code> ➡ arg0 (self)</li>
<li><code>$rsi</code> ➡ arg1 (_cmd)</li>
<li><code>$rdx</code> ➡ arg2</li>
<li><code>$rcx</code> ➡ arg3</li>
<li><code>$r8</code> ➡ arg4</li>
<li><code>$r9</code> ➡ arg5</li>
</ul>
<p>So, if you have a method defined as:<br />
<code>-(id)method:(id)foo bar:(id)bar baz:(id)baz</code><br />
you can print each of the parameters with:</p>
<table border="1">
<tbody>
<tr>
<th></th>
<th>ppc/ppc64</th>
<th>x86_64</th>
<th>i386 (before prolog)</th>
<th>i386 (after prolog)</th>
</tr>
<tr>
<th>self</th>
<td><code>po $r3</code></td>
<td><code>po $rdi</code></td>
<td><code>po *(id*)($esp)</code></td>
<td><code>po *(id*)($ebp + 8)</code></td>
</tr>
<tr>
<th>_cmd</th>
<td><code>p (SEL)$r4</code></td>
<td><code>p (SEL)$rsi</code></td>
<td><code>p *(SEL*)($esp + 4)</code></td>
<td><code>p *(SEL*)($ebp + 12)</code></td>
</tr>
<tr>
<th>foo</th>
<td><code>po $r5</code></td>
<td><code>po $rdx</code></td>
<td><code>po *(id*)($esp + 8)</code></td>
<td><code>po *(id*)($ebp + 16)</code></td>
</tr>
<tr>
<th>bar</th>
<td><code>po $r6</code></td>
<td><code>po $rcx</code></td>
<td><code>po *(id*)($esp + 12)</code></td>
<td><code>po *(id*)($ebp + 20)</code></td>
</tr>
<tr>
<th>baz</th>
<td><code>po $r7</code></td>
<td><code>po $r8</code></td>
<td><code>po *(id*)($esp + 16)</code></td>
<td><code>po *(id*)($ebp + 24)</code></td>
</tr>
</tbody>
</table>
<p>As Blake mentioned in his comment, on i386, if you&#8217;re at the beginning of a function or method, before the prolog has executed (i.e. the bit of code responsible for saving registers, adjusting the stack pointer, etc.), then ebp won&#8217;t have been set up for you yet.<br />
So, I&#8217;ve amended the above table.</p>
<p>That complexity is another reason I long for the simplicity of PowerPC asm, not to mention M68k asm; at least x86_64 has made the step towards using registers for parameters where possible.</p>
<p>Edited to add: In case it isn&#8217;t obvious, these particular stack offsets and registers assignments only make sense when dealing with pointer and integer parameters and return values. When structures and floating point values come into the mix, things can get more complicated.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2009/02/04/inspecting-obj-c-parameters-in-gdb/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
