Xcode 4 не может найти общедоступные заголовочные файлы из статической зависимости библиотеки - PullRequest
91 голосов
/ 05 апреля 2011

Альтернативные названия для облегчения поиска

  • Xcode не может найти заголовок
  • Отсутствует .h в Xcode
  • Xcode .h файл не найден
  • Файл лексического или препроцессорного файла не найден

Я работаю над проектом приложения для iOS, созданным в Xcode 3. Теперь я перешел в Xcode 4, мой проект создаетчисло статических библиотек.

Эти статические библиотеки также объявляют публичные заголовки, и эти заголовки используются кодом приложения.В Xcode 3.x заголовки были скопированы (как фаза сборки) в public headers directory, затем в проекте приложения public headers directory был добавлен в headers search list.

Под Xcode 4 каталог сборкиперемещен в ~/Library/Developer/Xcode/DerivedData/my-project.

Проблема в том, как мне сослаться на это новое местоположение в настройках поиска по заголовкам?Кажется, что:

  • public headers directory относится к каталогу DerivedData, но каталог
  • headers search относится к чему-то другому (возможно, к месту проекта)

Как настроить целевой объект статической библиотеки для разработки под iOS в Xcode 4, который обеспечит доступность заголовочных файлов клиентам, которые используют статическую библиотеку при попытке компилировать в качестве зависимости?

Ответы [ 17 ]

125 голосов
/ 01 марта 2012

Каждое из решений, которые я видел для этой проблемы, либо казалось нелегким (копирование заголовков в проект приложения), либо чрезмерно упрощалось до такой степени, что они работали только в тривиальных ситуациях.

Краткий ответ

Добавьте следующий путь к путям поиска заголовка пользователя

"$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts"

Почему это работает?

Во-первых, нам нужно понять проблему. При нормальных обстоятельствах, то есть когда вы запускаете, тестируете, профилируете или анализируете, Xcode строит ваш проект и помещает выходные данные в каталог Build / Products / Configuration / Products, который доступен через $ BUILT_PRODUCTS_DIR макрос.

В большинстве руководств, касающихся статических библиотек, рекомендуется указывать для Путь к папке общих заголовков значение $ TARGET_NAME , что означает, что вашим файлом lib становится $ BUILT_PRODUCTS_DIR / libTargetName.a и ваши заголовки помещаются в $ BUILT_PRODUCTS_DIR / TargetName. Пока ваше приложение включает в свои пути поиска $ BUILT_PRODUCTS_DIR , импорт будет работать в 4 ситуациях, указанных выше. Однако это не сработает при попытке архивирования.

Архивация работает немного иначе

Когда вы архивируете проект, XCode использует другую папку с именем ArchiveIntermediates. В этой папке вы найдете / YourAppName / BuildProductsPath / Release-iphoneos /. Это папка, на которую $ BUILT_PRODUCTS_DIR указывает, когда вы делаете архив. Если вы загляните туда, вы увидите, что есть символическая ссылка на ваш файл статической библиотеки, но папка с заголовками отсутствует.

Чтобы найти заголовки (и файл lib), вам нужно перейти к IntermediateBuildFilesPath / UninstalledProducts /. Помните, когда вам сказали установить Пропустить установку на ДА для статических библиотек? Ну, это тот эффект, который имеет настройка при создании архива.

Примечание: если вы не настроили пропустить установку, ваши заголовки будут помещены в другое место, а файл lib будет скопирован в ваш архив, что не позволит вам экспортировать файл .ipa, который вы можете отправить в App Store.

После долгих поисков я не смог найти ни одного макроса, который бы точно соответствовал папке UninstalledProducts, поэтому необходимо составить путь с помощью "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts"

Резюме

Для вашей статической библиотеки убедитесь, что вы пропустили установку и ваши публичные заголовки помещены в $ TARGET_NAME.

Для вашего приложения задайте в качестве путей поиска заголовка пользователя значение «$ (BUILT_PRODUCTS_DIR)», которое отлично работает для обычных сборок, и «$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts», которое работает для сборок архивов.

85 голосов
/ 01 июня 2012

Я столкнулся с этой же проблемой при разработке своей собственной статической библиотеки, и, хотя ответ Колина был очень полезен, мне пришлось немного его изменить, чтобы он работал последовательно и просто при выполнении и архивировании проектов в Xcode 4 с использованием Workspace.

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

Мой метод следующий:

