Debugging Qt with Xcode 3.0

Posted on May 30th, 2008 | by yan |

qt Xcode

As a user of Xcode and Trolltech’s Qt framework I recently discovered that data formatting for Qt’s string type QString no longer works in Xcode 3.0. This is something that used to work in the Xcode 2.4 and 2.5 releases, but with Xcode 3.0 I am unable to view the full contents of QStrings during debugging. At best, using simple data formatting methods, I am able to configure Xcode to display the the first character of a QString, but no other characters are displayed in the string. This makes the experience of debugging Qt code quite painful and reduces productivity.

There is a solution however. Xcode provides and exposes an interface for data formatting plug-ins, which Apple uses as well. Specifically, Apple has a similar plug-in for the Carbon data types which include: AEDesc, AEDataStorage, EventRecord, UTCDateTime and many more. By means of this functionality, I was able to cook up a plug-in that simplifies my life of debugging Qt source code with Xcode 3.0.

The plug-in is a Mach-O bundle that contains the code to interpret information about a particular object. In this case we’re extracting the character buffer contents of the QString. The contents look something like this:

#include "DataFormatterPlugin.h"
#include <QtCore>

_pbxgdb_plugin_function_list *_pbxgdb_plugin_functions;
static char *notSetString = "QtDataFormatter plugin error: _pbxgdb_plugin_functions not set!";

char * GetCharArrayFromQString(QString &inString, int identifier)
{
   const char *src = inString.toAscii();
   if (!src)
      return 0;

   char *dest;
   if (_pbxgdb_plugin_functions)
   {
      int bufLen = strlen(src) + 1;
      dest = (char *)(_pbxgdb_plugin_functions->allocate(identifier, bufLen));
      dest[0] = 0;
      strcpy(dest, src);
   }
   else
   {
      dest = notSetString;
   }
   return dest;
}

There also exists a plist file that maps the QString type to this function call during debugging. This file exists inside the plug-in bundle and is named CustomDataViews.plist.

The plug-in bundle needs to be copied to the Xcode plug-ins destination located in /Developer/Library/Xcode/CustomDataViews for a default installation. Once the plug-in is loaded, one can view the contents of a QString while debugging. See Figure 1.

figure 1

Figure 1

Double clicking on the Summary field of any QString will display the means by which Xcode determines the Summary for that variable. See Figure 2.

figure 2

Figure 2

That's pretty much it!

The same thing could be accomplished for any other Qt types if one wants to see the contents of a particular object during debugging. This does not just apply to Qt and can be extended to other frameworks as well.

Below you will find the binary and source tarballs for this plug-in.

