Xcode 4 не может найти файлы общедоступных заголовков из зависимости статической библиотеки

91

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

  • 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, которая обеспечит доступность файлов заголовков для клиентов, использующих статическую библиотеку при попытке компиляции в качестве зависимости?

Ричард Стеллинг
источник
Может быть связано с именами путей. Пожалуйста, проверьте этот пост. [Статические библиотеки в Xcode 4] [1] [1]: stackoverflow.com/questions/6074576/static-libraries-in-xcode-4/…
Диего Марафетти

Ответы:

124

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

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

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

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

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

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

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

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

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

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

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

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

Резюме

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

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

Колин
источник
Как это связано с папкой DerivedData?
Ричард Стеллинг,
Обычные сборки идут в: DerivedData / WorkspaceName-hash / Build / Products / Debug-iphoneos / TargetName.app --- Архивные сборки идут в: DerivedData / WorkspaceName-hash / Build / Intermediates / ArchiveIntermediates / TargetName / BuildProductsPath / Release-iphoneos / TargetName.app
Колин
3
Для меня использование «$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts» с рекурсивным флажком не сработало. Как только я использовал "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts / <nameOfStaticLibrary>" без рекурсивного флага, у меня это сработало.
TPoschel
7
Обратите внимание, что ваш $ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts на самом деле $(TARGET_BUILD_DIR). Даже при архивировании. ;)
Паскаль
1
Для меня в Xcode 5: $ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts / include / ИМЯ БИБЛИОТЕКИ Я не установил ДА: всегда искать пути пользователя.
xarly
85

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

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

Мой метод таков:

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

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

Параметры проекта статической библиотеки

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

включить / LibraryName

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

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

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

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

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

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

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

Настроить рабочее пространство

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

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

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

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

import <LibraryName/LibraryName.h>

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

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

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

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

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

Gdavis
источник
3
Ты классный, чувак! Это действительно полезно и работает так, как вы описали.
neevek 09
1
классно. Куда мне послать цветы :)
Рамеш
1
После настройки некоторые из вас могут столкнуться с « ...] неопознанным селектором, отправленным в класс 0x ... ». Если да, попробуйте добавить это в Targets-> Project-> Build Settings-> Linking-> Other Linker
MkVal
Убедитесь, что пути поиска заголовков пользователей заключены в кавычки, если в них есть пробелы.
респект TheCode
Xcode 4.6.2 ничего не пишет в "$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / include" для меня. Есть идеи, что мне не хватает? Или поведение Xcode снова изменилось?
c roald
16

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

Связанный вопрос: «Лексический файл проблем или файл препроцессора не найден» в Xcode 4

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

Решения:

  1. Убедитесь, что "пути заголовков пользователей" верны
  2. Установите "Всегда искать пути пользователей" на ДА.
  3. Создайте групповой вызов «Индексирование заголовков» в своем проекте и перетащите заголовки в эту группу, НЕ добавляйте ни к каким целям при появлении запроса.
Ричард Стеллинг
источник
11
Еще один легко упускаемый из виду, но чрезвычайно важный шаг: убедитесь, что ваши пути поиска заключены в двойные кавычки, чтобы избежать пробелов. Я всегда забываю это делать.
Брэд
Спасибо @Brad, это действительно очень важное и полезное замечание.
Джулиан Д.
15

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

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

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

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

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

Майкл Дж.
источник
для тех, кто перешел по ссылке выше .. будьте осторожны: шаг, который просит вас удалить файлы фиктивных шаблонов при создании проекта библиотеки .. НЕ УДАЛЯЙТЕ файл * .pch .. в конечном итоге он будет вас преследовать + вышеуказанное совет не работает с категориями .. хотя для этого есть исправление (где-то видел)
abbood 04
Спасибо за ссылку на официальный подход Apple к созданию статических библиотек. Я начал с создания своей статической библиотеки, используя этот подход , но не смог архивировать. @abbood - В чем проблема с удалением сгенерированного pch файла?
Аугусто Каллехас
если вы удалите файл .pch .. проект просто не будет компилироваться .. (для архивирования или иным образом) ..
abbood
У меня это не работает. Когда я пытаюсь импортировать оператор с "", он не работает, мне нужен <>. Также во время архивирования он не может найти заголовки. Любые идеи?
user1010819
4

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

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

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

Дмарнель
источник
3

Взгляните на решение Джона Уллиама (в середине) и модель GitHub (в комментариях) для понимания. http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/

