Xcode 4 не может найти общедоступные заголовочные файлы из статической зависимости библиотеки
Альтернативные названия, чтобы помочь поиску
- 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, которая будет гарантировать, что заголовочные файлы будут доступны клиентам, которые используют статическую библиотеку при попытке компилировать как зависимость?
18 ответов
Проект Xcode 4 не в состоянии компилировать статическую библиотеку
Связанный вопрос: "файл лексического или препроцессорного файла не найден" в Xcode 4
Ошибки могут включать в себя; отсутствуют заголовочные файлы, "лексическая проблема или проблема препроцессора"
Решения:
- Проверьте правильность "пути заголовка пользователя"
- Установите "Всегда искать пути пользователя" на ДА
- Создайте групповой вызов "Индексирование заголовков" в своем проекте и перетащите заголовки в эту группу, НЕ добавляйте ни к каким целям при появлении соответствующего запроса.
Каждое из решений этой проблемы, которое я видел, либо казалось нелегким (копирование заголовков в проект приложения), либо чрезмерно упрощалось до такой степени, что они работали только в тривиальных ситуациях.
Краткий ответ
Добавьте следующий путь к своим путям поиска заголовка пользователя
"$(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/. Помните, когда вам сказали установить Skip Install на YES для статических библиотек? Ну, это тот эффект, который имеет настройка при создании архива.
Примечание: если вы не настроили пропустить установку, ваши заголовки будут помещены в другое место, а файл lib будет скопирован в ваш архив, что не позволит вам экспортировать файл.ipa, который вы можете отправить в App Store,
После долгих поисков я не смог найти ни одного макроса, который бы точно соответствовал папке UninstalledProducts, поэтому мне нужно было создать путь с помощью "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts"
Резюме
Для вашей статической библиотеки убедитесь, что вы пропустили установку и ваши публичные заголовки помещены в $TARGET_NAME.
Для вашего приложения задайте для путей поиска в заголовке пользователя значение "$(BUILT_PRODUCTS_DIR)", которое отлично работает для обычных сборок, и "$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts", которое работает для сборок архивов.
Я столкнулся с этой же проблемой при разработке своей собственной статической библиотеки, и, хотя ответ Колина был очень полезен, мне пришлось немного его изменить, чтобы он работал согласованно и просто, когда выполняются и архивируются проекты под Xcode 4 с использованием рабочей области.
Что отличается от моего метода, так это то, что вы можете использовать один путь к заголовку пользователя для всех ваших конфигураций сборки.
Мой метод заключается в следующем:
Создать рабочее пространство
- Под Xcode 4, перейдите в Файл, Новый, Рабочая область.
- Из Finder вы можете затем перетащить в проекты.xcodeproj и статическую библиотеку, которую вы хотите использовать, и новое создаваемое приложение, которое использует библиотеку. См. Apple Docs для получения дополнительной информации о настройке рабочих областей: https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Workspace.html
Настройки проекта статической библиотеки
- Убедитесь, что все заголовки статической библиотеки установлены на "Public". Это делается в настройках статической библиотеки назначения> Фазы сборки. На этапе "Копировать заголовки" убедитесь, что все ваши заголовки находятся в разделе "Public".
- Далее перейдите в "Настройки сборки", найдите "Путь к общедоступной папке заголовков" и введите путь к своей библиотеке. Я решил использовать это:
включить /LibraryName
Я принял это из использования с RestKit и обнаружил, что он лучше всего работает со всеми моими статическими библиотеками. Это говорит Xcode скопировать все заголовки, которые мы переместили в раздел "Public" заголовков на шаге 1, в указанную здесь папку, которая находится в папке Derived Data при сборке. Как и в случае с RestKit, мне нравится использовать одну папку "include" для хранения каждой статической библиотеки, которую я использую в проекте.
Мне также не нравится использовать здесь макросы, потому что это позволит нам позже использовать путь поиска по одному заголовку пользователя, когда мы настроим проект с использованием статической библиотеки.
- Найдите "Пропустить установку" и убедитесь, что установлено значение "ДА".
Настройки для проекта с использованием статической библиотеки
- Добавьте статическую библиотеку в качестве фреймворка в "Фазы сборки"> "Связать двоичные файлы с библиотеками" и добавьте файл libLibraryName.a для любой статической библиотеки, которую вы хотите использовать.
- Затем убедитесь, что проект настроен на поиск путей поиска пользователя. Это делается в разделе "Параметры сборки"> "Всегда искать пути пользователя" и убедитесь, что для него установлено значение "ДА".
В той же области найдите пути поиска заголовка пользователя и добавьте:
"$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / включают"
Это говорит XCode искать статические библиотеки в промежуточной папке сборки, которую XCode создает в процессе сборки. Здесь у нас есть папка "include", которую мы используем для расположения статической библиотеки, которую мы настроили на шаге 2 для настроек проекта статической библиотеки. Это самый важный шаг в получении Xcode для правильного поиска ваших статических библиотек.
Настройте рабочее пространство
Здесь мы хотим настроить рабочее пространство так, чтобы оно создавало статическую библиотеку при создании нашего приложения. Это делается путем редактирования схемы, используемой для нашего приложения.
- Убедитесь, что у вас выбрана схема, которая создаст ваше приложение.
- В раскрывающемся списке "Схема" выберите "Редактировать схему".
- Выберите Build вверху списка слева. Добавьте новую цель, нажав + на средней панели.
- Вы должны увидеть статическую библиотеку, отображаемую для библиотеки, которую вы пытаетесь связать. Выберите статическую библиотеку iOS.
- Нажмите "Выполнить" и "Архив". Это говорит о схеме компиляции библиотек для статической библиотеки всякий раз, когда вы создаете свое приложение.
- Перетащите статическую библиотеку над целью приложения. Это заставляет статические библиотеки компилироваться перед вашей целью приложения.
Начните использовать библиотеку
Теперь вы сможете импортировать статическую библиотеку, используя
import <LibraryName/LibraryName.h>
Этот метод избавляет от необходимости иметь разные пути заголовка пользователя для разных конфигураций, поэтому у вас не должно возникнуть проблем при компиляции архивов.
Почему это работает?
Все зависит от этого пути:
"$(PROJECT_TEMP_DIR)/../UninstalledProducts/include"
Поскольку мы настраиваем нашу статическую библиотеку для использования "Пропустить установку", скомпилированные файлы перемещаются в папку "UninstalledProjects" во временном каталоге сборки. Наш путь здесь также разрешается в папку "include", которую мы устанавливаем для нашей статической библиотеки и используем для нашего пути поиска в заголовке пользователя. Работая вместе, Xcode знает, где найти нашу библиотеку во время процесса компиляции. Поскольку этот временный каталог сборки существует для обеих конфигураций Debug и Release, вам нужен только один путь для Xcode для поиска статических библиотек.
Это была очень полезная тема. Исследуя мою собственную ситуацию, я обнаружил, что у 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 может быть недостаточным. Я публикую это здесь для тех, кто только начинает свой путь по пути статического библиотечного сада - это может быть лучшей отправной точкой для простых случаев.
http://developer.apple.com/library/ios/
Согласно документации Apple:
Ваша библиотека будет иметь один или несколько заголовочных файлов, которые клиенты этой библиотеки должны импортировать. Чтобы настроить, какие заголовки экспортируются на клиенты, выберите проект библиотеки, чтобы открыть редактор проектов, выберите цель библиотеки, чтобы открыть редактор целей, и перейдите на вкладку фаз сборки. Если у вашей целевой библиотеки есть фаза сборки "Копировать заголовки", вы должны удалить ее; Фазы сборки заголовков копирования не работают должным образом со статическими целями библиотеки при выполнении действия "Архивирования" в XCode.
Посмотрите на решение Jonah Wlliam (в середине пути) и модель GitHub (в комментариях) для понимания. http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/
Ни один из ответов выше не работал для меня на Xcode 7, но они дали мне хорошую идею, хотя. Для парней, борющихся с Xcode 7, я исправил это, добавив следующее в User Header Search Paths (включая кавычки)
"$(BUILT_PRODUCTS_DIR)/usr/local/include"
Изменить относительную часть URL usr/local/include
в соответствии с тем, что есть в настройке "Public Header Folder Path" статической библиотеки
Добавьте $(OBJROOT)/UninstalledProducts/ sharpPathToHeaders к путям поиска по заголовкам.
По какой-то причине рекурсивный флажок у меня не сработал, и мне пришлось добавить оставшуюся часть пути к расположению заголовков.
Под Навигатором Журнала в XCode (вкладка справа от навигатора точек останова) вы можете увидеть историю сборки. Если вы выберете фактическую ошибку сборки, вы можете развернуть ее детали, чтобы увидеть путь PATH setenv и убедиться, что путь к вашим заголовочным файлам там.
В моем случае в моей рабочей области было несколько статических библиотечных проектов, и один из них имел зависимость, включая заголовочные файлы с другим. Вопрос был с порядком застройки. На странице редактирования схемы в разделе "Построение" я снял флажок "Распараллелить" и упорядочил порядок целей в соответствии с зависимостями, и это решило проблему.
Добавьте следующий путь к своим путям поиска в заголовке пользователя:
$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts
Это проверено!
С риском показать, что я идиот... Я страдаю от того, что XCode отказывается найти мои файлы.h весь день.
Тогда я понял.
Поскольку я использовал "XCode 4", я "разумно" решил поместить все свои проекты в подпапки папки "Проекты XCode 4".
Эти пробелы в имени папки испортили XCode!
Переименование этой папки в "XCode_4_Projects" вернуло радость (и меньше ругательства) в мою жизнь.
Напомни мне еще раз, какой это год?
Возможно, кто-то может рассказать разработчикам Apple...
Ни один из этих ответов не работал для меня. Вот что сделал. Точно добавьте следующее (скопируйте и вставьте, включая двойные кавычки) в настройку сборки " Пути поиска заголовка пользователя":
"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include/"
Обратите внимание на добавление подкаталога "/include/" по сравнению с другими ответами. Как отмечали другие пользователи, "рекурсивная" опция, похоже, ничего не делает, поэтому вы можете ее проигнорировать.
Мой проект теперь может успешно архивироваться при импорте файлов заголовков статической библиотеки в следующей форме:
#import "LibraryName/HeaderFile.h"
Вам не нужно включать параметр " Всегда искать пути пользователя", если вы не включаете заголовки статической библиотеки в угловые скобки (#import <LibraryName/HeaderFile.h>
), но вам все равно не следует так поступать, если это не заголовок system/framework.
Это связанная проблема, которая привела меня к этому вопросу, поэтому я добавляю свое решение строго для документации / это может сэкономить еще несколько часов потливости
Файл DropboxSDK.h не найден
После нескольких дней попыток заставить VES скомпилировать для iOS я столкнулся с этой проблемой. DropboxSDK.h
был определенно доступен search headers
Я даже добавил это к framework headers
путь поиска, include
д .h
прямо и пошел на все виды большой длины, чтобы попытаться получить DropboxSDK.h
найденный.
Решение
EXPLICITY перетащите DropboxSDK.framework
файл в Xcode Project Navigation
и убедитесь, Copy Files if needed
проверено. Также убедитесь, что ваша цель проверена по мере необходимости.
Предупреждение
Установка явного расположения фреймворка в build phases
не работал для меня. Мне пришлось перетащить.framework в Xcode и убедиться, что файлы скопированы в мой проект.
# mbp2015 # xcode7 # ios9
Обновление: Xcode 9
Вышеупомянутые ответы не работали для меня, используя Xcode 9, но этот ответ работал отлично для меня. я добавил $(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/include
к моим "путям поиска заголовка", и XCode связал заголовок моей статической библиотеки без проблем.
При создании статической библиотеки.modulemap
иumbrella.h
генерируется дополнительно к.a
библиотека
Чтобы использовать статическую библиотеку Objective-C, вы должны
- Link Library — добавить библиотеку как зависимость
- установить пути поиска библиотеки
- установить пути поиска заголовков
Вот что решило ту же проблему для меня.
У меня есть цель приложения и цель расширения iMessage. Затем у меня было 2 SDK (мои собственные), с которыми связывает App Target.
Проблема заключалась в том, что моя цель iMessage также использовала 2 моих SDK (отдельные проекты), но она не связывалась с ними на этапах сборки -> Связать двоичные файлы с библиотеками. Мне пришлось добавить туда 2 SDK в iMessage Target, чтобы соответствовать цели моего приложения, и теперь она архивируется.
Итак, мораль этой истории такова: если у вас есть несколько целей, таких как расширения, убедитесь, что все ваши цели связаны с нужными им библиотеками. Он был в состоянии строить и развертывать на симуляторе и устройстве, но не архивировать.
Существуют различные сложные способы сделать это, и в этой теме предлагаются некоторые очень умные решения.
Основная проблема всех этих решений заключается в том, что они серьезно уменьшают переносимость вашей библиотеки.
- Каждый раз, когда вам нужно запустить новый проект с использованием вашей библиотеки и заархивировать его для iTunes, это ад конфигурации.
- Каждый раз, когда вам нужно поделиться своим проектом с вашей командой или клиентами, он может сломаться по любой причине (контекст, версия Xcode, что угодно,..)
Наконец-то я решил просто использовать фреймворки - всегда - как рекомендовано Apple (видео WWDC).
Это так просто и делает ту же самую работу в конце!
Еще одно довольно элегантное решение, которое, кажется, работает, - это использовать Private Cocoapods. Cocoapods выполняет всю работу по настройке, копирование заголовка и так далее.
Рамки рок!
Избавьте себя от неприятностей и сделайте это = создайте новую учетную запись пользователя на вашем Mac - откройте проект под новой учетной записью пользователя - все проблемы исчезнут. Экономьте свое время и сохраняйте здравомыслие. все эти занудные ответы не помогают!!
Удачи