makdad
makdad

Reputation: 6450

How does XCode handle #import header statements in with multiple targets?

I have an XCode project with 2 targets (both are iPhone apps sharing 95% of the same code). However, one module isn't "shareable"; the implementations are too different.

My solution (that is not working) was to add 2 subdirectories to my Classes/ folder in my project directory - one for each target. In each directory, I've placed a view controller class, called ExampleSentencesViewController. Of course, each file is compiled as part of only one of the targets - I'm looking for an "automatic switching" of which implementation to use based on the target.

Inside each target's settings, I added each directory to the "Header Search Paths" setting (each path for each target).

Oddly, it only compiles for the original target. The target I added later won't compile, claiming that I've included the same header twice (there ARE two files, to be fair). How do I get XCode to forget about the original header??

I've tried deleting the .h files out of my project, but that does not seem to help.

Any help is appreciated.

Upvotes: 2

Views: 2700

Answers (1)

justin
justin

Reputation: 104698

fully qualify the header paths in the separate implementation files, based on one of your defined search directories:

#include <MONProject/Source/ExampleSentencesViewController.h>

vs

#include <MONSecondProject/Source/ExampleSentencesViewController.h>

update based on clarification:

ideally, you'd create a static library for the shared code.

for a simple case... you could take the direct approach by populating a header in your project's root, named ExampleSentencesViewController.h, and populating it like so:

/* you must define either MON_BUILD_MON_FIRST_PROJECT or MON_BUILD_MON_SECOND_PROJECT at the target level */

#if (defined(MON_BUILD_MON_FIRST_PROJECT) && defined(MON_BUILD_MON_SECOND_PROJECT))
#error invalid configuration: you cannot specify both projects to be compiled
#elif defined(MON_BUILD_MON_FIRST_PROJECT)
/* some fully qualified path: */
#include <MONFirstProject/ExampleSentencesViewController.h>
#elif defined(MON_BUILD_MON_SECOND_PROJECT)
/* some other fully qualified path: */
#include <MONSecondProject/ExampleSentencesViewController.h>
#else
#error uh... which project are you trying to build?
#endif

or you could just use these defines to conditionally enable/disable the interface and implementation of the classes with duplicate names (and then just include them both in the project's declaration of:

/* MONFirstProject/ExampleSentencesViewController.h> */

#if defined(MON_BUILD_MON_FIRST_PROJECT)
@interface ExampleSentencesViewController : NSViewController
/* ... */
@end
#endif

…but this will require to include both headers in your distribution (if applicable).

some of the finer details of inclusion can vary based on how you've declared your search paths (e.g., are they recursive or not?) and whether you use copy headers build phases in your xcodeproj. maintaining both projects which share code can become messy if you've been too relaxed in your include directives, discovery options, preprocessor declarations (conditional compilation/visibility) and/or build configurations so... that's why i recommend a library for the shared bits. this conditional stuff (in the two previous examples) is error prone and doesn't evolve or scale well. doing this is also a good way to confuse other tools in the development toolkit.

in fact, i prefer this over the preprocessor (assuming you're able to distribute both classes):

- (UIViewController *)newViewControllerForMyAwesomeView {
    if (IsAppMONFirstProject) {
        return [[MONFirstProjectViewController alloc] init...];
    }
    else if (IsAppMONSecondProject) {
        return [[MONSecondProjectViewController alloc] init...];
    }
    else {
        assert(0 && "definitely break up your code, now that it is referenced by 3 or more projects");
        return 0;
    }
}

if you're merely maintaining two versions of the same title, then practices will be much different.

anyways... this should be enough ideas to solve your problem - you just have to determine the lesser evil.

Upvotes: 3

Related Questions