The Blog of Maxim Porges

Posts Tagged ‘Xcode’

  • How to work around problems with Xcode SCM and svn+ssh

    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.

    Xcode un-FUBAR’d
    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.

    2010.02.13 / 2 responses / Category: Uncategorized

  • Adding Headers and External Libraries to Xcode Projects

    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}/apr
    ${SOURCE_ROOT}/svncpp

    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-1.0.2.7.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-1.0.0.0.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.

    2010.02.08 / 8 responses / Category: Uncategorized

  • An Objective-C Tutorial for Enterprise Java Programmers

    As a programmer, the lingua franca for computers and I is mainly Java. And although I have no real work-related purpose for it, I’ve always had a hankering to learn Objective-C and OS X development.

    And so, over the years, I’ve acquired a handful of really nice books on Objective-C and OS X programming that generous relatives have bought for me as gifts from my Amazon wish list, including Aaron Hillegass’s Cocoa Programming for Mac OS X and Beginning Mac OS X Programming from Wiley. But after a handful of evening coding sessions, I’ve never been able to stick with it long enough to learn it, and every time I return to an old project I find that I’ve forgotten most of what I learned and have to start over at the early chapters again.

    Last night, I finally figured out why this is the case when I decided to give OS X development another try. All the books I have dive in and say: “Let’s build a program with a GUI!” And then I’m bouncing around between Xcode and Interface Builder, and I’m doing drag-and-drop UI building, and I’m hooking up selectors to class methods, and it’s totally alien from anything I’ve ever done before.

    The reason this is so alien to me is that I’m an enterprise Java programmer with years of experience writing web and desktop apps through code, with the IDE as a participant rather than the full-blown means. The last time I used a drag-and-drop editor to build a GUI was when I was forced to take a VB6 class in college; even in my programming salad days, I thought that a “program that builds a program” was way too far from the metal. I’ve got a solid foundation in ground-up MVC principles, and I never, ever start building an application GUI-first nor use drag-and-drop GUI builders.

    When building something in Java, what I do is code the core business logic of the app, write unit tests, and then hook the GUI in to it last once I know everything at the core is working perfectly. If I could just apply this pattern to development of an Objective-C project, I knew I would have a chance of actually retaining what I had learned. I know that the way things are done with OS X is to use Interface Builder and hook up the GUI to the classes visually (and that this is one of the things that makes it a rapid development environment), but for me it was just the wrong place to start.

    So, I decided to try building a test-only GUI-less app last night, and I had some success. I’d like to share what I did with other Java developers in case it can help them too. This won’t be a tutorial as much as a post with a bunch of links to other tutorials that helped me accomplish my goal along with notes about using Objective-C and Xcode that were helpful to somebody familiar with Eclipse. If you like, you can download the project that I put together for reference.

    Getting Started

    I’ll assume that if you are reading this, you (a) have a Mac and (b) have installed Xcode. If not, go and do these things now. Go ahead, I’ll wait.

    As I usually advise programmers learning JUnit to build the world’s simplest calculator application, I decided to apply this same principle to what I was doing. So that’s what I’ll be telling you about; riveting, I know…

    Making Xcode Livable

    Having worked in Eclipse so long, I’m used to having code completion on by default, all my editing happening in a single window, strong support for custom code formatting, and many other things that just seem like good plain common sense.

    Xcode in its default state appears to have none of this, and is really frustrating to use when you first dive in if you are familiar with Eclipse. Have no fear, though – these features are mostly there and just need to be turned on. before you do anything with Xcode, I suggest that you open the preference pane and set up the following options. Note that I am using Xcode 3.0 on Leopard so you may see the options under different headings depending on the version you are using.

    General Tab

    • “Layout”: set this to “All-In-One” to prevent tons of new windows from opening whenever you do anything at all.
    • Check “Open counterparts in same editor” to prevent Apple-Option-Up (used to switch between header and implementation files) from causing the files to open in a new window.
    • Check “Automatically open/close attached editor” to cause the in-window editor to be used when you select code files.
    • Check “Automatically clear log” to clear out the log between runs, a la Eclipse.

    Code Sense Tab
    For some reason, code sense is not on by default from what I could see, which just seems plain silly to me. The options for turning it on in this tab are self-explanatory .

    Debugging Tab
    Launching an app in debug mode doesn’t show the debug “perspective” in Xcode by default. I changed the “On Start” option to “Show Console & Debugger” to make this happen, since I am used to switching to debug mode in Eclipse when I launch an app to see what it’s doing. Press Apple-0 in Xcode to switch back to the project “perspective” after running your app.

    SCM
    Setting up a source control repo is totally painless, and Xcode has a built-in SCM browser that’s as nice as anything I’ve used elsewhere. I got it hooked up to my SVN repo running on my old G4 tower in about ten seconds using svn+ssh.

    Unit Testing in Objective-C

    In Java, I always use JUnit and its associated set of libraries (such as JMock). There’s a framework for Objective-C called OCUnit which is basically identical to JUnit in purpose and operation, and an associated mocking framework called OCMock. Apparently OCUnit is such a standard that Apple decided to include it in Xcode 3.x, so unless you are developing in Xcode 2.x or lower you don’t need to download and compile OCUnit yourself.

    To get a basic Xcode project set up with unit testing, I found this tutorial on the ADC site to be the easiest to follow. There are a few gotchas.

    1. If you are using an older version of Xcode 3.x like I am and the ADC site is being retarded and not letting you download a newer non-Snow Leopard version of Xcode, then the panels are not as nicely broken down as the screenshots in the tutorial. It’s very easy to accidentally pick the C++ Unit Test Bundle instead of the Cocoa Unit Test Bundle. If your project compiles fine but you get linking errors during your build, you picked the wrong framework. You’ll also be able to tell this by looking in the Info window for the Unit Tests target (select the target, right click, and select Get Info). Under the Build tab, if the Linking => Other Linker Flags section shows “-framework Carbon -framework SenTestingKit” instead of “-framework Cocoa -framework SenTestingKit”, you selected the wrong thing – you need the Cocoa version for a Cocoa app.
    2. The way that OCUnit works, it links in to your main application as a dependency during building. So, you’ll create a regular GUI app, create a unit testing target with a dependency on this app, and then when you build the unit testing target it fires up a unit test wrapper during the build and exercises your code; the build will simply fail if any tests fail. The nice thing about this is that your test errors appear as build errors in Xcode, which lets you see build error bubbles adjacent to the broken assertions (in other words, no custom OCUnit runner plugin is needed in Xcode like the JUnit plugin is needed in Eclipse). The key takeaway here is that you want to make sure that your Cocoa GUI app fires up in main.m (i.e. the default “return NSApplicationMain(argc, (const char **) argv);” code is present); if not, then the OCUnit hooks can’t work their magic.
    3. Each class implementation file (i.e. .m file) in an Xcode project can be built for one or more targets. You choose the target for your classes as you create them using the “New File…” wizard, but you can verify and/or change your build targets by right-clicking the .m file and selecting “Get Info” and looking in the “targets” tab. Like with JUnit, you don’t want your tests ending up in your main application, so make sure your app code is aimed at the main application target in your project, and your test code is pointed to your unit testing target.

    Besides this, OCUnit is very similar to JUnit with the convention for test method names to begin with “test…”, setUp() and tearDown() methods, and automatic introspection of the unit test class to determine the tests to run. Assertions are implemented as macros (which are kind of like Java’s static imports from what I can see).

    Writing Some Objective-C

    I’m told Objective-C is like SmallTalk, but having never learned SmallTalk I can’t tell you if this is true or not. In any event, it’s a piece of cake to learn for anybody who has a basic understanding of object-oriented development and C/C++. I’ve forgotten a lot of the C/C++ I learned in college, and haven’t refreshed on method overloading or language specifics yet since my primary goal last night was to get a unit testable project up and running, so forgive the basic-ness of the code presented below, but I wanted to share what I wrote so that people familiar with Java and JUnit can get the idea.

    I found a few useful tutorials on the language to get me going, in addition to referring to my books for sample code. Tristan O’Tierney has a nice language overview on his blog.

    Here’s the awful Objective-C code for my calculator app.

    Calculator.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    #import <Cocoa/Cocoa.h>
     
    @interface Calculator : NSObject
    {
     
    }
     
    - (int) addTwoNumbers: (int) first secondNumber:(int) second;
    - (float) addTwoDecimals: (float) first plus:(float) second;
     
    @end

    Calculator.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    
    #import "Calculator.h"
     
    @implementation Calculator
     
    - (int) addTwoNumbers: (int) first secondNumber:(int) second
    {
      return (first + second);
    }
     
    - (float) addTwoDecimals: (float) first plus:(float) second
    {
      return (first + second);
    }
     
    @end

    CalculatorTest.h

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    #import <SenTestingKit/SenTestingKit.h>
    #import "Calculator.h"
     
    @interface CalculatorTest : SenTestCase
    {
      // it's standard in Objective-C to declare class
      // members in the header file; this will be our fixture
      Calculator *calculator;
    }
     
    - (void) testAddTwoNumbers;
    - (void) testAddTwoDecimals;
     
    @end

    CalculatorTest.m

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    #import "CalculatorTest.h"
     
    @implementation CalculatorTest
     
    - (void) setUp
    {
      // I'm using Objective-C 2.0 which has built-in garbage collection
      // so I didn't use [[Calculator alloc] init] or use autorelease pools;
      // not sure if this is the right way to do this yet but I saw it in a
      // tutorial
      calculator = [Calculator new];
    }
     
    - (void) tearDown
    {
      // This resets the fixture reference for each test. Again, this
      // was recommended so I'm just towing the line
      calculator = nil;
    }
     
    - (void) testAddTwoNumbers
    {
      // I wanted to see where log output for tests goes; more on this later
      NSLog(@"Something in my test...");
      int result = [calculator addTwoNumbers:3 secondNumber:6];
     
      // This is how SenTest rolls for assertions... ugh. See my update
      // at the end of this blog post for a way to get JUnit-style
      // assertions with Hamcrest if you prefer them
      STAssertEquals(9, result, @"Expected 9, got %d", result);
    }
     
    - (void) testAddTwoDecimals
    {
      float result = [calculator addTwoDecimals:10.1 plus:1.2];
      STAssertEquals(11.3f, result, @"Expected 11.3, got %f", result);
    }
     
    @end

    Getting Output

    Any output from print statements in your main app code will show up in the console in Xcode, but output in the test classes themselves does not. However, everything you NSLog shows up in the OS X Console, so if you really need to print something in your unit test and see it come out as output, open up the Console application. There is a little lag since Console polls its logs. There might be a way to get the output of the unit test inside Xcode but I couldn’t find it.

    Next Steps

    Now that I have all that working, for my next trick I want to do something else that is familiar to me: talk to a web service. Apple has a few tutorials on their web service APIs as well as their tree-based XML parsing. I haven’t gone through these yet, but they look pretty thorough and have tutorials. They also provide a sample Java web service app (linked to in the web service document) which will echo back whatever is sent to it, so you can use this to test out your Cocoa calls to SOAP.

    I hope you find this useful. I’m looking forward to corrections/tips from anybody who really knows what they are doing with this stuff, so please add them in the comments.

    UPDATE 2010.02.06:The “STAssertEquals”-style syntax for assertions in SenTest is really annoying if you are used to JUnit-style assertXXX()-style assertions. I just found a blog post by the guys at CarbonFive where they describe how to set up Hamcrest matches for Obj-C. Check it out! The source for the Obj-C implementation of the Hamcrest project has an Xcode build that works flawlessly.

    2010.01.23 / 12 responses / Category: Uncategorized