d1bru
источник
4
Хотя это может технически ответить на вопрос, было бы предпочтительнее , если бы вы включили в свой ответ основные части связанной статьи и предоставили ссылку для справки. Если этого не сделать, ответ окажется под угрозой из-за гниения ссылок.
jscs
2

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

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

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

Коллин
источник
Хорошее замечание о рекурсивном флажке, здесь та же проблема.
Codezy
Да, мне также пришлось указать конкретную подпапку, проверка рекурсии не сработала.
Оливер Пирмейн 01
Однако в итоге я использовал этот путь (просто потому, что он короче) «$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / SubProjectHeaders»
Оливер Пирмейн 01
2

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

"$(BUILT_PRODUCTS_DIR)/usr/local/include"

Измените относительную часть URL-адреса в usr/local/includeсоответствии с тем, что указано в настройке «Путь к общедоступной папке заголовка» статической библиотеки.

Evol Gate
источник
2

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

Вамши
источник
1

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

$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts

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

Yirenjun
источник
1

Рискуя показать, какой я идиот ... Я весь день страдал от того, что XCode отказывался найти мои файлы .h.

Потом я понял.

Поскольку я использовал «XCode 4», я «разумно» решил поместить все свои проекты во вложенные папки папки с названием « XCode 4 projects ».

Эти пробелы в имени папки испортили XCode!

Переименование этой папки в " XCode_4_Projects » вернуло в мою жизнь радость (и меньше ругательств).

Напомни мне еще раз, какой сейчас год?

Возможно, кто-нибудь сможет сказать разработчикам Apple ...

Майк Гледхилл
источник
1

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

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

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

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

#import "LibraryName/HeaderFile.h"

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

devios1
источник
0

Это связанная проблема, которая привела меня к этому вопросу, поэтому я добавляю свое решение строго для документации / это может сэкономить еще несколько часов пота.

Файл DropboxSDK.h не найден

После нескольких дней попыток скомпилировать VES для iOS я в конце концов столкнулся с этой проблемой. DropboxSDK.hопределенно в пределах досягаемости от search headersЯ даже добавил его в framework headersпути поиска, included .hнепосредственно и пошел на всякие большие длины , чтобы попытаться получить DropboxSDK.hнайдены.

Решение

EXPLICITY перетащите DropboxSDK.frameworkфайл в Xcode Project Navigationи убедитесь, что Copy Files if neededон отмечен. Также убедитесь, что ваша цель отмечена при необходимости.

Предупреждение

Установка явного местоположения фреймворка build phasesу меня не сработала. Мне пришлось перетащить .framework в Xcode и убедиться, что файлы скопированы в мой проект.

# mbp2015 # xcode7 # ios9

Джексонкр
источник
0

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

Основная проблема всех этих решений заключается в том, что они серьезно снижают переносимость вашей библиотеки.

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

В конце концов, я решил просто использовать фреймворки - всегда - в соответствии с рекомендациями Apple (WWDC Videos).

Это так проще и в конце выполняет ту же работу!

Еще одно довольно элегантное решение, которое, кажется, работает, - использовать Private Cocoapods. Cocoapods выполняет всю работу по настройке, копированию заголовка и так далее.

Рамки молодцы!

лось
источник
1
Где это установить? simply use frameworks - always -
Нил Фолкнер
Он нигде не установлен. Это просто архитектурный выбор. Фреймворки - это «современные библиотеки», которые намного проще связывать и управлять ими. На момент написания этого сообщения swift все еще не позволяет создавать двоичные библиотеки.
Moose
0

Вот что решило для меня ту же проблему.

У меня есть цель приложения и цель расширения iMessage. Затем у меня было 2 SDK (мои собственные), на которые ссылается App Target.

Проблема заключалась в том, что моя цель iMessage также использовала 2 моих SDK (отдельные проекты), но не связывалась с ними на этапах сборки -> Связать двоичный файл с библиотеками. Мне пришлось добавить там два моих SDK в iMessage Target, чтобы они соответствовали моей цели приложения, и теперь он архивируется.

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

FranticRock
источник
0

Обновление: Xcode 9

Приведенные выше ответы не сработали для меня с использованием Xcode 9, но этот ответ отлично сработал для меня. Я добавил $(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/includeв свои «Пути поиска заголовков», и Xcode без проблем связал заголовок моей статической библиотеки.

Мохаммед Абдуллатиф
источник
-18

Избавьте себя от неприятностей и сделайте это = создайте новую учетную запись пользователя на своем Mac - откройте проект под новой учетной записью пользователя - все проблемы исчезнут. Экономьте свое время и сохраняйте рассудок. все эти ботанические ответы не помогают !!

Удачи

Максимум
источник