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


Може бути пов’язано з іменами шляхів. Pl перевірити цей пост. [Статичні бібліотеки в Xcode 4] [1] [1]: stackoverflow.com/questions/6074576/static-libraries-in-xcode-4 / ...
Дієго Marafetti

Відповіді:


124

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

Коротка відповідь

Додайте такий шлях до своїх шляхів пошуку в заголовку користувача

"$ (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", що працює для збірок архівів.


Як це пов’язано з папкою 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

84

Я зіткнувся з цією ж проблемою при розробці власної статичної бібліотеки, і хоча відповідь Коліна була дуже корисною, мені довелося трохи її змінити, щоб працювати послідовно і просто під час запуску та архівування проектів під Xcode 4 за допомогою робочої області.

Що відрізняється від мого методу, так це те, що ви можете використовувати один шлях до заголовка користувача для всіх своїх конфігурацій збірки.

Мій метод такий:

Створіть робочу область

  1. У розділі Xcode 4 перейдіть до Файл, Створити, Робоча область.
  2. З Finder ви можете перетягнути проекти .xcodeproj як для статичної бібліотеки, яку ви хочете використовувати, так і для нової програми, яку ви створюєте, яка використовує бібліотеку. Докладнішу інформацію про налаштування робочих областей див. У Документах Apple: https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Workspace.html

Налаштування проекту статичної бібліотеки

  1. Переконайтесь, що всі заголовки статичної бібліотеки налаштовано на копіювання у "Загальнодоступне". Це робиться в налаштуваннях для цілі статичної бібліотеки> Фази побудови. На етапі "Копіювати заголовки" переконайтеся, що всі ваші заголовки знаходяться в розділі "Загальнодоступний".
  2. Далі перейдіть до Налаштування побудови, знайдіть "Шлях до папки загальних заголовків" і введіть шлях до вашої бібліотеки. Я вирішив використовувати це:

включити / LibraryName

Я прийняв це для використання з RestKit і виявив, що він найкраще працює з усіма моїми статичними бібліотеками. Що це робить, це говорить Xcode скопіювати всі заголовки, які ми перемістили до розділу "Загальнодоступні" заголовки на кроці 1, у папку, яку ми вказали тут, яка знаходиться в папці Виведені дані під час створення. Як і у RestKit, мені подобається використовувати одну папку "включити", щоб містити кожну статичну бібліотеку, яку я використовую в проекті.

Мені також не подобається використовувати тут макроси, тому що це дозволить нам використовувати шлях пошуку одного заголовка користувача пізніше, коли ми налаштовуємо проект за допомогою статичної бібліотеки.

  1. Знайдіть "Пропустити встановлення" та переконайтеся, що для цього встановлено ТАК.

Налаштування проекту за допомогою статичної бібліотеки

  1. Додайте статичну бібліотеку як фреймворк у розділі Фази побудови> Зв’язати двійковий файл з бібліотеками та додайте файл libLibraryName.a для будь-якої статичної бібліотеки, яку ви хочете використовувати.
  2. Далі переконайтеся, що проект налаштований на пошук шляхів пошуку користувачів. Це робиться в Налаштування побудови> Завжди шукати шляхи користувача та переконайтеся, що для нього встановлено ТАК.
  3. У тій же області знайдіть шляхи пошуку заголовка користувача та додайте:

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

Це вказує Xcode шукати статичні бібліотеки в проміжній папці збірки, яку Xcode створює під час процесу збірки. Тут ми маємо папку "включити", яку ми використовуємо для розташування наших статичних бібліотек, які ми встановили на кроці 2 для параметрів проекту статичної бібліотеки. Це найважливіший крок у отриманні Xcode для правильного пошуку ваших статичних бібліотек.

Налаштуйте робочу область

Тут ми хочемо налаштувати робочу область так, щоб вона створювала статичну бібліотеку, коли ми будуємо наш додаток. Це робиться шляхом редагування схеми, яка використовується для нашого додатка.

  1. Переконайтеся, що вибрана схема, яка створить вашу програму.
  2. У спадному меню схеми виберіть Редагувати схему.
  3. Виберіть Побудувати у верхній частині списку зліва. Додайте нову ціль, натиснувши + на середній панелі.
  4. Ви повинні побачити, як статична бібліотека відображається для бібліотеки, яку ви намагаєтеся зв’язати. Виберіть статичну бібліотеку iOS.
  5. Клацніть на Запустити та Архівувати. Це повідомляє схемі компіляції бібліотек для статичної бібліотеки щоразу, коли ви створюєте програму.
  6. Перетягніть статичну бібліотеку над цільовою програмою. Це робить статичні бібліотеки компіляцією перед цільовим додатком.

