GData Static Library for Specific API

From my previous posts I mentioned how to deploy GData by using all-in-one static library, and official build procedures. But both methods have their trade-offs:

  • Using all-in-one static library is easy but need to import a big image file.
  • Following official procedures generate small image file but tedious. Also, you need to re-compile hundreds of source file every time  after cleaning your build, which is quite clumsy if you are under active development.

So the question is: How can we generate GData static library for specific API, such that its reasonably small and save some re-compiling time after cleaning the build? Here is how:

  • Download GData Objective-C client and open its project in XCode
  • Select the Build Settings of GDataTouchStaticLib target
  • Add -DGDATA_REQUIRE_SERVICE_INCLUDES=1 in the Debug setting of “Other C Flags”

  • Suppose I want to implement Youtube API only, add -DGDATA_INCLUDE_YOUTUBE_SERVICE=1 in both Debug and Release setting of “Other C Flags”. Just change this entry to other API name (say -DGDATA_INCLUDE_CONTACTS_SERVICE=1) if you want to implement other API. You can see all the API names in GData Srouces folder in the source tree.
  • In Build Phases of the same target, click Add Build Phase at the lower right corner and select Add Run Script. Then paste the following shell script:
# Version 2.0 (updated for Xcode 4, with some fixes)
# Changes:
#    - Works with xcode 4, even when running xcode 3 projects (Workarounds for apple bugs)
#    - Faster / better: only runs lipo once, instead of once per recursion
#    - Added some debugging statemetns that can be switched on/off by changing the DEBUG_THIS_SCRIPT variable to "true"
#    - Fixed some typos
#
# Purpose:
#   Create a static library for iPhone from within XCode
#   Because Apple staff DELIBERATELY broke Xcode to make this impossible from the GUI (Xcode 3.2.3 specifically states this in the Release notes!)
#   ...no, I don't understand why they did this!
#
# Author: Adam Martin - http://twitter.com/redglassesapps
# Based on: original script from Eonil (main changes: Eonil's script WILL NOT WORK in Xcode GUI - it WILL CRASH YOUR COMPUTER)
#
# More info: see this Stack Overflow question: http://stackoverflow.com/questions/3520977/build-fat-static-library-device-simulator-using-xcode-and-sdk-4

#################[ Tests: helps workaround any future bugs in Xcode ]########
#
DEBUG_THIS_SCRIPT="false"

if [ $DEBUG_THIS_SCRIPT = "true" ]
then
echo "########### TESTS #############"
echo "Use the following variables when debugging this script; note that they may change on recursions"
echo "BUILD_DIR = $BUILD_DIR"
echo "BUILD_ROOT = $BUILD_ROOT"
echo "CONFIGURATION_BUILD_DIR = $CONFIGURATION_BUILD_DIR"
echo "BUILT_PRODUCTS_DIR = $BUILT_PRODUCTS_DIR"
echo "CONFIGURATION_TEMP_DIR = $CONFIGURATION_TEMP_DIR"
echo "TARGET_BUILD_DIR = $TARGET_BUILD_DIR"
fi

#####################[ part 1 ]##################
# First, work out the BASESDK version number (NB: Apple ought to report this, but they hide it)
#    (incidental: searching for substrings in sh is a nightmare! Sob)

SDK_VERSION=$(echo ${SDK_NAME} | grep -o '.\{3\}$')

# Next, work out if we're in SIM or DEVICE

if [ ${PLATFORM_NAME} = "iphonesimulator" ]
then
OTHER_SDK_TO_BUILD=iphoneos${SDK_VERSION}
else
OTHER_SDK_TO_BUILD=iphonesimulator${SDK_VERSION}
fi

echo "XCode has selected SDK: ${PLATFORM_NAME} with version: ${SDK_VERSION} (although back-targetting: ${IPHONEOS_DEPLOYMENT_TARGET})"
echo "...therefore, OTHER_SDK_TO_BUILD = ${OTHER_SDK_TO_BUILD}"
#
#####################[ end of part 1 ]##################