qtdataformatters_bin.tar.gz Binary Package
qtdataformatters_src.tar.gz Source Package

  1. 9 Responses to “Debugging Qt with Xcode 3.0”

  2. By Stefan on Jun 16, 2008 | Reply

    Thanks for this contribution, but I don’t see the content of the QString in my debugger. I always see the function “{(char *)GetCharArrayFromQString(&$VAR, $ID)}:s” that’s all.. Did I missed something?

  3. By yan on Jun 16, 2008 | Reply

    Sometimes Xcode 3.0 requires a restart in order for the plug-in to be loaded properly. In addition, make sure you placed the binary plug-in bundle inside /Developer/Library/Xcode/CustomDataViews if you installed Xcode into /Developer (the default Xcode installation location). If your Xcode is not installed in the default location, place the plug-in bundle into $XCODE_INSTALL_ROOT/Library/Xcode/CustomDataViews

    Hope this helps.

  4. By lukassen on Jun 18, 2008 | Reply

    Hi,
    i’ve build your bundle against Qt4.4 with Xcode 3.0 but it complains about nil assertions in the dictionary. and eventually cores

    any thoughts

    regards

    Chris

    18/06/08 16:18:02 Xcode[450] ** INTERNAL ERROR: Uncaught Exception **
    Exception: *** -[NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: Plugin Path)
    Stack:
    0 0×953b014b __raiseError (in CoreFoundation)
    1 0×948380fb objc_exception_throw (in libobjc.A.dylib)
    2 0×953aff2b +[NSException raise:format:arguments:] (in CoreFoundation)
    3 0×953aff6a +[NSException raise:format:] (in CoreFoundation)
    4 0×925f9328 -[NSCFDictionary setObject:forKey:] (in Foundation)
    5 0×00cfcda8 +[PBXDebugDataValueViewHelper addBundlesFromDirectory:load:] (in DevToolsInterface)
    6 0×00cfcef6 +[PBXDebugDataValueViewHelper addFormatStringsFromFiles:load:] (in DevToolsInterface)
    7 0×00cf9bb8 +[PBXDebugDataValueViewHelper initializeFormatStringsDictionaries] (in DevToolsInterface)
    8 0×00cf94ac +[PBXDebugDataValueViewHelper initialize] (in DevToolsInterface)
    9 0×94834b78 _class_initialize (in libobjc.A.dylib)
    10 0×948334f9 _class_lookupMethodAndLoadCache (in libobjc.A.dylib)
    11 0×94843736 objc_msgSend (in libobjc.A.dylib)
    12 0×00ca9df1 -[PBXDebugDataValueViewModule updateFromContainerDataValue] (in DevToolsInterface)
    13 0×00ca9583 -[PBXDebugDataValueViewModule setContainerDV:] (in DevToolsInterface)
    14 0×00ca996e -[PBXDebugDataValueViewModule setModel:] (in DevToolsInterface)
    15 0×00cbaa6d -[PBXDebugExpressionsViewModule setContainerDataValue:] (in DevToolsInterface)
    16 0×00c08047 -[PBXDebugSessionModule debugExecutable:] (in DevToolsInterface)
    17 0×00db030d -[XCProjectSelection startActiveExecutable] (in DevToolsInterface)
    18 0×00da9a1f -[XCProjectSelection toggleGo:] (in DevToolsInterface)
    19 0×953b5a7d __invoking___ (in CoreFoundation)
    20 0×953b5468 -[NSInvocation invoke] (in CoreFoundation)
    21 0×953b5538 -[NSInvocation invokeWithTarget:] (in CoreFoundation)
    22 0×953b59aa ___forwarding___ (in CoreFoundation)
    23 0×953b5a12 _CF_forwarding_prep_0 (in CoreFoundation)
    24 0×9307bac8 -[NSToolbarButton sendAction:to:] (in AppKit)
    25 0×9307ba59 -[NSToolbarButton sendAction] (in AppKit)
    26 0×9307afda -[NSToolbarItemViewer mouseDown:] (in AppKit)
    27 0×92f3588b -[NSWindow sendEvent:] (in AppKit)
    28 0×00b32199 -[XCWindow sendEvent:] (in DevToolsInterface)
    29 0×92f02431 -[NSApplication sendEvent:] (in AppKit)
    30 0×00ad759c -[PBXExtendedApplication sendEvent:] (in DevToolsInterface)
    31 0×92e5fe27 -[NSApplication run] (in AppKit)
    32 0×92e2d030 NSApplicationMain (in AppKit)

  5. By yan on Jun 19, 2008 | Reply

    Chris,
    You are receiving the stack trace because the plug-in is not being loaded, because the executable in the bundle is missing, hence “attempt to insert nil value (key: Plugin Path)”.

    This means that the build of the plug-in did not succeed, even though a bundle appeared in the Release folder. The Release build is setup to build a universal plug-in (ppc && i386). It would fail to link if your Qt libraries (or frameworks) were built for only one architecture. To resolve, change the architecture of the target to match the architecture of your Qt 4.4 libraries (or frameworks) and then rebuild the project and copy the newly successful bundle over to the proper location.

    Another solution would be to take the binary package and use the ‘install_name_tool’ executable to change the location of libQtCore.4.dylib… for example:

    install_name_tool -change /Developer/qt-4.4.0/lib/libQtCore.4.dylib /path/to/your/libQtCore.4.dylib QtDataFormatters.bundle/Contents/MacOS/QtDataFormatters

  6. By lukassen on Jun 22, 2008 | Reply

    Hi,

    i am using the frameworked version of Qt not build-from-source-as-dynlib, so my Qt is in /Library/Frameworks/QtCore.framework. Which rules out the install_tool_path.
    Back to the source, i noticed you used Xcode 3.1 (iPhone) so i installed that. It still can’t find QtCore, but at least i can add the framework as existing external framework. It now complains about not finding QtCore… one step forward, two in reverse :-)
    Of course i could run qmake -project and qmake, but that will create a whole new project file, that can find the frameworks, but will complain about the target..
    still puzzled…

    regards
    Chris

  7. By lukassen on Jun 22, 2008 | Reply

    solved it! apparently xcode left some of your old references in the project file where it searches for headers and linker search paths, totally ignoring the fresh framework! some manual tinkering in the xproject file and in particular removing the -lQtCore parameter did it.

    It is very nice to be able to debug QStrings in Xcode, thanks for posting the code!

  8. By Lerry on Jun 27, 2008 | Reply

    I have the same problem : It can’t find QtCore. But where to remove -|QtCore parameter? My environment is QT 4.4 and XCode 3.0. Thanks a lot?

  9. By yan on Jun 30, 2008 | Reply

    Lerry,

    The quickest way is to use the install_name_tool utility and update the bundle executable’s dependency on libQtCore to your location of libQtCore (if your Qt is built as a set of libs) or to the location of the QtCore framework executable (if your Qt is built as a set of frameworks).

    The other option to resolve this issue would be to modify the project as specified by lukassen. Edit the target in the project:

    1. Update the “Header Search Paths” section
    2. Update the “Library Search Paths” section
    3. Update the “Other Linker Flags” section

    clean and rebuild.

  10. By xEsk on Oct 28, 2008 | Reply

    Hi, it is possible link this DataFormater with static Qt compilation?

Post a Comment