views:

537

answers:

2

My Xcode project builds to variations of the same product using two targets. The difference between the two is only on which version of an included library is used. For the .c source files it's easy to assign the correct version to the correct target using the target check box. However, including the header file always includes the same one. This is correct for one target, but wrong for the other one.

Is there a way to control which header file is included by each target?

Here is my project file hierarchy (which is replicated in Xcode):

MyProject
  TheirOldLib
    theirLib.h
    theirLib.cpp
  TheirNewLib
    theirLib.h
    theirLib.cpp
myCode.cpp

and myCode.cpp does thing such as:

#include "theirLib.h"
…
somecode()
{
#if OLDVERSION
  theirOldLibCall(…);
#else
  theirNewLibCall(…);
#endif
}

And of course, I define OLDVERSION for one target and not for the other.

Note the #include must be as shown. Both of the following fail with a file not found error:

#include "TheirOldLib/theirLib.h"
#include "TheirNewLib/theirLib.h"

So is there a way to tell Xcode which theirLib.h to include per target?

Constraints:
- the two header files have the same name. As a last resort, I could rename one of them, but I'd rather avoid that as this will lead to major hair pulling on the other platforms.
- having to change the #include to add a reference to the enclosing folder is also something I'd rather avoid, because I would need to do it twice with a conditional compile directive.
- I'm free to tweak my project as I otherwise see fit

Thanks for any help.

+1  A: 

Why can't you just use different include paths in each target?

Azeem.Butt
If you have two headers with the same name but different paths, you need to set USE_HEADERMAP = NO in a custom build setting in both targets.
cdespinosa
Neat. I guess I've never tried. Good to see that Mike Ferris is still fighting the good fight against usability.
Azeem.Butt
using different include paths in each target doesn't work: include files *in* the project are always made accessible by Xcode with no path at all. This is the reason why the issue arise in the first place: with no path to disambiguate, there seems to be no way to tell Xcode which is the right file to include. Chris's suggestion is to disable that feature, to reverse to a more conventional include path scheme. I'll write up the answer in detail.
Jean-Denis Muys
A: 

The key part of the answer is to use USE_HEADERMAP = NO as suggested by Chris in a comment. Here are the details.

Short recipe (checked in Xcode 3.2.2):

  1. add a custom build setting of USE_HEADERMAP = NO for each concerned target. Here is how:
    1.1. Open the target's info panel on the "Build" pane.
    1.2. Pull down the action pop-up menu at the bottom left of the window, select "Add User-Defined Setting".
    1.3. In the newly added line, set the first column ("Setting") to USE_HEADERMAP, and the second column ("Value") to NO.

  2. add the correct include path to each target (target Build settings "Header Search Paths"). In my example that would be:
    2.1. add TheirOldLib for "old" target
    2.2. add TheirNewLib for "new" target

Step 1 disables the automatic header map feature of Xcode, through which any header file included in the project is directly accessible through its name, whatever its actual path. When two headers have the same name, this feature leads to an unresolvable ambiguity.

Step 2 allows for the #include "theirLib.h" to work without qualifying the header file actual path name.

These two steps together fulfill my two constraints.

Finally, USE_HEADERMAP is not documented by Apple, as far as I can tell. I'll fill a bug report for that, as this setting is crucial in a number of cases, as googling for it reveals. Reported as rdar://7840694. Also on open Radar as http://openradar.appspot.com/radar?id=253401

Jean-Denis Muys