#####################[ part 2 ]##################
#
# IF this is the original invocation, invoke WHATEVER other builds are required
#
# Xcode is already building ONE target...
#
# ...but this is a LIBRARY, so Apple is wrong to set it to build just one.
# ...we need to build ALL targets
# ...we MUST NOT re-build the target that is ALREADY being built: Xcode WILL CRASH YOUR COMPUTER if you try this (infinite recursion!)
#
#
# So: build ONLY the missing platforms/configurations.

if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: I am NOT the root invocation, so I'm NOT going to recurse"
else
# CRITICAL:
# Prevent infinite recursion (Xcode sucks)
export ALREADYINVOKED="true"

echo "RECURSION: I am the root ... recursing all missing build targets NOW..."
echo "RECURSION: ...about to invoke: xcodebuild -configuration \"${CONFIGURATION}\" -target \"${TARGET_NAME}\" -sdk \"${OTHER_SDK_TO_BUILD}\" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO"
xcodebuild -configuration "${CONFIGURATION}" -target "${TARGET_NAME}" -sdk "${OTHER_SDK_TO_BUILD}" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"

ACTION="build"

#Merge all platform binaries as a fat binary for each configurations.

# Calculate where the (multiple) built files are coming from:
CURRENTCONFIG_DEVICE_DIR=${SYMROOT}/${CONFIGURATION}-iphoneos
CURRENTCONFIG_SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator

echo "Taking device build from: ${CURRENTCONFIG_DEVICE_DIR}"
echo "Taking simulator build from: ${CURRENTCONFIG_SIMULATOR_DIR}"

CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
echo "...I will output a universal build to: ${CREATING_UNIVERSAL_DIR}"

# ... remove the products of previous runs of this script
#      NB: this directory is ONLY created by this script - it should be safe to delete!

rm -rf "${CREATING_UNIVERSAL_DIR}"
mkdir "${CREATING_UNIVERSAL_DIR}"

#
echo "lipo: for current configuration (${CONFIGURATION}) creating output file: ${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}"
lipo -create -output "${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_DEVICE_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_SIMULATOR_DIR}/${EXECUTABLE_NAME}"

#########
#
# Added: StackOverflow suggestion to also copy "include" files
#    (untested, but should work OK)
#
if [ -d "${CURRENTCONFIG_DEVICE_DIR}/usr/local/include" ]
then
mkdir -p "${CREATING_UNIVERSAL_DIR}/usr/local/include"
# * needs to be outside the double quotes?
cp "${CURRENTCONFIG_DEVICE_DIR}/usr/local/include/"* "${CREATING_UNIVERSAL_DIR}/usr/local/include"
fi
fi
  • Build the project (⌘B), then get the build products by clicking the little arrow in Organizer -> Projects -> Derived Data. There should be 3 directories (iphoneos, simulator, and universal) in your project’s Build/Products directory. Copy out the Headers subdirectory from iphoneos, and libGDataTouchStaticLib.a from the universal directory.

Thats all! You now have your GData static library for specific API. Its reasonably small and easy to use, just like other static library you download elsewhere ~~

Here is how to use your static library:

  • Drag the headers and library image into your project
  • In your target’s Build Phases -> Link Binary With Libraries, add libxml2.dylib
  • In your target’s Build Settings, set /usr/include/libxml2 in “Header Search Paths”

  • Finally, put #import “GData.h” in your source code.

Happy coding🙂

GData Static Library for Specific API

