Mulle kybernetiK - Tech Info:
Project Builder (PBX): Compile errors when building frameworks with separate location for intermediate build files
You'll stumble into this pitfall if you build framework projects that depend on other framework projects as well. A typical candidate would be EDInternet as it depends on EDCommon.
The problem

Let's begin with a common example. You want to build EDCommon & EDInternet as these are frameworks which are needed for MulleNewz.dock or XMLRPC for example. Let's assume you've checked out the latest versions from CVS to make sure you get the best snapshots that hopefully have all remaining bugs fixed.

You start by compiling EDCommon as this is the prerequisite for building EDInternet. You type:

% cd ed/EDCommon
% pbxbuild install -buildstyle Development INSTALL_ROOT=/
=== BUILDING TARGET EDCommon (Framework) OF TYPE Framework ===
/usr/bin/jam -d0 JAMBASE=/Developer/Makefiles/pbx_jamfiles/ProjectBuilderJambase JAMFILE=- install ACTION=install "TARGETNAME=EDCommon (Framework)" NATIVE_ARCH=ppc BUILD_STYLE=Development "CPP_HEADERMAP_FILE=/Local/BuildArea/EDCommon (Framework).build/Headermaps/EDCommon.hmap" DSTROOT=/tmp/EDCommon.dst INSTALL_ROOT=/ OBJROOT=/Local/BuildArea SRCROOT=/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDCommon SYMROOT=/Local/BuildArea

warning: <EDCommon>EDCommon.framework depends on itself
Completed phase <CopyHeaders> for EDCommon.framework
Completed phase <CopyResources> for EDCommon.framework
Completed phase <DeriveAndCompileSources> for EDCommon.framework
Completed phase <LinkWithFrameworksAndLibraries> for EDCommon.framework
Completed phase <RezResourceManagerFiles> for EDCommon.framework
** BUILD SUCCEEDED **

This went fairly smooth, so you continue building EDInternet. You type:

% cd ../EDInternet
% pbxbuild install -buildstyle Development INSTALL_ROOT=/
=== BUILDING TARGET EDInternet (Framework) OF TYPE Framework ===
/usr/bin/jam -d0 JAMBASE=/Developer/Makefiles/pbx_jamfiles/ProjectBuilderJambase JAMFILE=- install ACTION=install "TARGETNAME=EDInternet (Framework)" NATIVE_ARCH=ppc BUILD_STYLE=Development "CPP_HEADERMAP_FILE=/Local/BuildArea/EDInternet (Framework).build/Headermaps/EDInternet.hmap" DSTROOT=/tmp/EDInternet.dst INSTALL_ROOT=/ OBJROOT=/Local/BuildArea SRCROOT=/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDInternet SYMROOT=/Local/BuildArea

warning: <EDInternet>EDInternet.framework depends on itself
Completed phase <CopyHeaders> for EDInternet.framework
Completed phase <CopyResources> for EDInternet.framework
/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDCommon/EDCommon.h:25: header file 'NSArray+Extensions.h' not found
...
/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDCommon/EDCommon.h:74: header file 'EDSwapView.h' not found
cpp-precomp: warning: errors during smart preprocessing, retrying in basic mode
** BUILD FAILED **

What happened?

Understanding the problem

If you switch to Build Log detail level: Detailed Logs mode you'll see that both the resulting products and the intermediary build files are being put in/Local/BuildArea. Most probably your directory will be named differently but that's how some people at Mulle kybernetiK name it (since early Object Factory days). If we take a look in that directory we can see a directory called ProjectHeaders in there. In that directory, PBX places intermediary versions of the projects' header files which are simply stubs. These stubs contain references to the real header files by simply containing a (sample taken from my copy of EDCommon's NSArray+Extensions.h) #include "/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDCommon/FoundationExtensions.subproj/NSArray+Extensions.h" reference.

Now let's compile again and have a look at the detailed logs (for simplicity's sake I'm only including the relevant parts in the output):

% pbxbuild install -buildstyle Development INSTALL_ROOT=/
=== BUILDING TARGET EDInternet (Framework) OF TYPE Framework ===
/usr/bin/jam -d2 JAMBASE=/Developer/Makefiles/pbx_jamfiles/ProjectBuilderJambase JAMFILE=- install ACTION=install "TARGETNAME=EDInternet (Framework)" NATIVE_ARCH=ppc BUILD_STYLE=Development "CPP_HEADERMAP_FILE=/Local/BuildArea/EDInternet.build/EDInternet (Framework).build/Headermaps/EDInternet.hmap" DSTROOT=/tmp/EDInternet.dst INSTALL_ROOT=/ OBJROOT=/Local/BuildArea/EDInternet.build SRCROOT=/automount/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDInternet SYMROOT=/Local/BuildArea

