Контроль, какой заголовочный файл проекта будет включать 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):
добавьте пользовательский параметр сборки USE_HEADERMAP = NO для каждой соответствующей цели. Вот как:
1.1. Откройте информационную панель цели на панели "Построение".
1.2. В раскрывающемся меню действий в левом нижнем углу окна выберите "Добавить пользовательскую настройку".
1.3. В добавленной строке установите для первого столбца ("Настройка") значениеUSE_HEADERMAP
и второй столбец ("Значение") дляNO
,Добавьте правильный путь включения для каждой цели (целевые параметры сборки "Пути поиска заголовка"). В моем примере это будет:
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 имеет три настройки, которые управляют генерацией файлов карты заголовков.
HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT
ЕслиYES
(по умолчанию), все файлы заголовков, которые принадлежат создаваемой цели, добавляются в файл карты заголовков и могут быть включены с помощьюinclude "header.h"
. Обратите внимание, что заголовки могут принадлежать только целям framework/library/bundle, но не целям приложения / программы.HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES
ЕслиYES
(по умолчанию), заголовки всех других целей добавляются в файл карты заголовков и могут быть включены с помощьюinclude <TargetName/header.h>
. Обратите внимание, что это также верно для целей, не относящихся к фреймворку.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}/**
Почему вы не можете просто использовать разные пути включения в каждой цели?