Почніть користуватися бібліотекою

Тепер ви зможете імпортувати вашу статичну бібліотеку за допомогою

import <LibraryName/LibraryName.h>

Цей метод вирішує клопоти з необхідністю мати різні шляхи заголовків користувача для різних конфігурацій, тому у вас не повинно виникнути проблем зі складанням архівів.

Чому це працює?

Все залежить від цього шляху:

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

Оскільки ми налаштовуємо нашу статичну бібліотеку на використання "Пропустити інсталяцію", скомпільовані файли переміщуються до папки "UninstalledProjects" у тимчасовій директорії збірки. Наш шлях також вирішує папку "include", яку ми налаштували для нашої статичної бібліотеки та використовуємо для нашого шляху пошуку в заголовках користувача. Вони працюють разом, щоб Xcode знав, де знайти нашу бібліотеку під час процесу компіляції. Оскільки цей тимчасовий каталог побудови існує як для налагодження, так і для випуску, вам потрібен лише один шлях для Xcode для пошуку статичних бібліотек.


3
Ти чудовий, чоловіче! Це дійсно корисно, і це працює так, як ви описали.
neevek

1
дивовижний. Куди я пошлю квіти :)
Рамеш,

1
Після цього деякі з вас можуть зіткнутися з " ...] невпізнаним селектором, надісланим до класу 0x ... ". Якщо ви це зробите, спробуйте додати це до цілей вашого проекту-> Проект-> Налаштування збірки-> Зв'язування-> Інші прапори зв'язування
MkVal

Переконайтеся, що шляхи пошуку заголовка користувача вказані в лапках, якщо вони мають пробіли.
respectTheCode

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

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


для тих, хто переходить за вищевказаним посиланням .. будьте обережні: крок, який вимагає видалити фіктивні файли шаблонів під час створення проекту бібліотеки .. НЕ ВИДАЛЯЙТЕ файл * .pch .. це врешті-решт переслідує вас + вище порада не працює з категоріями .. хоча для цього є виправлення (десь це бачив)
abbood

Дякуємо за надання посилання на офіційний підхід Apple до створення статичних бібліотек. Я почав зі створення своєї статичної бібліотеки, використовуючи цей підхід , але не зміг архівувати. @abbood - У чому проблема видалення генерованого файлу pch?
augusto callejas

якщо ви видалите файл .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/


4
Хоча це технічно може дати відповідь на запитання, вам було б краще включити до своєї відповіді основні частини пов'язаної статті та надати посилання для довідки. Якщо цього не зробити, відповідь ризикує через гниття посилань.
jscs

2

Додайте $ (OBJROOT) / UninstalledProducts / absolutePathToHeaders до шляхів пошуку заголовків.

З якоїсь причини рекурсивний прапорець для мене не працював, і мені довелося додати решту шляху туди, де розташовані заголовки.

У розділі Навігатор журналу в Xcode (вкладка праворуч від навігатора точок розриву) ви можете переглянути історію збірки. Якщо ви вибрали фактичну помилку збірки, ви можете розгорнути її деталі, щоб побачити setenv PATH та перевірити, чи є шлях до ваших файлів заголовків там.


Хороша нотатка про рекурсивний прапорець, те саме питання тут.
Codezy

Так, мені також довелося вказати конкретну підпапку, перевірка рекурсивної роботи не спрацювала.
Олівер Пірмен

Я все-таки використав цей шлях (просто тому, що він коротший) "$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / SubProjectHeaders"
Олівер Пірмен

2

У моєму випадку у моєму робочому просторі було кілька проектів статичної бібліотеки, і один із них має залежність, включаючи файли заголовків з іншим. Справа була в порядку будівництва. На сторінці редагування схеми в розділі "Збірка" я відмінив паралелізацію і впорядкував порядок цілей відповідно до залежностей, і це вирішено проблемою


1

Додайте такий шлях до своїх шляхів пошуку в заголовку користувача:

$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts

Це перевірено!


1

Ризикуючи показати, який я ідіот ... Я весь день страждаю від того, що XCode відмовляється знаходити свої .h-файли.

