Archive for February, 2010
Gene Marks recently wrote a column for BusinessWeek about the inapplicability of the iPad as a device for business users.
There’s so much wrong with this column that I’m not sure where to start, and I couldn’t fit my response in the comment limit. I’ve posted my response here.
I work in a business that makes heavy use of both Macs and PCs, so I have some perspective on using both in the workplace. It’s seriously hard to believe that somebody who runs an IT consulting firm could come to such conclusions, nor be so resistant to change in an industry composed of nothing else.
Printing issues? Clearly you’ve never set up a printer with OS X. When we hire new employees, they enter the printer’s IP and OS X figures out everything else.
Connection problems? The only time people who visit our office have problems connecting to the wireless is when they are on a Windows laptop. That’s not a slam on Windows, it just faces an impossible challenge as an OS: there’s so many drivers and different types of wireless cards that not all of them work properly with every wireless security protocol. Apple’s hardware and software are built to match and every wireless protocol I’ve ever been challenged with is supported.
Software installation issues? Everything they will ever install on the iPad will come from the App Store… which means software installation is automatic. Worst case, they will have a custom proprietary app they will want to install, and there’s a foolproof method for that, too (using Xcode). Have you ever even used an iPhone? Comparing the software installation process of an iPad with Windows PCs makes no sense at all.
Security problems? I’m not sure how you think the iPad is going to open security holes any worse than any other device that connects corporate devices to the Internet. The iPad will still run a UNIX core which is arguably one of the most secure OS platforms on the planet.
You’re misinformed and clearly missing the point. I can see the iPad being an excellent device for admin assistants to take notes/manage email/schedules while running around the office. It will work great for anybody who shares and annotates documents collaboratively (such as software wireframes, blueprints, contracts, etc.). Remote versions of proprietary apps written specifically for the iPad that can be used by travelling business people are an obvious third use case. And like the iPhone, totally new accessories like credit card readers, point of sale scanners, and all manner of other things are destined to surround it and support new ways of doing business.
I use source control religiously, even for my own stupid projects at home. To this end, I run a SVN server on an old Quicksilver G4 tower that I use as my file server. Now that I am getting proficient enough with Xcode to do some damage, I decided to set up my SVN repo so I can manage my source while I work. Xcode’s SCM support is missing a few features and can thus be characterized as “modest” when compared with similar tools like Subversive in Eclipse, but it’s still a welcome addition to what I have come to regard as a generally-excellent IDE.
I run connectivity with my home SVN server over svn+ssh using transparent authentication. Unfortunately, Xcode doesn’t seem to handle svn+ssh connections the way you might expect them to. Worst of all, if you don’t set things up the way Xcode wants, it half-works, which is really f***ing confusing. Fear not, however – by operating somewhat abnormally, you can get it to work.
The default svn+ssh case
I have a server called zaphod that acts as my SVN host. My SVN repo on zaphod is stored in the path /Users/porgesm/Documents/code/svn-repos. My user account on this machine is porgesm, and my user account on my local machine is mporges. To enable transparent authentication, I have a SSH config file that looks like this.
Host zaphod Hostname zaphod.local Compression yes User porgesm
zaphod.local uses networking magic to find the IP of the machine named zaphod in my network when I am at home. With this config, I can use SVN from the command line as follows. Note that all I need to enter for the server info is “zaphod”, and my ssh config file expands this appropriately to use any and all config settings I have defined for the host aliased zaphod in the config file.
maxbookpro:~ mporges$ svn list svn+ssh://zaphod/Users/porgesm/Documents/code/svn-repos CommonLib/ FacePlant/ HibernateMavenProject/ MavenReleasePlugin/ Pudding/ SampleMavenProject/ SomeAPI/ StrikeTracker2.0/ SvnCpp/ cxf/
This all works beautifully… unless you are in Xcode.
Xcode brings the FUBAR
So in Xcode (v3.1.4 – I don’t have another version to test with), my first (and incorrect) attempt to set up my SVN repo was as follows. Note the grayed-out label at the bottom where it says “Host Offline” – this is a very important detail that I missed at first.
Basically, the configuration pictured will let you browse and modify the repository from the Repositories window without issue, but if you try to compare, commit, update, or anything else from your project, all those options are grayed out in the menus and changed files don’t appear in the “SCM Results” tab of your workspace. This is the “half-works” situation I was talking about, which was confusing as hell.
At first, I thought Xcode was just broken. Since I also run a generic SVN service on zaphod, I tried setting up a repository using svn://zaphod.local as the URL, and it worked fine. So I figured there had to be something about the way I was defining my svn+ssh URL that Xcode doesn’t like, even though that URL works perfectly from the command line.
The solution is to expand the details of your SSH configuration in to the svn+ssh URL that you enter in to Xcode, and to enter your SSH account password for Xcode to use. Stupid, I know, but this is the only solution I could find that works. You would think that Xcode would hand off to the native SVN client the same way that Subclipse does for things like this, but that would be wishful thinking.
Once you enter all your details, you will get an “Authenticated” message at the bottom of the screen, and all the options that you expect to be able to use in Xcode will magically start working as expected.
And now, the caveat
Of course, there is a caveat to this workaround. Using my SSH config file, I can use the alias zaphod to access my server from anywhere on the Internet by changing the server address in my config file from zaphod.local to my dynamic DNS server and configuring the obfuscated SSH port number that I use. This is useful for when I am not at home, since I like to use SSH to log in to zaphod remotely from coffee shops and hotels to tunnel various services that the server runs (such as iTunes sharing, AFP for mounting remote directories, VNC, etc.).
By explicitly specifying the server address in Xcode as in the solution above, I now have to keep the Xcode SCM repository details up to date with my SSH config file. This defeats the purpose of the SSH config file, which is to store all your SSH settings in one place for SSH to find and use. Suckage.
The best solution I can think of for this stupidity is to set up an SSH tunnel on a local port, and configure Xcode to point to that port on localhost. The downside of this is that I can’t use SCM with Xcode at home without having my tunnel lit up; but at least I’ll know that my SSH settings are all maintained in one place instead of scattered around various files.
To set up what I am describing, I would configure my SSH entry for zaphod as follows. The LocalForward entry causes SSH to tunnel port 3690 on my local machine to port 3690 on zaphod.local, which is where the standard SVN service runs. Note that the LocalForward is always set up from the perspective of the SSH host; in this case, my G4 tower in my local network. It’s basically just looping back to itself in the config file shown below.
Host zaphod Hostname servername.dynamic-dns-server-provider.com Port [obfuscated port number] Compression yes User porgesm #svn loopback for Xcode SVN LocalForward 3690 zaphod.local:3690
I can then light up this tunnel with the command ssh zaphod in Terminal; the tunnel stays lit up as long as I have network connectivity and my Terminal session stays open. I would then use the SVN URL svn://localhost:3690 in Xcode to ride the tunnel securely across the Internet and access the SVN service on zaphod as if I was at home, as shown in the picture below. Note that when you go this route, there’s no need to provide authentication details since the SSH tunnel has already authorized me and I haven’t set up my svn:// service to require authentication. If I had set up the svn:// service to require authentication, I could enter my credentials in the fields provided in Xcode.
I filed this as a bug with Apple (#7646524), so hopefully they will fix it in a future release.
I come from the Java world. In the Java world, when you want to add a library to a project you just add a JAR to the classpath and you are good to go. With a little extra work, you can whip up an Ant script with Ivy or a Maven build, and suddenly anybody can download your project and build it and, like magic, that whole library dependency thing is taken care of as your project’s dependent libraries fly in across the wonderful intarwebs and expose their soft nougat innards to the compiler and runtime for linking.
After a week of messing with Xcode and C++ libraries, I’ve come to one conclusion: managing dependencies in platform-dependent environments is a big pain in the ass. I guess that’s the trade-off for blazing speed. But I digress; this post is about adding said libraries to projects in Xcode, not complaining about dependency management.
Before reading this post, please note that I literally have a week of experience with Xcode; I am by no means an expert. However, I didn’t find much material on the web for including external libraries, so I’m sharing what I have gathered so far and seen working for the benefit of other newbies. If you are an experienced Mac/Xcode developer, please correct me on any incorrect statements/assumptions in the comments.
Compiling In External Library Support with Header Files
When it comes to using external libraries in your project, Xcode actually does a fine job in helping you – but the documentation isn’t particularly up-front about how to set this up. If you Get Info on your project, there’s a build setting called Header Search Paths that lets you set search paths for headers, allowing the compiler to find them. Note that you can set separate paths for the Debug and Release builds, so if you want to put the same settings in all your builds, make sure you select All Configurations in the drop-down at the top of the build window before you enter any header paths.
On the project I am working on, I have copied in the source and headers for the SvnCpp library that is part of the RapidSVN project since I don’t want other people that download my project to have to deal with doing this. I put these under the project folder along with the Apache Portable Runtime (apr) and Subversion (svn) headers that SvnCpp depends on using a project structure like this.
/MyProject /apr ...headers for apr... /svn ...headers for svn... /svncpp ...source for svncpp... /svncpp ...headers for svncpp...
Since these directories are nestled under my project root, I can now set the Header Search Paths as follows:
SOURCE_ROOT is a variable that Xcode exposes to its build environment, referencing the root of the project wherever it may be. This is expanded for you at compile time by Xcode under the hood. For a complete list of build variables, check out Apple’s documentation in the Xcode Build Settings Reference.
Note that I have two folders called svncpp with one nested in the other. This is becuase all the source in SvnCpp references header file includes using the statement #include “svncpp/header_file_name.h”. By setting the top-level svncpp folder as a header search path with the recursive option turned on, Xcode uses this path as the root of the search and can reference the relative path to the headers in a way that agrees with these #include statements.
Finally, what about the svn path? Well, the Subversion headers are referenced in the SvnCpp source using statements like #include “svn_client.h”. To get this to work, I simply made a group in the Xcode project containing references to all the headers in the svn directory. I set the Path Type to these header files to Relative to Enclosing Group so the file names appear in the compiler path as just their file names, which matches the expectations in the source code.
Including Libraries for Linking
So, that covers the headers; what about the libraries containing the object code that these headers reference?
As it turns out, the dylibs for SVN and APR are in the Mac SDKs under /Developer/SDKs/MacOSX[version].sdk/usr/lib/, such as libapr-18.104.22.168.dylib. To include these in my project and allow Xcode to find them for linking, I simply located these dylibs on the file system and dragged them in to the Link Binary With Libraries step under my target. Xcode pulls them in to the project automatically under the Path Type Relative to Current SDK, which I like because it means that I should be able to distribute my build and anybody with the Mac SDK on their system should be able to use it. The SDK provides symbolic link abstractions, presumably so that you can link to a general version of a library (such as libsvn_client-1.dylib) instead of a specific version (such as libsvn_client-22.214.171.124.dylib). Honestly, I haven’t had enough experience with OS X development to comment on best practices in this area, but it seems to follow the “wildcard” conventions available in Maven to link to a major version of a library’s API without specifying the exact point release, which lends more flexibility so long as the developers of the library have adhered to a standard for API compatibility within major version numbers.
Anecdotally, the SVN and APR libraries that I have linked to in my SDK are accompanied by matching header files under /Developer/SDKs/MacOSX[version].sdk/usr/include, so it really would have made more sense for me to link to these SDK headers than to copy the header files in to my project. However, I was experimenting with adding headers to my projects, so I wanted to see how to do it the brute-force way first. I don’t think the compiler is going to complain so long as the headers you compile against match the binaries you link against.
Most Popular Yelling
- Scrolling Large Data Sets in Flex Charts (41)
- Configuring Tomcat SSL Client/Server Authentication (28)
- Fixing "Bluetooth audio failed" Error Message on Mac OS X with Sony DR-BT50 Headphones (16)
- How To Become A Software Engineer/Programmer (15)
- Using Axis's wsdl2java in a Maven Build (13)
- Speak and Spell Samples (13)
- An Objective-C Tutorial for Enterprise Java Programmers (12)
- On A Personal Note (10)
- Abandoning ColdFusion? (9)
- Adobe Says: "Thousands of Developers are using CF 8" (9)
Stuff I Like
- October 2011
- August 2011
- April 2011
- March 2011
- January 2011
- December 2010
- August 2010
- July 2010
- June 2010
- May 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- September 2009
- August 2009
- July 2009
- June 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- July 2008
- June 2008
- May 2008
- April 2008
- March 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- January 2007
- December 2006
- August 2006
- July 2006
- June 2006
- April 2006
- February 2006
- December 2005
- November 2005
- October 2005
- August 2005
- July 2005
- June 2005