Создать рабочее пространство

  1. Под Xcode 4, перейдите в Файл, Новый, Рабочая область.
  2. Из Finder вы можете затем перетащить в проекты .xcodeproj и статическую библиотеку, которую вы хотите использовать, и новое создаваемое вами приложение, которое использует библиотеку. См. Apple Docs для получения дополнительной информации о настройке рабочих областей: https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Workspace.html

Настройки проекта статической библиотеки

  1. Убедитесь, что все заголовки статической библиотеки настроены на копирование в «Public». Это делается в настройках статической библиотеки назначения> Фазы сборки. На этапе «Копировать заголовки» убедитесь, что все ваши заголовки находятся в разделе «Public».
  2. Далее перейдите в «Настройки сборки», найдите «Путь к папке публичных заголовков» и введите путь к своей библиотеке. Я решил использовать это:

включить / LibraryName

Я принял это из использования с RestKit и обнаружил, что он лучше всего работает со всеми моими статическими библиотеками. Это говорит XCode скопировать все заголовки, которые мы переместили в раздел «Public» заголовков на шаге 1, в указанную здесь папку, которая находится в папке Derived Data при сборке. Как и в случае с RestKit, мне нравится использовать одну папку «include» для хранения каждой статической библиотеки, которую я использую в проекте.

Мне также не нравится использовать здесь макросы, потому что это позволит нам позже использовать путь поиска в заголовке одного пользователя при настройке проекта с использованием статической библиотеки.

  1. Найдите «Пропустить установку» и убедитесь, что для него установлено значение «ДА».

Настройки для проекта с использованием статической библиотеки

  1. Добавьте статическую библиотеку в качестве фреймворка в «Фазы сборки»> «Связать двоичные файлы с библиотеками» и добавьте файл libLibraryName.a для любой статической библиотеки, которую вы хотите использовать.
  2. Далее убедитесь, что проект настроен на поиск путей поиска пользователя. Это делается в разделе «Настройки сборки»> «Всегда искать пути пользователя» и убедитесь, что для него установлено значение «ДА»
  3. В той же области найдите пути поиска заголовка пользователя и добавьте:

    "$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / включить"

Это говорит XCode искать статические библиотеки в промежуточной папке сборки, которую XCode создает в процессе сборки. Здесь у нас есть папка «include», которую мы используем для расположения статической библиотеки, которую мы настроили на шаге 2 для настроек проекта статической библиотеки. Это самый важный шаг в получении Xcode для правильного поиска ваших статических библиотек.

Настройка рабочего пространства

Здесь мы хотим настроить рабочее пространство таким образом, чтобы оно создавало статическую библиотеку при создании нашего приложения. Это делается путем редактирования схемы, используемой для нашего приложения.

  1. Убедитесь, что у вас выбрана схема, которая создаст ваше приложение.
  2. В раскрывающемся списке «Схема» выберите «Редактировать схему».
  3. Выберите Build вверху списка слева. Добавьте новую цель, нажав + на средней панели.
  4. Вы должны увидеть статическую библиотеку, отображаемую для библиотеки, которую вы пытаетесь связать. Выберите статическую библиотеку iOS.
  5. Нажмите «Выполнить» и «Архивировать». Это говорит о схеме компиляции библиотек для статической библиотеки всякий раз, когда вы создаете свое приложение.
  6. Перетащите статическую библиотеку выше цели приложения. Это заставляет статические библиотеки компилироваться перед вашей целью приложения.

Начало использования библиотеки

Теперь вы можете импортировать статическую библиотеку, используя

import <LibraryName/LibraryName.h>

Этот метод избавляет от необходимости иметь разные пути пользовательских заголовков для разных конфигураций, поэтому у вас не должно возникнуть проблем при компиляции архивов.

Почему это работает?

Все зависит от этого пути:

"$(PROJECT_TEMP_DIR)/../UninstalledProducts/include"

Поскольку мы настраиваем нашу статическую библиотеку для использования «Пропустить установку», скомпилированные файлыперемещен в папку «UninstalledProjects» во временном каталоге сборки.Наш путь здесь также разрешается в папку «include», которую мы устанавливаем для нашей статической библиотеки и используем для нашего пути поиска в заголовке пользователя.Работая вместе, Xcode знает, где найти нашу библиотеку во время процесса компиляции.Поскольку этот временный каталог сборки существует для обеих конфигураций Debug и Release, вам нужен только один путь для Xcode для поиска статических библиотек.

16 голосов
/ 09 апреля 2011

Проект Xcode 4 не в состоянии скомпилировать статическую библиотеку

Смежный вопрос: «Файл проблемы лексического или препроцессора не найден» в Xcode 4

