• 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.

    Category: Uncategorized | Tags: