Контроль, какой заголовочный файл проекта будет включать Xcode

Мой проект XCode строится на вариации одного и того же продукта с использованием двух целей. Разница между ними заключается только в том, какая версия включенной библиотеки используется. Для исходных файлов.c легко назначить правильную версию для правильной цели, используя флажок target. Тем не менее, включение заголовочного файла всегда включает один и тот же. Это верно для одной цели, но неправильно для другой.

Есть ли способ контролировать, какой заголовочный файл включен каждой целью?

Вот моя иерархия файла проекта (который копируется в XCode):

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

и myCode.cpp делает такие вещи, как:

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

И конечно же я определяю OLDVERSION для одной цели, а не для другой.

Обратите внимание #include должно быть, как показано. Оба следующих сбоя с файлом не найдена ошибка:

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

Так есть ли способ сказать Xcode, который theirLib.h включить на цель?

Ограничения:
- два заголовочных файла имеют одинаковое имя. В крайнем случае, я мог бы переименовать одну из них, но я бы предпочел этого избегать, так как это приведет к сильному растяжению волос на других платформах.
- необходимость изменить #include Я бы предпочел избегать добавления ссылки на вложенную папку, потому что мне нужно было бы сделать это дважды с помощью директивы условной компиляции.
- Я могу настроить свой проект так, как считаю нужным

Спасибо за любую помощь.

4 ответа

Решение

Ключевой частью ответа является использование USE_HEADERMAP = NO, как предложено Крисом в комментарии. Вот подробности.

Краткий рецепт (проверено в Xcode 3.2.2):

  1. добавьте пользовательский параметр сборки USE_HEADERMAP = NO для каждой соответствующей цели. Вот как:
    1.1. Откройте информационную панель цели на панели "Построение".
    1.2. В раскрывающемся меню действий в левом нижнем углу окна выберите "Добавить пользовательскую настройку".
    1.3. В добавленной строке установите для первого столбца ("Настройка") значение USE_HEADERMAPи второй столбец ("Значение") для NO,

  2. Добавьте правильный путь включения для каждой цели (целевые параметры сборки "Пути поиска заголовка"). В моем примере это будет:
    2.1. добавлять TheirOldLib для "старой" цели
    2.2. добавлять TheirNewLib для "новой" цели

Шаг 1 отключает функцию автоматической карты заголовков Xcode, посредством которой любой файл заголовка, включенный в проект, напрямую доступен через его имя, независимо от его фактического пути. Когда два заголовка имеют одинаковое имя, эта функция приводит к неразрешимой неоднозначности.

Шаг 2 позволяет #include "theirLib.h" работать без указания заголовка файла фактического пути к файлу.

Эти два шага вместе выполняют мои два ограничения.

В заключение, USE_HEADERMAP насколько я могу судить, Apple не документирует. Я заполню отчет об ошибке, так как этот параметр имеет решающее значение в ряде случаев, как показывает поиск в Google. Сообщается как rdar://7840694. Также на открытом Радар, как http://openradar.appspot.com/radar?id=253401

USE_HEADERMAP=NO - это излишне для некоторых проектов. Может быть достаточно просто использовать HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT=NO. Документация здесь: https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/XcodeBuildSettingRef/1-Build_Setting_Reference/build_setting_ref.html

Xcode ускоряет сборку, создавая файлы карты заголовков.

Вместо того, чтобы предоставлять компилятору список каталогов для поиска заголовков, вы также можете предоставить ему файлы карты заголовков. Файл карты заголовка похож на хеш-таблицу, ключи поиска - этоinclude аргументы, значения - это пути к заголовкам.

Вот пример такого файла карты:
(Примечание: это не фактический синтаксис файла карты заголовка, это просто удобочитаемое представление)

Foo.h -> /usr/include/Foo.h
Bar.h -> /home/user/Documents/ProjectA/src/include/Bar.h
foo/bar/foobar.h -> /home/user/Documents/ProjectB/inc/foo/bar/foobar.h

Эти три записи соответствуют

#include "Foo.h"
#include "Bar.h"
#include "foo/bar/foobar.h"

Теперь Xcode имеет три настройки, которые управляют генерацией файлов карты заголовков.

  1. HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT
    Если YES (по умолчанию), все файлы заголовков, которые принадлежат создаваемой цели, добавляются в файл карты заголовков и могут быть включены с помощью include "header.h". Обратите внимание, что заголовки могут принадлежать только целям framework/library/bundle, но не целям приложения / программы.

  2. HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES
    Если YES (по умолчанию), заголовки всех других целей добавляются в файл карты заголовков и могут быть включены с помощью include <TargetName/header.h>. Обратите внимание, что это также верно для целей, не относящихся к фреймворку.

  3. HEADERMAP_INCLUDES_PROJECT_HEADERS
    Если YES (по умолчанию), все остальные заголовки, присутствующие в файле проекта, которому принадлежит построенная цель, также добавляются в файл карты заголовков и могут быть включены с помощью include "header.h".

Дополнительно есть общая настройка USE_HEADERMAPэто контролирует, должен ли вообще создаваться файл карты заголовка. Только еслиYES (по умолчанию), Xcode сгенерирует файл карты заголовков и передаст его в качестве аргумента компилятору.

Если заголовок не указан в файле карты заголовков или карты заголовков не используются, компилятор будет искать заголовки с использованием одной из двух стратегий поиска:

Если заголовок импортируется с <...>, он будет искать во всех каталогах, указанных с помощью -I вариант (HEADER_SEARCH_PATHS), все каталоги, указанные с -isystem вариант (SYSTEM_HEADER_SEARCH_PATHS в Xcode) и в каталогах заголовков системы stanadrd (/usr/includeвыбранного SDK и других каталогов, принадлежащих установленным инструментам разработчика); именно в таком порядке и в каждой категории в указанном порядке.

Если заголовок импортируется с "...", он будет искать в том же каталоге, что и создаваемый файл.c/.m, во всех каталогах, указанных с помощью -iquote вариант (USER_HEADER_SEARCH_PATHS в Xcode), и в тех же каталогах он ищет <...>; именно в таком порядке и в каждой категории в указанном порядке.

Используйте USE_HEADERMAP=NO и в поле "Пути поиска по заголовкам пользователей" сначала укажите свой пользовательский каталог, а затем - каталог проекта: ${PROJECT_DIR}/ OurNewLib ${PROJECT_DIR}/**

Почему вы не можете просто использовать разные пути включения в каждой цели?

Другие вопросы по тегам