Ошибки могут включать; отсутствующие заголовочные файлы, "лексическая проблема или проблема препроцессора"

Решения:

  1. Проверьте правильность "путей заголовка пользователя"
  2. Установить «Всегда искать пути пользователя» на ДА
  3. Создайте групповой вызов «Индексирование заголовков» в своем проекте и перетащите заголовки в эту группу, НЕ добавляйте к любым целям при появлении запроса.
15 голосов
/ 28 декабря 2012

Это была очень полезная тема.Исследуя мою собственную ситуацию, я обнаружил, что у Apple есть 12-страничный документ от сентября 2012 года под названием «Использование статических библиотек в iOS».Вот ссылка в формате pdf: http://developer.apple.com/library/ios/technotes/iOSStaticLibraries/iOSStaticLibraries.pdf

Это намного проще, чем большинство обсуждений в Интернете, и с некоторыми небольшими модами, чтобы объяснить, как настроены внешние библиотеки, которые я использую, это хорошо работает длямне.Вероятно, самая важная часть:

Если у вашей целевой библиотеки есть фаза сборки «Копировать заголовки», вы должны удалить ее;Фазы сборки заголовков копирования не работают правильно с статическими библиотеками при выполнении действия «Архивировать» в XCode.

Новые статические целевые библиотеки, созданные с помощью Xcode 4.4 или более поздней версии, будут иметь правильно настроенную фазу копирования файлов для заголовков., так что вы должны проверить, если у вас уже есть один, прежде чем создавать его.Если вы этого не сделаете, нажмите «Add Build Phase» в нижней части целевого редактора и выберите «Add Copy Files». Раскройте новую фазу сборки «Copy Files» и задайте для «Destination» «Каталог продуктов». Установите для «Subpath» значение /$ {PRODUCT_NAME}.Это скопирует файлы в папку, названную в честь вашей библиотеки (взято из настройки сборки PRODUCT_NAME), внутри папки с именем include, внутри вашего каталога встроенных продуктов.Папка include внутри каталога продуктов сборки находится в пути поиска заголовка по умолчанию для приложений, поэтому это подходящее место для размещения файлов заголовков.

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

4 голосов
/ 15 июля 2013

http://developer.apple.com/library/ios/#technotes/iOSStaticLibraries/Articles/creating.html

Согласно документации Apple:

В вашей библиотеке будет один или несколько заголовочных файлов, которые необходимо импортировать клиентам этой библиотеки.Чтобы настроить, какие заголовки экспортируются на клиенты, выберите проект библиотеки, чтобы открыть редактор проектов, выберите цель библиотеки, чтобы открыть редактор целей, и перейдите на вкладку фаз сборки.Если у вашей целевой библиотеки есть фаза сборки «Копировать заголовки», вы должны удалить ее;Фазы сборки заголовков копирования не работают должным образом со статическими целями библиотеки при выполнении действия «Архивирования» в XCode.

3 голосов
/ 08 апреля 2011

Посмотрите на решение Jonah Wlliam (в середине пути) и модель GitHub (в комментариях) для понимания. http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/

2 голосов
/ 10 февраля 2016

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

2 голосов
/ 15 апреля 2012

Добавить $ (OBJROOT) / UninstalledProducts / sharpPathToHeaders в Пути поиска заголовка.

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

Под Навигатором Журнала в XCode (вкладка справа от навигатора точек останова) вы можете увидеть историю сборки. Если вы выберете фактический сбой сборки, вы можете развернуть его детали, чтобы увидеть setenv PATH и убедиться, что путь к вашим заголовочным файлам там.

1 голос
/ 30 марта 2015

Ни один из этих ответов не работал для меня. Вот что сделал. Точно добавьте следующее (скопируйте и вставьте, включая двойные кавычки) в ваш путь поиска заголовка пользователя параметр сборки:

"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include/"

Обратите внимание на добавление подкаталога "/ include /" по сравнению с другими ответами. Как отмечали другие пользователи, «рекурсивный» вариант, похоже, ничего не делает, поэтому вы можете его игнорировать.

Мой проект теперь может успешно архивироваться при импорте файлов заголовков статической библиотеки в следующем виде:

#import "LibraryName/HeaderFile.h"

Вы не должны включить параметр Всегда искать пути пользователя , если только вы не включили заголовки статической библиотеки в угловые скобки (#import <LibraryName/HeaderFile.h>), но вам действительно не следует так или иначе, если это не заголовок системы / фреймворка.

1 голос
/ 30 мая 2012

Добавьте следующий путь к своим путям поиска в заголовке пользователя:

$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts

Это проверено!

...