Тоді я зрозумів.

Оскільки я використовував "XCode 4", я "розумно" вирішив розмістити всі свої проекти в підпапках папки " XCode 4 projects ".

Ці пробіли в назві папки переплутали XCode!

Перейменування цієї папки в " XCode_4_Projects " повернуло радість (і менше лайку) у моє життя.

Знову нагадайте, який це рік?

Можливо, хтось міг сказати розробникам Apple ...


1

Жодна з цих відповідей не спрацювала для мене. Ось що зробили. Додайте наступне точно (скопіюйте та вставте, включаючи подвійні лапки) до налаштування побудови шляхів пошуку заголовків користувача :

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

Зверніть увагу на додавання підкаталогу "/ include /" порівняно з іншими відповідями. Як зазначали інші користувачі, "рекурсивний" варіант, здається, нічого не робить, тому ви можете ігнорувати його.

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

#import "LibraryName/HeaderFile.h"

Вам не потрібно вмикати налаштування Завжди шукати шляхи користувачів, якщо ви не включаєте заголовки статичної бібліотеки з кутовими дужками ( #import <LibraryName/HeaderFile.h>), але насправді не слід робити це так, якщо це не заголовок системи / фреймворку.


1

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

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

Змініть відносну частину URL-адреси usr/local/includeвідповідно до того, що є в налаштуванні "Шлях загальної папки заголовка" статичної бібліотеки


0

Це пов’язана проблема, яка призвела мене до цього питання, тому я додаю своє рішення суто для документації / це може заощадити ще одну годину пітливості

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

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

Рішення

ПРОСТОТА перетягніть DropboxSDK.frameworkфайл у Xcode Project Navigationта переконайтеся, що Copy Files if neededвстановлений прапорець. Також переконайтеся, що ціль перевіряється за необхідності.

Увага

Встановлення явного розташування фреймворку в build phasesмені не спрацювало. Мені довелося перетягнути .framework в Xcode і переконатися, що файли скопійовані до мого проекту.

# mbp2015 # xcode7 # ios9


0

Для цього існують різні складні способи, і в цій темі пропонуються деякі дуже розумні рішення.

Основна проблема всіх цих рішень полягає в тому, що це серйозно знижує портативність вашої бібліотеки.

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

Нарешті, я вибрав просто використовувати фреймворки - завжди - як рекомендує Apple (Відео WWDC).

Це так простіше і робить ту ж роботу в кінці!

Ще одне цілком елегантне рішення, яке, здається, працює, - використання приватних кокопод. Cocoapods виконує всю роботу з налаштування, копіювання заголовка тощо.

Каркаси рок!


1
Де ви це встановлюєте? simply use frameworks - always -
Ніл Фолкнер

Це ніде не встановлено. Це просто архітектурний вибір. Фреймворки - це «сучасні бібліотеки», з якими набагато простіше зв’язати та керувати ними. На момент цього повідомлення swift все ще не дозволяє створювати двійкові бібліотеки.
Moose

0

Ось що вирішило для мене ту ж проблему.

У мене є ціль програми та ціль розширення iMessage. Потім у мене було 2 SDK (власний), на які посилається App Target.

Проблема полягала в тому, що моя ціль iMessage також використовувала 2 мої SDK (окремі проекти), але вона не зв’язувала їх із фазами побудови -> Пов’язати двійковий файл з бібліотеками. Мені довелося додати свої 2 SDK до цільової iMessage, щоб відповідати моїй цілі програми, і тепер вона архівується.

Тож мораль історії така: якщо у вас є декілька цілей, таких як розширення, переконайтеся, що всі ваші цілі пов’язані з потрібними бібліотеками. Він зміг побудувати та розгорнути на симуляторі та пристрої, але не архівувати.


0

Оновлення: Xcode 9

Наведені вище відповіді не працювали для мене за допомогою Xcode 9, але ця відповідь для мене спрацювала ідеально. Я додав $(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/includeдо свого "Шляху пошуку заголовків", і Xcode без проблем зв'язав заголовок моєї статичної бібліотеки.


-18

Позбавте себе від проблем і зробіть це = створіть новий обліковий запис користувача на своєму Mac - відкрийте проект під новим обліковим записом користувача - усі проблеми зникають. Економте свій час і зберігайте свою розсудливість. всі ці нерозумні відповіді не допомагають !!

Щасти

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.