warning: <EDInternet>EDInternet.framework depends on itself
...updating 27 target(s)...
BuildPhase EDInternet.framework
[...]
CompileC /Local/BuildArea/EDInternet.build/EDInternet (Framework).build/Objects/ppc/NSHost+Extensions.o

    /usr/bin/cc  -c "-F/Local/BuildArea/ProjectHeaders" "-F/Local/BuildArea" "-F/Library/Frameworks"  "-I/Local/BuildArea/ProjectHeaders/EDInternet" "-I/Local/BuildArea/include" "-IFoundationExtensions.subproj"  "-arch" "ppc" "-fno-common" "-fpascal-strings" "-O3" "-Wmost" "-Wno-four-char-constants" "-Wno-unknown-pragmas" "-pipe" "-g" "-precomp-trustfile" "/Local/BuildArea/EDInternet.build/EDInternet (Framework).build/TrustedPrecomps.txt" "-Wp,-header-mapfile,/Local/BuildArea/EDInternet.build/EDInternet (Framework).build/Headermaps/EDInternet.hmap"   "-I/Local/BuildArea/EDInternet.build/EDInternet (Framework).build/DerivedSources"   "FoundationExtensions.subproj/NSHost+Extensions.m"  -o "/Local/BuildArea/EDInternet.build/EDInternet (Framework).build/Objects/ppc/NSHost+Extensions.o"

/automount/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDCommon/EDCommon.h:25: header file 'NSArray+Extensions.h' not found
/automount/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDCommon/EDCommon.h:26: header file 'NSAttributedString+Extensions.h' not found
[...]
cpp-precomp: warning: errors during smart preprocessing, retrying in basic mode
...failed CompileC /Local/BuildArea/EDInternet.build/EDInternet (Framework).build/Objects/ppc/NSHost+Extensions.o ...
** BUILD FAILED **

For some reasons /Local/BuildArea/ProjectHeaders is the first framework include path as we can see in the output above. This shouldn't be a problem but it turns out that there is a bug in the compiler that prevents the stub's (see above) referenced files from being found when there are multiple references to identical "sounding" headers in a framework include path. [Note: this sounds a bit flaky - and it is - but it's rather complicated to go into the compiler's internals. All testcases that I could think of provided me with this result, however.] If one would change the order in the include path and put /Local/BuildArea frontmost everything would be ok.

Solution

We cannot simply change the framework include order because the Jamfile is generated automatically on the fly. But another workaround is pretty easy: Remove the EDCommon.framework directory from /Local/BuildArea/ProjectHeaders before you build EDInternet. Here is what happens then:

% pbxbuild install -buildstyle Development INSTALL_ROOT=/
=== BUILDING TARGET EDInternet (Framework) OF TYPE Framework ===
/usr/bin/jam -d0 JAMBASE=/Developer/Makefiles/pbx_jamfiles/ProjectBuilderJambase JAMFILE=- install ACTION=install "TARGETNAME=EDInternet (Framework)" NATIVE_ARCH=ppc BUILD_STYLE=Development "CPP_HEADERMAP_FILE=/Local/BuildArea/EDInternet.build/EDInternet (Framework).build/Headermaps/EDInternet.hmap" DSTROOT=/tmp/EDInternet.dst INSTALL_ROOT=/ OBJROOT=/Local/BuildArea/EDInternet.build SRCROOT=/automount/Network/Users/znek/Projects/mulle-anon-cvs/ed/EDInternet SYMROOT=/Local/BuildArea

warning: <EDInternet>EDInternet.framework depends on itself
Completed phase <CopyHeaders> for EDInternet.framework
Completed phase <CopyResources> for EDInternet.framework
FoundationExtensions.subproj/NSString+MessageUtils.m:142: warning: ** workaround for broken implementation of -invertedSet in 5G64
Socket.subproj/EDStream.m:95: warning: * auto close (cf EDSMTPStream)
Message.subproj/ContentCoder.subproj/EDPlainTextContentCoder.m:52: warning: * maybe we should allow text/enriched or even text/html and dump the formatting...    
Mail.subproj/EDMailAgent.m:128: warning: * maybe check for root if not debug build   
Completed phase <DeriveAndCompileSources> for EDInternet.framework
Completed phase <LinkWithFrameworksAndLibraries> for EDInternet.framework
Completed phase <RezResourceManagerFiles> for EDInternet.framework
** BUILD SUCCEEDED **


Usually I do remove the whole /Local/BuildArea/ProjectHeaders directory before building anything. This imposes a small time penalty on larger builds - but your builds won't fail for the above reasons, probably saving more time and nerves.

Copyright (C) 2001 Mulle kybernetiK
written by ZNeK <znek@mulle-kybernetik.com>