<?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</title>
	<atom:link href="http://www.clarkcox.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.clarkcox.com/blog</link>
	<description>Clark’s musings</description>
	<lastBuildDate>Wed, 21 Sep 2011 18:18:54 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Simple SSH over Back To My Mac</title>
		<link>http://www.clarkcox.com/blog/2010/12/03/simple-ssh-over-back-to-my-mac/</link>
		<comments>http://www.clarkcox.com/blog/2010/12/03/simple-ssh-over-back-to-my-mac/#comments</comments>
		<pubDate>Fri, 03 Dec 2010 21:15:28 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Macintosh]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=180</guid>
		<description><![CDATA[If you use Back To My Mac, and often ssh to your machines, you can save a lot of typing by adding the following to your ~/.ssh/config file[1]: Host *.«account» ProxyCommand /usr/bin/nc -6 "%h".members.mac.com %p From that point on, you can ssh to your machines with: ssh «machine».«account» For instance, I have a machine called [...]]]></description>
			<content:encoded><![CDATA[<p>If you use Back To My Mac, and often ssh to your machines, you can save a lot of typing by adding the following to your ~/.ssh/config file<sup>[<a href="http://www.clarkcox.com/blog/2010/12/03/simple-ssh-over-back-to-my-mac/#footnote_0_180" id="identifier_0_180" class="footnote-link footnote-identifier-link" title="where &laquo;account&raquo; is your MobileMe account name">1</a>]</sup>:</p>
<p><code>Host *.«account»<br />
ProxyCommand /usr/bin/nc -6 "%h".members.mac.com %p<br />
</code></p>
<p>From that point on, you can ssh to your machines with:</p>
<p><code>ssh «machine».«account»</code></p>
<p>For instance, I have a machine called “ccox-imac”, and I can ssh to it with:</p>
<p><code>ssh ccox-imac.clarkcox3</code></p>
<p>And this also works with anything that sits atop of ssh, such as</p>
<ul>
<li>git &#8211; <code>git clone ccox-imac.clarkcox3:/somerepo.git</code></li>
<li>svn &#8211; <code>svn co svn+ssh://ccox-imac.clarkcox3/somesvnrepo</code></li>
<li>bbedit &#8211; <code>bbedit sftp://ccox-imac.clarkcox3//etc/sshd_config</code></li>
</ul>
<ol class="footnotes"><li id="footnote_0_180" class="footnote">where «account» is your MobileMe account name</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2010/12/03/simple-ssh-over-back-to-my-mac/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Woman in Technology</title>
		<link>http://www.clarkcox.com/blog/2010/07/29/woman-in-technology/</link>
		<comments>http://www.clarkcox.com/blog/2010/07/29/woman-in-technology/#comments</comments>
		<pubDate>Thu, 29 Jul 2010 20:34:57 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=173</guid>
		<description><![CDATA[I just got finished reading the blog post Woman in technology, where Nicole Sullivan explains some of the issues she and others have faced in a male-dominated industry. (I&#8217;m posting here because comments are disabled for her post). While I don&#8217;t deny that there are problems of discrimination (some of her examples made my stomach [...]]]></description>
			<content:encoded><![CDATA[<p>I just got finished reading the blog post <a href="http://www.stubbornella.org/content/2010/07/26/woman-in-technology/">Woman in technology</a>, where Nicole Sullivan explains some of the issues she and others have faced in a male-dominated industry. (I&#8217;m posting here because comments are disabled for her post).</p>
<p>While I don&#8217;t deny that there are problems of discrimination (some of her examples made my stomach turn), I do have problems with a few of her proposed solutions:</p>
<blockquote><p> Video games are largely made by and for men. We need to be willing to rethink the genre completely, bust things wide open to make video games appeal more to girls.</p></blockquote>
<p>I think this is backwards (or is, at the very least, a chicken–and–egg problem). People write and design games that they would like to play, so it seems natural that male designers would write games that would appeal to male gamers. Making video games “appeal more to girls” seems condescending to me; that&#8217;s like claiming that we need to make video games “appeal more to black people”.</p>
<blockquote><p> CS education works best for people who already know how to code before they begin. CS teaches the theory behind a practice in which they assume you already have some skill. Women are less likely to already know, because they don’t play video games as much. In addition, code-cowboys among their classmates are likely to judge them harshly for being a beginner. Are psychology majors expected to already know how to psychoanalyze patients before their first semester?</p></blockquote>
<p>No, psychology majors aren&#8217;t expected to already know how to psychoanalyze patients, but they <i>are</i> expected to have some kind of interest in the subject that they are majoring in. If someone wants to major in CS, it&#8217;s perfectly reasonable that they already have some idea what&#8217;s involved, and to even have done some research on their own beforehand.</p>
<blockquote><p> Women are less likely to jump up and say “me! me! me!” They are far more likely to wait to be asked to participate. We don’t need women to be different than they are, we just need to invite them in a way that works.</p></blockquote>
<p>But that devalues the effort of people who put in the work to say, “me! me! me!”. Given two people, of any gender, if one person is willing to work harder than the other to be recognized, don&#8217;t they deserve to be recognized? Someone&#8217;s getting “invited” because they aren&#8217;t willing to put themselves forward to be recognized seems to reward just waiting around to be recognized, instead of making it happen.</p>
<blockquote><p>Hell, I spent 8 years coding CSS before I ever spoke about it to anyone. The first time I spoke at a conference, John Allsopp contacted me to ask if I would do it. I never would have submitted a proposal. You might say that I should have, but I would counter that I shouldn’t need to act like a dude to get respect.</p></blockquote>
<p>I find it a little offensive (and pretty sexist) that submitting a proposal is “acting like a dude”. It is not “acting like a chick” to sit back and undervalue your own work. If you have an idea, you develop it; there is nothing inherently masculine or feminine about that. Relying on the chance that someone else will convince you to do something seems like a bad strategy to me.</p>
<p>The main problem with affirmative action is that, despite all of the best intentions, it reinforces, rather than diminishes, the idea that class-X of people are inherently different and therefore need special treatment. That to me, seems to be more a part of the problem and less a part of the solution.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2010/07/29/woman-in-technology/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Westinghouse TVs are great…</title>
		<link>http://www.clarkcox.com/blog/2009/06/24/westinghouse-tvs-are-great%e2%80%a6/</link>
		<comments>http://www.clarkcox.com/blog/2009/06/24/westinghouse-tvs-are-great%e2%80%a6/#comments</comments>
		<pubDate>Wed, 24 Jun 2009 21:26:15 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[HDMI]]></category>
		<category><![CDATA[PS3]]></category>
		<category><![CDATA[Westinghouse]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=107</guid>
		<description><![CDATA[…as long as you never need any customer service. (feel free to skip this entry, as it has nothing to do with development, and is probably too long and boring for most people out there) I have been largely happy with my 47&#8243;, Westinghouse HDTV, however, for the past six months or so, it has [...]]]></description>
			<content:encoded><![CDATA[<p>…as long as you never need any customer service.</p>
<p><i>(feel free to skip this entry, as it has nothing to do with development, and is probably too long and boring for most people out there)</i></p>
<p> I have been largely happy with my 47&#8243;, Westinghouse HDTV, however, for the past six months or so, it has had issues talking to both of my PS3s (yes, two of them). Frequently, while displaying anything (DVDs, Blu-Rays, PS3 games, PS2 games, PS1 games, anything), the screen will just go blank. At this point, it’s a flip of a coin as to whether or not the picture will come back. The only solution is to unplug the HDMI cable and reattach it.</p>
<p>So, as any relatively geeky person of my generation would do, I went looking on Google. I found several places online where people were complaining about the same issue. One place of note was the Popular Mechanics website:</p>
<p><a href="http://www.popularmechanics.com/blogs/technology_news/4203691.html">http://www.popularmechanics.com/blogs/technology_news/4203691.html</a><br />
<a href="http://www.popularmechanics.com/blogs/technology_news/4212161.html">http://www.popularmechanics.com/blogs/technology_news/4212161.html</a><br />
<a href="http://www.popularmechanics.com/blogs/technology_news/4212233.html">http://www.popularmechanics.com/blogs/technology_news/4212233.html</a></p>
<p>Since, as you can see, those articles are dated as early as 2006, so I thought that there was a good chance that the problem had been fixed. So I go to make sure that I have the latest firmware on all concerned devices. I check for updates on both PS3’s and find that they are up to date, and I search for a way to update the firmware in the TV.</p>
<p>I find that my TV has the “5110_1.1.0 april 13th 2007” firmware installed and that many people on internet forums claim that a version 1.3 of the firmware has fixed their issue. As I don’t really want to download firmware from an untrusted third party (namely some anonymous guy on a technology forum), all I have to do is head to Westinghouse’s site, download the newest firmware, load it onto a USB key and transfer it to my TV, right? <b>wrong</b>, oh so wrong.</p>
<p>I go to Westinghouse’s support site and enter my serial number (which I had to unmount my TV from the wall in order to see in the first place) on <a href="http://westinghousedigital.com/firmware.aspx">http://westinghousedigital.com/firmware.aspx</a>. After which, I am presented with this unhelpful message:<br />
<img class="size-full wp-image-136 aligncenter" title="Firmware_Updates_WTF" src="http://www.clarkcox.com/blog/wp-content/uploads/2009/06/Firmware_Updates_WTF.png" alt="Firmware_Updates_WTF" width="472" height="668" /></p>
<p>Since I was doing this on the weekend, and I am either working or getting ready to go to work during those hours, I didn’t have the option to call the customer support line. So I e-mailed them using their support form:</p>
<blockquote><p>I am seeing some disturbing flickering whenever I use my PS3 with my HDTV. I have searched online, and have found that this seems to be common among users of Westinghouse HDTV’s, and was told that I probably need a firmware update. Currently my television reports its firmware version as 5110_1.1.0 april 13th 2007</p></blockquote>
<p>Three hours later, I received a response. (“Wow,” I thought, “that’s some speedy turnaround.”):</p>
<blockquote><p>Hello Clark Cox,</p>
<p>Thank you for your inquiry.</p>
<p>We apologize for any inconvenience in awaiting our response; we’re happy to assist you in any way we can. You can try updating the firmware for the TV if you are using an HDMI input. Also PS3 has released a firmware update to work with our TV’s.</p>
<p>If you have any further questions, you may contact us through email, or by calling us toll-free at 1-866-287-5555, between 9am and 9pm Eastern Standard Time, Monday through Saturday. One of our technicians will assist you.</p>
<p>-Nick, Westinghouse Digital Support Staff</p></blockquote>
<p>“OK,” I thought, “now I’m getting somewhere; all I need do is ask, and Nick will tell me how to update my TV.”:</p>
<blockquote><p>On Mon, May 4, 2009 at 1:18 PM, Westinghouse Digital Support<br />
&lt;westinghouse@microdyne.com&gt; wrote:</p>
<blockquote><p>Hello Clark Cox,</p>
<p>Thank you for your inquiry.</p></blockquote>
<p>And thank you for your quick response.</p>
<blockquote><p>We apologize for any inconvenience in awaiting our response; we’re happy to assist you in any way we can. You can try updating the firmware for the TV if you are using an HDMI input.</p></blockquote>
<p>How do I do that? When I enter my serial number on &lt;<a href="http://westinghousedigital.com/firmware.aspx">http://westinghousedigital.com/firmware.aspx</a>&gt;, I get the message: “Sorry, those numbers do not match our records. Please call Customer Support for assistance.”</p>
<p>Is there a direct link to a file I could download to a USB key?</p>
<blockquote><p>Also PS3 has released a firmware update to work with our TV’s.</p></blockquote>
<p>I believe that I already have the latest Firmware on my PS3, but I can check when I get home. Do you happen to know which version of their firmware addresses compatibility with your TV’s?</p></blockquote>
<p>Two days later, I hear back from someone (“Meg”, this time):</p>
<blockquote><p>Hello Clark,</p>
<p>Thank you for your inquiry.</p>
<p>We apologize for any inconvenience in awaiting our response; we’re happy to assist you in any way we can. The message you are receiving indicates a firmware update is not currently available on our website for your product. I’m sorry for any confusion regarding that. You may also want to try updating the firmware in the Playstation to help resolve the issue you are experiencing.</p>
<p>If you have any further questions, you may contact us through email, or by calling us toll-free at 1-866-287-5555, between 9am and 9pm Eastern Standard Time, Monday through Saturday. One of our technicians will assist you.</p>
<p>-Meg, Westinghouse Digital Support Staff</p></blockquote>
<p>So, I got passed off to someone else, who didn’t read the e-mail that she was responding to (otherwise she would have known that I already had the latest firmware on my PS3), and told me that there isn’t a firmware update for my TV (So, “Nick” lied to me, and “Meg” is just parroting advice that I’d already followed a week prior to even contacting them in the first place). So, I respond, still attempting to remain civil:</p>
<blockquote><p>On Wed, May 6, 2009 at 10:37 AM, Westinghouse Digital Support<br />
&lt;westinghouse@microdyne.com&gt; wrote:</p>
<blockquote><p>Hello Clark,</p>
<p>Thank you for your inquiry.</p>
<p>We apologize for any inconvenience in awaiting our response; we’re happy to assist you in any way we can. The message you are receiving indicates a firmware update is not currently available on our website for your product.</p></blockquote>
<p>Someone really should fix your website in that case (i.e. it should actually display a message to that effect, instead of the “Sorry, those numbers do not match our records.” message). Additionally, I find it hard to believe that firmware built over two years ago is the latest firmware (especially since I see people posting on message boards about a version 1.3 firmware for the TX-47F430S).</p>
<blockquote><p>I’m sorry for any confusion regarding that. You may also want to try updating the firmware in the Playstation to help resolve the issue you are experiencing.</p></blockquote>
<p>I’ve verified that my PS3 already has the latest firmware (i.e. 2.70). This essentially makes my TV useless for virtually all of my HD content (i.e. my PS3 is my BluRay player). I can connect through component cables, but then I get some pretty obvious ghosting on the screen in high contrast areas (to the point where my not–technically-minded wife said, “Wow, that looks like crap”). What are my options at this point?</p></blockquote>
<p>Two days later, I hear back from “Nick”:</p>
<blockquote><p>Hello Clark Cox,</p>
<p>Thank you for your inquiry.</p>
<p>We apologize for any inconvenience in awaiting our response; we’re happy to assist you in any way we can. If the unit does have a firmware update and is not showing one currently available, it may have been taken down for maintenance. If a firmware is taken down we will post it again as soon as possible. Is this issue happening on any other HDMI sources?</p>
<p>If you have any further questions, you may contact us through email, or by calling us toll-free at 1-866-287-5555, between 9am and 9pm Eastern Standard Time, Monday through Saturday. One of our technicians will assist you.</p>
<p>-Nick, Westinghouse Digital Support Staff</p></blockquote>
<p>And my response:</p>
<blockquote><p>On Thu, May 7, 2009 at 7:49 AM, Westinghouse Digital Support<br />
&lt;westinghouse@microdyne.com&gt; wrote:</p>
<blockquote><p>Hello Clark Cox,</p>
<p>Thank you for your inquiry.</p>
<p>We apologize for any inconvenience in awaiting our response; we’re happy to assist you in any way we can. If the unit does have a firmware update</p></blockquote>
<p>Is there, or is there not a 1.3 firmware for the TX-47F430S? “Yes” or<br />
“no” please.</p>
<blockquote><p>and is not showing one currently available, it may have been taken down for maintenance. If a firmware is taken down we will post it again as soon as possible. Is this issue happening on any other HDMI sources?</p></blockquote>
<p>No, however both of my PS3’s (both at 2.70) exhibit this issue with my<br />
Westinghouse TV, and neither of them exhibit it with my Samsung TV.</p></blockquote>
<p>Then silence. They completely ignore me, and apparently do not want to answer my “Yes” or “No” question. Almost 20 days later, in a fit of frustration, I <a href="http://twitter.com/clarkcox/status/1933265031">tweet</a>:</p>
<blockquote><p>Westinghouse TV’s = pretty good :) Westinghouse customer service = about as bad as it gets :(</p></blockquote>
<p>This gets the attention of <a href="http://twitter.com/WestinghouseTV/status/1938368155">@WestinghouseTV</a>, who asks me to e-mail him/her the details of my issue. So starts the next e-mail chain. I e-mail him/her with a transcript of all communications so far. Then ten days with no response. I e-mail again, and get back a form letter about their “new state of the art Customer Service Call Center”:</p>
<blockquote><p>Dear Valued Westinghouse Customer,</p>
<p>On Monday, June 15th at 7:00 AM Central Time Westinghouse Digital Electronics opened its new state of the art Customer Service Call Center. The new call center is designed to allow us to provide you with the service that you are accustomed to when dealing with the Westinghouse brand.</p>
<p>Over the past couple of weeks we have done our best to address our customer issues as they came up, but we realize that we may have missed connecting with a few of our valued customers along the way. We want to ensure that we have provided service to all of our customers; therefore, we are reaching out to you to ensure your need for service has been addressed. If we have not yet had the chance to work with you, please contact us at our new service center by calling 1-800-701-0680.</p>
<p>Our service center is open from 7:00AM until 7:00 PM Central Time, Monday through Friday. Or feel free to email us at service@westinghousedigital.com at any time. Our goal is to return your email inquiry in 24 – 48 hours.</p>
<p>We would like to thank you for you patience as we transitioned to our new call center and we look forward to providing you excellent service in the future.</p></blockquote>
<p>I e-mail back:</p>
<blockquote><p>On Fri, Jun 19, 2009 at 8:48 AM, service&lt;service@westinghousedigital.com&gt; wrote:</p>
<blockquote><p>On Monday, June 15th at 7:00 AM Central Time Westinghouse Digital Electronics opened its new state of the art Customer Service Call Center. The new call center is designed to allow us to provide you with the service that you are accustomed to when dealing with the Westinghouse brand.</p></blockquote>
<p>I sure hope not. The “service that [I am] accustomed to when dealing with the Westinghouse brand” is being ignored.</p>
<blockquote><p>Over the past couple of weeks we have done our best to address our customer issues as they came up, but we realize that we may have missed connecting with a few of our valued customers along the way.</p></blockquote>
<p>I don’t feel very valued. My question has gone unanswered and my issue unaddressed for months now.</p>
<blockquote><p>We would like to thank you for you patience as we transitioned to our new call center and we look forward to providing you excellent service in the future.</p></blockquote>
<p>I’ll believe it when I see it. Below, you can find all of my<br />
correspondence so far:</p></blockquote>
<p>And, since then? Nothing. While I generally like my TV, I will never be buying another Westinghouse TV again. You can simply not trust that they will stand behind their products.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2009/06/24/westinghouse-tvs-are-great%e2%80%a6/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<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>[<a href="http://www.clarkcox.com/blog/2009/06/23/sdks-and-deployment-targets/#footnote_0_108" id="identifier_0_108" class="footnote-link footnote-identifier-link" title="or IPHONEOS_DEPLOYMENT_TARGET/iPhone OS Deployment Target">1</a>]</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>[<a href="http://www.clarkcox.com/blog/2009/06/23/sdks-and-deployment-targets/#footnote_1_108" id="identifier_1_108" class="footnote-link footnote-identifier-link" title="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">2</a>]</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>16</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>C99&#8242;s VLAs are evil</title>
		<link>http://www.clarkcox.com/blog/2009/04/07/c99s-vlas-are-evil/</link>
		<comments>http://www.clarkcox.com/blog/2009/04/07/c99s-vlas-are-evil/#comments</comments>
		<pubDate>Wed, 08 Apr 2009 04:14:27 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[C99]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=74</guid>
		<description><![CDATA[While, at first glance, the ability to define an array, whose length is determined at runtime from a variable, seems like a good idea. Hey, it’s very clean and easy to understand, and all of the normal array operations work[1]; there is one major flaw—there is no way to deal with errors. Variable Length Arrays, [...]]]></description>
			<content:encoded><![CDATA[<p>While, at first glance, the ability to define an array, whose length is determined at runtime from a variable, seems like a good idea. Hey, it’s very clean and easy to understand, and all of the normal array operations work<sup>[<a href="http://www.clarkcox.com/blog/2009/04/07/c99s-vlas-are-evil/#footnote_0_74" id="identifier_0_74" class="footnote-link footnote-identifier-link" title="Even sizeof works, though that required a distasteful exception to the normal sizeof rules. Before VLAs, sizeof was always evaluated at compile time, and the resulting value was always a compile-time constant. When applied to VLAs, this obviously cannot be.">1</a>]</sup>; there is one major flaw—there is no way to deal with errors.</p>
<p>Variable Length Arrays, in C99 are defined just like any other array, <em>except that the length doesn’t need to be a compile-time constant</em>:</p>
<p><code><br />
void foo(int size) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;int array[size];<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(int i=0; i&lt;size; ++i) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array[i] = i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
}<br />
</code></p>
<p>Calling the above function with any reasonable value will do the obvious thing, the array will be sized appropriately, will contain sequential numbers. <code>sizeof(array)</code> will even return <code>size*sizeof(int)</code>. For the common case, everything works, and everybody is happy. But what happens when a <code>size</code> is too large to fit on the stack? Who knows.<sup>[<a href="http://www.clarkcox.com/blog/2009/04/07/c99s-vlas-are-evil/#footnote_1_74" id="identifier_1_74" class="footnote-link footnote-identifier-link" title="I&rsquo;m not joking. The official term is &ldquo;undefined behavior&rdquo;. In such a case, the C standard doesn&rsquo;t specify anything about what happens.">2</a>]</sup></p>
<p>In the most common implementation of VLAs the compiler literally decrements the stack pointer by <code>size</code> and goes on it’s merry way, without regard to whether or not the stack pointer now points to an invalid address (or worse, a valid address somewhere inside of your program’s heap). If you’re lucky, and the stack pointer points to an invalid address, your program will likely crash. On the other hand, if you’re not so lucky, the seemingly innocuous function above will start trashing things in your program’s memory space; you may not catch it, you may have a strange, untraceable crash hours later, etc.. Needless to say, this can be quite difficult to debug.</p>
<p>The solution is to simply not use this feature of C99. If you&#8217;ve got a higher-level abstraction (such as <code>std::vector</code> in C++, <code>NSData</code> or <code>NSArray</code> in Cocoa) use that. If you really want to stick with pure, standard C, use <code>malloc()</code>/<code>free()</code><sup>[<a href="http://www.clarkcox.com/blog/2009/04/07/c99s-vlas-are-evil/#footnote_2_74" id="identifier_2_74" class="footnote-link footnote-identifier-link" title="Don&amp;#8217;t be tempted to use alloca(), it is not a standard C function, and has exactly the same issue that VLAs do">3</a>]</sup>:</p>
<p><code><br />
void foo(int size) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;int *array = malloc(size * sizeof *array);<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;if(!array) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Error out here<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;for(int i=0; i&lt;size; ++i) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array[i] = i;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;...<br />
&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;free(array);<br />
}<br />
</code></p>
<ol class="footnotes"><li id="footnote_0_74" class="footnote">Even <code>sizeof</code> works, though that required a distasteful exception to the normal <code>sizeof</code> rules. Before VLAs, <code>sizeof</code> was <em>always</em> evaluated at compile time, and the resulting value was <em>always</em> a compile-time constant. When applied to VLAs, this obviously cannot be.</li><li id="footnote_1_74" class="footnote">I’m not joking. The official term is “undefined behavior”. In such a case, the C standard doesn’t specify <em>anything</em> about what happens.</li><li id="footnote_2_74" class="footnote">Don&#8217;t be tempted to use <code>alloca()</code>, it is not a standard C function, and has <em>exactly</em> the same issue that VLAs do</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2009/04/07/c99s-vlas-are-evil/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Link errors when mixing C++ with C/Objective-C</title>
		<link>http://www.clarkcox.com/blog/2009/02/07/link-errors-when-mixing-c-with-cobjective-c/</link>
		<comments>http://www.clarkcox.com/blog/2009/02/07/link-errors-when-mixing-c-with-cobjective-c/#comments</comments>
		<pubDate>Sun, 08 Feb 2009 02:58:08 +0000</pubDate>
		<dc:creator>Clark Cox</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Objective-C]]></category>

		<guid isPermaLink="false">http://www.clarkcox.com/blog/?p=43</guid>
		<description><![CDATA[Twice in the past week, people have asked questions about getting undefined symbol errors when mixing Objective-C and C++. In both cases, this was a result of C++&#8217;s name-mangling. Anytime you want to have a single function that is callable from both C++ and Objective-C (or C, for that matter), you need to disable name [...]]]></description>
			<content:encoded><![CDATA[<p>Twice in the past week, people have asked questions about getting undefined symbol errors when mixing Objective-C and C++. In both cases, this was a result of C++&#8217;s name-mangling. Anytime you want to have a single function that is callable from both C++ and Objective-C (or C, for that matter), you need to disable name mangling for that function.</p>
<h4>Name Mangling</h4>
<p>Normally, in C, the actual symbol name of a function is simply the function&#8217;s name with an underscore prepended; that is, <code>int Foo(int i, float f)</code> becomes simply <code>_Foo</code>. Nice and straightforward.</p>
<p>In C++, on the other hand, the exact same function will be named <code>__Z3fooif</code><sup>[<a href="http://www.clarkcox.com/blog/2009/02/07/link-errors-when-mixing-c-with-cobjective-c/#footnote_0_43" id="identifier_0_43" class="footnote-link footnote-identifier-link" title="Note, the exact encoding can vary from compiler to compiler, but the basic principle remains the same">1</a>]</sup>. At first glance, this seems like unnecessary complication for complication&#8217;s sake, but all becomes clear when you bring function overloading into the picture. Since C++ allows multiple functions with the same name to exist, as long as they accept different parameters, it makes sense that the types of the parameters themselves must somehow be encoded in the symbol name.</p>
<p>This is precisely what <code>__Z3fooif</code> is:</p>
<ul>
<li><code>__Z</code> means “This is a mangled name”.</li>
<li><code>3</code> means “The next part of this name is 3 characters long”.</li>
<li><code>foo</code> is the actual name of the function.</li>
<li><code>if</code> represents the types of the parameters (i.e. “<code><strong>i</strong>nt</code>” and “<code><strong>f</strong>loat</code>”)</li>
</ul>
<p>This allows <code>foo(int,char)</code> to have a different name than <code>foo(int,float)</code> in the binary.</p>
<h4>Now What?</h4>
<p>So, now that we know why C and C++ encode their function names differently, what can we do about it. The designers of C++ foresaw this situation, after all C++ would have had a long row to hoe were it not compatible with C. They added the <code>extern "C"</code> directive to the language.</p>
<p>There are two ways to apply this directive; either to an entire block of code, or to a single function declaration. Each has it&#8217;s advantages and disadvantages:</p>
<ul>
<li><code>extern "C" int foo(int,float);</code>
<p>This disables name mangling on this single function</p>
</li>
<li><code>extern "C" { ... }</code>
<p>This disables name mangling on <em>all</em> functions between the curly braces.</li>
</ul>
<h4>Final Gotcha</h4>
<p>So, we&#8217;re done, right? Not quite. Since C knows nothing of this “<code>extern "C"</code>” business any of the above declarations will fail to compile when passed to a C or Objective-C compiler. They must be conditionally compiled so that only the C++ compiler sees them.</p>
<p>For the single-function version of the declaration, most people define some kind of macro to hide all of this complexity:<br />
<code><br />
#ifdef __cplusplus<br />
#define MY_EXTERN_C extern "C"<br />
#else<br />
#define MY_EXTERN_C extern<br />
#endif<br />
</code></p>
<p>After this is defined, your function declaration becomes:<br />
<code>MY_EXTERN_C int foo(int i, float f);</code></p>
<p>And, for the block style, just wrap the beginning and end of the block with <code>#ifdef __cplusplus</code>, like so:<br />
<code><br />
#ifdef __cplusplus<br />
extern "C" {<br />
#endif</p>
<p>...</p>
<p>#ifdef __cplusplus<br />
}<br />
#endif<br />
</code></p>
<ol class="footnotes"><li id="footnote_0_43" class="footnote">Note, the exact encoding can vary from compiler to compiler, but the basic principle remains the same</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2009/02/07/link-errors-when-mixing-c-with-cobjective-c/feed/</wfw:commentRss>
		<slash:comments>2</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>arm (before prolog)</h4>
<ul>
<li><code>$r0</code> ➡ arg0 (self)</li>
<li><code>$r1</code> ➡ arg1 (_cmd)</li>
<li><code>$r2</code> ➡ arg2</li>
<li><code>$r3</code> ➡ arg3</li>
<li><code>*($sp)</code> ➡ arg4</li>
<li><code>*($sp+4)</code> ➡ arg5</li>
<li><code>*($sp+8)</code> ➡ arg6</li>
</ul>
<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" style="white-space:nowrap;table-layout:fixed" >
<tbody>
<tr>
<th></th>
<th>arm</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&nbsp;$r0</code></td>
<td><code>po&nbsp;$r3</code></td>
<td><code>po&nbsp;$rdi</code></td>
<td><code>po&nbsp;*(id*)($esp)</code></td>
<td><code>po&nbsp;*(id*)($ebp+8)</code></td>
</tr>
<tr>
<th>_cmd</th>
<td><code>p (SEL)$r1</code></td>
<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&nbsp;$r2</code></td>
<td><code>po&nbsp;$r5</code></td>
<td><code>po&nbsp;$rdx</code></td>
<td><code>po&nbsp;*(id*)($esp+8)</code></td>
<td><code>po&nbsp;*(id*)($ebp+16)</code></td>
</tr>
<tr>
<th>bar</th>
<td><code>po&nbsp;$r3</code></td>
<td><code>po&nbsp;$r6</code></td>
<td><code>po&nbsp;$rcx</code></td>
<td><code>po&nbsp;*(id*)($esp+12)</code></td>
<td><code>po&nbsp;*(id*)($ebp+20)</code></td>
</tr>
<tr>
<th>baz</th>
<td><code>po&nbsp;*(id*)($sp)</code></td>
<td><code>po&nbsp;$r7</code></td>
<td><code>po&nbsp;$r8</code></td>
<td><code>po&nbsp;*(id*)($esp+16)</code></td>
<td><code>po&nbsp;*(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>
<p>Edited to add: I&#8217;ve added registers/stack offsets for arm. But note that these are for before the prolog has executed. Arm code seems much looser about what happens in its function prologs, so there really isn&#8217;t a standard layout post-prolog</p>
]]></content:encoded>
			<wfw:commentRss>http://www.clarkcox.com/blog/2009/02/04/inspecting-obj-c-parameters-in-gdb/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
	</channel>
</rss>