16 thoughts on “GData Static Library for Specific API

  1. Tharun says:

    Hey, I have a question. How can we couple oauth with Gdata. my client is not willing to key in the username and pass inside the app, rather he prefer oAuth. Can you help.

  2. Rick Zaccone says:

    Many thanks for the helpful post. I had just two issues.

    I was sending an object of type id (really an NSDecimalNumber *) the message doubleValue. doubleValue is defined in GData too! I had to cast my object to the correct type so that the compiler could figure out which message to send.

    In GDataServiceGoogleYouTube.h, I got a warning that serviceRootURLString was multiply defined. I commented out the declaration. Then, everything seems to work properly.

  3. GDataHTTPFetcherLogging.m file
    [[self class] headersStringForDictionary:responseHeaders
    alignColons:YES]];
    the aboue line showing this error
    Data argument not used by format string

  4. i followed all steps but when i try to build i get this error: “/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: unknown option character `D’ in: -DGDATA_REQUIRE_SERVICE_INCLUDES=1
    Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -static [-] file […] [-filelist listfile[,dirname]] [-arch_only arch] [-sacLT]
    Usage: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool -dynamic [-] file […] [-filelist listfile[,dirname]] [-arch_only arch] [-o output] [-install_name name] [-compatibility_version #] [-current_version #] [-seg1addr 0x#] [-segs_read_only_addr 0x#] [-segs_read_write_addr 0x#] [-seg_addr_table ] [-seg_addr_table_filename ] [-all_load] [-noall_load]
    Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool failed with exit code 1”

    I’m getting crazy! please help me to sove..i need a fat static lib for my youtube project.🙂

  5. dhaaaa says:

    It generate to the this linker error

    Undefined symbols for architecture i386:
    “_GTMApplicationIdentifier”, referenced from:
    +[GDataServiceBase defaultApplicationIdentifier] in libGDataTouchStaticLib.a(GDataServiceBase.o)
    “_GTMAssertSelectorNilOrImplementedWithArgs”, referenced from:
    -[GDataServiceBase fetchObjectWithURL:objectClass:objectToPost:ETag:httpMethod:delegate:didFinishSelector:completionHandler:retryInvocationValue:ticket:] in libGDataTouchStaticLib.a(GDataServiceBase.o)

  6. Parth says:

    Undefined symbols for architecture i386:
    “_OBJC_CLASS_$_GDataServiceGoogleYouTube”, referenced from:
    objc-class-ref in ViewController.o
    ld: symbol(s) not found for architecture i386
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

    Error after completing above steps, what’s the problem ?

  7. Jhimli says:

    Undefined symbols for architecture i386:
    “_AreEqualOrBothNil”, referenced from:
    -[GDataGeo isEqual:] in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_CLASS_$_GDataEntryBase”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataEntryACL.o)
    _OBJC_CLASS_$_GDataEntryACL in libGDataTouchStaticLib.a(GDataEntryACL.o)
    l_OBJC_$_CATEGORY_GDataEntryBase_$_GDataACLLinks in libGDataTouchStaticLib.a(GDataEntryACL.o)
    “_OBJC_CLASS_$_GDataFeedBase”, referenced from:
    _OBJC_CLASS_$_GDataFeedACL in libGDataTouchStaticLib.a(GDataFeedACL.o)
    “_OBJC_CLASS_$_GDataObject”, referenced from:
    _OBJC_CLASS_$_GDataACLScope in libGDataTouchStaticLib.a(GDataACLScope.o)
    _OBJC_CLASS_$_GDataGeo in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_CLASS_$_GDataMediaCategory in libGDataTouchStaticLib.a(GDataMediaCategory.o)
    _OBJC_CLASS_$_GDataMediaContent in libGDataTouchStaticLib.a(GDataMediaContent.o)
    _OBJC_CLASS_$_GDataMediaCredit in libGDataTouchStaticLib.a(GDataMediaCredit.o)
    _OBJC_CLASS_$_GDataMediaGroup in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_CLASS_$_GDataMediaPlayer in libGDataTouchStaticLib.a(GDataMediaPlayer.o)

    “_OBJC_CLASS_$_GDataServiceGoogle”, referenced from:
    l_OBJC_$_CATEGORY_GDataServiceGoogle_$_GDataServiceACLAdditions in libGDataTouchStaticLib.a(GDataServiceACL.o)
    “_OBJC_CLASS_$_GDataTextConstruct”, referenced from:
    _OBJC_CLASS_$_GDataMediaDescription in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_CLASS_$_GDataMediaTitle in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    “_OBJC_CLASS_$_GDataUtilities”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_CLASS_$_GDataValueConstruct”, referenced from:
    _OBJC_CLASS_$_GDataACLRoleBase in libGDataTouchStaticLib.a(GDataACLRole.o)
    “_OBJC_CLASS_$_GDataValueElementConstruct”, referenced from:
    _OBJC_CLASS_$_GDataGeoRSSFeatureName in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_CLASS_$_GDataGeoRSSRadius in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_CLASS_$_GDataMediaKeywords in libGDataTouchStaticLib.a(GDataMediaKeywords.o)
    “_OBJC_CLASS_$_GDataXMLElement”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_CLASS_$_GDataXMLNode”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_METACLASS_$_GDataEntryBase”, referenced from:
    _OBJC_METACLASS_$_GDataEntryACL in libGDataTouchStaticLib.a(GDataEntryACL.o)
    “_OBJC_METACLASS_$_GDataFeedBase”, referenced from:
    _OBJC_METACLASS_$_GDataFeedACL in libGDataTouchStaticLib.a(GDataFeedACL.o)
    “_OBJC_METACLASS_$_GDataObject”, referenced from:
    _OBJC_METACLASS_$_GDataACLScope in libGDataTouchStaticLib.a(GDataACLScope.o)
    _OBJC_METACLASS_$_GDataGeo in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_METACLASS_$_GDataMediaCategory in libGDataTouchStaticLib.a(GDataMediaCategory.o)
    _OBJC_METACLASS_$_GDataMediaContent in libGDataTouchStaticLib.a(GDataMediaContent.o)
    _OBJC_METACLASS_$_GDataMediaCredit in libGDataTouchStaticLib.a(GDataMediaCredit.o)
    _OBJC_METACLASS_$_GDataMediaGroup in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_METACLASS_$_GDataMediaPlayer in libGDataTouchStaticLib.a(GDataMediaPlayer.o)

    “_OBJC_METACLASS_$_GDataTextConstruct”, referenced from:
    _OBJC_METACLASS_$_GDataMediaDescription in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_METACLASS_$_GDataMediaTitle in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    “_OBJC_METACLASS_$_GDataValueConstruct”, referenced from:
    _OBJC_METACLASS_$_GDataACLRoleBase in libGDataTouchStaticLib.a(GDataACLRole.o)
    “_OBJC_METACLASS_$_GDataValueElementConstruct”, referenced from:
    _OBJC_METACLASS_$_GDataGeoRSSFeatureName in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_METACLASS_$_GDataGeoRSSRadius in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_METACLASS_$_GDataMediaKeywords in libGDataTouchStaticLib.a(GDataMediaKeywords.o)
    ld: symbol(s) not found for architecture i386
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

  8. Jhimli says:

    Undefined symbols for architecture i386:
    “_AreEqualOrBothNil”, referenced from:
    -[GDataGeo isEqual:] in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_CLASS_$_GDataEntryBase”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataEntryACL.o)
    _OBJC_CLASS_$_GDataEntryACL in libGDataTouchStaticLib.a(GDataEntryACL.o)
    l_OBJC_$_CATEGORY_GDataEntryBase_$_GDataACLLinks in libGDataTouchStaticLib.a(GDataEntryACL.o)
    “_OBJC_CLASS_$_GDataFeedBase”, referenced from:
    _OBJC_CLASS_$_GDataFeedACL in libGDataTouchStaticLib.a(GDataFeedACL.o)
    “_OBJC_CLASS_$_GDataObject”, referenced from:
    _OBJC_CLASS_$_GDataACLScope in libGDataTouchStaticLib.a(GDataACLScope.o)
    _OBJC_CLASS_$_GDataGeo in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_CLASS_$_GDataMediaCategory in libGDataTouchStaticLib.a(GDataMediaCategory.o)
    _OBJC_CLASS_$_GDataMediaContent in libGDataTouchStaticLib.a(GDataMediaContent.o)
    _OBJC_CLASS_$_GDataMediaCredit in libGDataTouchStaticLib.a(GDataMediaCredit.o)
    _OBJC_CLASS_$_GDataMediaGroup in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_CLASS_$_GDataMediaPlayer in libGDataTouchStaticLib.a(GDataMediaPlayer.o)

    “_OBJC_CLASS_$_GDataServiceGoogle”, referenced from:
    l_OBJC_$_CATEGORY_GDataServiceGoogle_$_GDataServiceACLAdditions in libGDataTouchStaticLib.a(GDataServiceACL.o)
    “_OBJC_CLASS_$_GDataTextConstruct”, referenced from:
    _OBJC_CLASS_$_GDataMediaDescription in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_CLASS_$_GDataMediaTitle in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    “_OBJC_CLASS_$_GDataUtilities”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_CLASS_$_GDataValueConstruct”, referenced from:
    _OBJC_CLASS_$_GDataACLRoleBase in libGDataTouchStaticLib.a(GDataACLRole.o)
    “_OBJC_CLASS_$_GDataValueElementConstruct”, referenced from:
    _OBJC_CLASS_$_GDataGeoRSSFeatureName in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_CLASS_$_GDataGeoRSSRadius in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_CLASS_$_GDataMediaKeywords in libGDataTouchStaticLib.a(GDataMediaKeywords.o)
    “_OBJC_CLASS_$_GDataXMLElement”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_CLASS_$_GDataXMLNode”, referenced from:
    objc-class-ref in libGDataTouchStaticLib.a(GDataGeo.o)
    “_OBJC_METACLASS_$_GDataEntryBase”, referenced from:
    _OBJC_METACLASS_$_GDataEntryACL in libGDataTouchStaticLib.a(GDataEntryACL.o)
    “_OBJC_METACLASS_$_GDataFeedBase”, referenced from:
    _OBJC_METACLASS_$_GDataFeedACL in libGDataTouchStaticLib.a(GDataFeedACL.o)
    “_OBJC_METACLASS_$_GDataObject”, referenced from:
    _OBJC_METACLASS_$_GDataACLScope in libGDataTouchStaticLib.a(GDataACLScope.o)
    _OBJC_METACLASS_$_GDataGeo in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_METACLASS_$_GDataMediaCategory in libGDataTouchStaticLib.a(GDataMediaCategory.o)
    _OBJC_METACLASS_$_GDataMediaContent in libGDataTouchStaticLib.a(GDataMediaContent.o)
    _OBJC_METACLASS_$_GDataMediaCredit in libGDataTouchStaticLib.a(GDataMediaCredit.o)
    _OBJC_METACLASS_$_GDataMediaGroup in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_METACLASS_$_GDataMediaPlayer in libGDataTouchStaticLib.a(GDataMediaPlayer.o)

    “_OBJC_METACLASS_$_GDataTextConstruct”, referenced from:
    _OBJC_METACLASS_$_GDataMediaDescription in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    _OBJC_METACLASS_$_GDataMediaTitle in libGDataTouchStaticLib.a(GDataMediaGroup.o)
    “_OBJC_METACLASS_$_GDataValueConstruct”, referenced from:
    _OBJC_METACLASS_$_GDataACLRoleBase in libGDataTouchStaticLib.a(GDataACLRole.o)
    “_OBJC_METACLASS_$_GDataValueElementConstruct”, referenced from:
    _OBJC_METACLASS_$_GDataGeoRSSFeatureName in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_METACLASS_$_GDataGeoRSSRadius in libGDataTouchStaticLib.a(GDataGeo.o)
    _OBJC_METACLASS_$_GDataMediaKeywords in libGDataTouchStaticLib.a(GDataMediaKeywords.o)
    ld: symbol(s) not found for architecture i386
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    any solution??????

  9. Paula says:

    I can’t build the project. It says that the scheme ‘GDataUnitTests’ is not configured for Running. What should I do? And, I’m also interested in the answer to Jitendra Deore’s question.🙂 Thanks!

  10. Paula says:

    Update: I was able to build the project using your other post.🙂 Now I’m lost as to how I’m supposed to use it to retrieve my gmail contacts in xcode.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s