Комментарии 12
Где же вы были 5 лет назад, когда я очень хотел нагуглить такую статью))
5 лет назад код на C++ без танцев с бубном собирался просто включением соответствующих файлов на C++ в ObjC-проект с изменением их расширения на .mm
. Или даже и переименовывать не надо было, не помню уже -- старый стал. Полагаю, что и сейчас этот способ работает.
Этот же совет можно использовать и для работы со Swift ниже версии 5.9.
Ох, уж эти зуммеры, раз и навсегда похоронившие ObjC ^.^
если бы это было 5 лет назад, нам бы нечего было написать, как правильно в комментариях заметили, таких проблем не было :)
Ошибку, связанную с нелегальностью такой сборки, XCode выдаст только при попытки опубликовать сборку такого приложения.
я бы уточнил, что проблема будет только при заливке в аппсторконнект, при этом на макос приложения это ограничение не распространяется. А если распространять просто ipa файл всем желающим, то этого ограничения тоже нет.
Собрать модуль на XCode 14 под минимальный таргет 14 не удалось, поэтому первым шагом потребовалось установить XCode 12
очень странно... И как раз было бы интересно посмотреть на ошибку и изучить ее причину, а не использовать подобные «хаки» (понятно, что тогда могло не быть времени разбираться, но уж сколько времени прошло с тех пор). Да и почему хкод 12, а не 13? А что насчет современного хкода 15 (и даже беты 16)?
После копирования SDK поменяем свойство
MinimumSDKVersion
а зачем это делать, если в итоге мы все равно через vtool
задаем нужную версию?
И кстати получить версию сдк и платформы также можно через vtool
(вместо otool).
Так мы создали TensorflowLiteFramework.framework, который можем использовать в проекте с минимальным таргетом iOS 14.0.
но ради чего, если никто не мешает использовать библиотеки с меньшим деплоймент таргетом?..
Теперь сконфигурируем сборку с помощью Cmake
а зачем нам смаке, если в итоге все равно используется хкод генератор? Что мешало просто создать хкод проект?
cmake ..
тут стоит указать, что предполагается, что мы находимся в папке сборки, которая лежит внутри корня исходников. Но предпочтительнее:
так не делать и держать папку сборки снаружи папки исходников
явно указывать каталоги исходников и сборки. В данном случае мы бы написали
cmake -S .. -B .
, хотя более традиционной формой является конфигурация из папки исходников:cmake -S . -B build
Запускаем в XCode проект MyFramework.xcodeproj и внутри XCode собираем фреймворк под целевую платформу
до этого мы все собирали в терминале, а теперь внезапно надо открывать иде :) Собрать хкод проект можно через xcodebuild или fastlane.
TensorflowLiteFramework.podspec
не очень понятно зачем явно указывать CLANG_CXX_LIBRARY
, если она уже сто лет как установлена в libc++ по умолчанию.
s.dependency 'TensorflowLiteFramework'
подождите, а разве MyFramework
не зависит от TensorflowLiteFramework
, выступая оберткой над ней? В таком случае зависимость от TensorflowLiteFramework
должна быть указана в подспеке MyFramework
. Если же основной фреймворк также напрямую зависит от TensorflowLiteFramework
(вызывает что-то оттуда в обход обертки), тогда да, следует указать эту зависимость в основном фреймворке.
Я понимаю, что оно работает и так, но лучше все делать аккуратно :)
P.S. Вопросики к колонке Архитектура для симуляторов у картинки под спойлером: какие-то там очень странные значения написаны. Они ж должны практически совпадать со значениями в строке Макбук за исключением того, что для симуляторов iOS < 11 использовалась i386 (интел 32-бит).
я бы уточнил, что проблема будет только при заливке в аппсторконнект, при этом на макос приложения это ограничение не распространяется. А если распространять просто ipa файл всем желающим, то этого ограничения тоже нет.
Совершенно верное замечание. Но в нашем кейсе мы пытались сбилдить именно под iOS и распоcтранять, используя AppStore. Еще можно добавить, что аналогичная ситуация (с ошибкой на этапе аплоада) возможна, если попытаться отправить сборку, содержащую фреймворк с embeded фреймворком, не смотря на то, что сама ipa будет работать корректно
очень странно... И как раз было бы интересно посмотреть на ошибку и изучить ее причину, а не использовать подобные «хаки» (понятно, что тогда могло не быть времени разбираться, но уж сколько времени прошло с тех пор). Да и почему хкод 12, а не 13? А что насчет современного хкода 15 (и даже беты 16)?
Да, это действительно была очень странная ситуация. По идее XCode 14 (а в теории и 15, 16) должны без проблем собирать, используя iOS SDK 14.0. Самой ошибки не было – фреймворк просто гордо работал только от 16 iOS, что не соответствовало нашим требованиям. Эта проблема съела львиную долю времени и мы были рады найти хоть какой-то хак, а суть проблемы до сих пор остается непонятной.
Причем у нас есть уверенность, что правильное решение элементарное, на уровне указания флага или лишней настройки, но найти его не удалось. Будем рады, если кто-нибудь прольет свет на эту ситуацию.
XCode 15 стали использовать лишь недавно. XCode 16 даже не щупали
но ради чего, если никто не мешает использовать библиотеки с меньшим деплоймент таргетом?..
А у нас получалась именно библиотека, что с большим таргетом. Проект на 14, а получавшаяся либа работала только от 16
а зачем нам смаке, если в итоге все равно используется хкод генератор? Что мешало просто создать хкод проект?
Можно идти двумя путями, получится в обоих случаях. Мы выбрали путь CMake. Если коротко в чем разница:
СMake требует разобраться и написать правильную инструкцию сборки
XCode требует разобраться, как правильно прибить все хедеры и победить проблемы в стиле "framework not found" для зависимости tensorflow
Особо разницы никакой, но нам было проще сделать CMakeLists.txt
тут стоит указать, что предполагается, что мы находимся в папке сборки, которая лежит внутри корня исходников. Но предпочтительнее:
так не делать и держать папку сборки снаружи папки исходников
явно указывать каталоги исходников и сборки. В данном случае мы бы написали
cmake -S .. -B .
, хотя более традиционной формой является конфигурация из папки исходников:cmake -S . -B build
Справедливое замечание. Мы указывали пути до исходников в явном виде. В статье просто этот момент опустили в пользу читаемости
до этого мы все собирали в терминале, а теперь внезапно надо открывать иде :) Собрать хкод проект можно через xcodebuild или fastlane.
Здесь мы тоже немного разнообразили статью. Чтобы не только запуск команд был. xcodebuild прекрасно делает тоже самое, что и XCode
не очень понятно зачем явно указывать
CLANG_CXX_LIBRARY
, если она уже сто лет как установлена в libc++ по умолчанию.
Не знали об этом, примем к сведению. Мы нашли рекомендации указывать это явно и решили, что стоит явно указать какой стандарт нам необходим
подождите, а разве
MyFramework
не зависит отTensorflowLiteFramework
, выступая оберткой над ней? В таком случае зависимость отTensorflowLiteFramework
должна быть указана в подспекеMyFramework
. Если же основной фреймворк также напрямую зависит отTensorflowLiteFramework
(вызывает что-то оттуда в обход обертки), тогда да, следует указать эту зависимость в основном фреймворке.Я понимаю, что оно работает и так, но лучше все делать аккуратно :)
Да. У нас зависимость от TensorflowLiteFramework, описана явно в основном модуле нашего SDK. Но ваше замечание абсолютно справедливо. Оно действительно работает и так, но стоит явно указывать эту зависимость. А то не всем будет очевидно, что и от чего зависит
P.S. Вопросики к колонке Архитектура для симуляторов у картинки под спойлером: какие-то там очень странные значения написаны. Они ж должны практически совпадать со значениями в строке Макбук за исключением того, что для симуляторов iOS < 11 использовалась i386 (интел 32-бит).
Мы допустили ошибку в этой таблице, спасибо, что подсветили. Конечно же правильные значения тут будут amr64, x86_64 и старенький совсем i386. Скорректировали ее в статье
По идее XCode 14 (а в теории и 15, 16) должны без проблем собирать, используя iOS SDK 14.0. Самой ошибки не было – фреймворк просто гордо работал только от 16 iOS, что не соответствовало нашим требованиям. Эта проблема съела львиную долю времени и мы были рады найти хоть какой-то хак, а суть проблемы до сих пор остается непонятной.
Причем у нас есть уверенность, что правильное решение элементарное, на уровне указания флага или лишней настройки, но найти его не удалось. Будем рады, если кто-нибудь прольет свет на эту ситуацию.
Теперь проблема начинает проясняться. Хкод 14.х поставляется с 16.х сдк, а если при сборке не указывать никакой деплоймент таргет, то будет использоваться версия сдк, вот и получается, что у вас минимальная версия проставлялась 16.х. Неужели вы не пробовали задать нужный вам деплоймент таргет и даже не смотрели в итоговые флаги компиляции?
Особо разницы никакой, но нам было проще сделать CMakeLists.txt
и добавили еще одну сущность :) плюс дополнительная нагрузка на того, кто будет это сопровождать в будущем.
---
Кстати, можно поступить немного хитрее. Описать свою обертку в виде подспека, и уже использовать его как единый источник правды для построения бинарника. Тогда получится, что есть некая шаблонная часть подспека, которая будет единой как для "исходного" подспека (из которого будем строить бинарь), так и для "бинарного" (который будет распространяться для интеграции), ну и каждый из подспеков добавляет что-то свое. "Исходный" подспек может использоваться для демо-проекта, который будет выступать как песочница / проверка библиотеки на "здравый смысл". А при выполнении pod install для демо-проекта у нас как раз и появится хкод проект для построения фреймворка.
(конечно, от шаблонов можно отказаться и просто не забывать вносить правки в оба файла одновременно)
Теперь проблема начинает проясняться. Хкод 14.х поставляется с 16.х сдк, а если при сборке не указывать никакой деплоймент таргет, то будет использоваться версия сдк, вот и получается, что у вас минимальная версия проставлялась 16.х. Неужели вы не пробовали задать нужный вам деплоймент таргет и даже не смотрели в итоговые флаги компиляции?
В этом и была проблема, что мы не смогли его использовать (дефолтный iOS SDK). Какие бы мы опции не пробовали, в итоге всегда собиралось под дефолтный iOS 16.0 SDK. Перепробовали все, что можно, перед тем, как ставить xCode, у которого дефолт именно iOS 14.0
и добавили еще одну сущность :) плюс дополнительная нагрузка на того, кто будет это сопровождать в будущем.
Да, мы осознавали это при выборе решения
Кстати, можно поступить немного хитрее. Описать свою обертку в виде подспека, и уже использовать его как единый источник правды для построения бинарника. Тогда получится, что есть некая шаблонная часть подспека, которая будет единой как для "исходного" подспека (из которого будем строить бинарь), так и для "бинарного" (который будет распространяться для интеграции), ну и каждый из подспеков добавляет что-то свое. "Исходный" подспек может использоваться для демо-проекта, который будет выступать как песочница / проверка библиотеки на "здравый смысл". А при выполнении pod install для демо-проекта у нас как раз и появится хкод проект для построения фреймворка.
(конечно, от шаблонов можно отказаться и просто не забывать вносить правки в оба файла одновременно)
Спасибо за классную идею! Неплохой способ все упаковать и распространять, забрали себе в toDo :)
В этом и была проблема, что мы не смогли его использовать (дефолтный iOS SDK). Какие бы мы опции не пробовали, в итоге всегда собиралось под дефолтный iOS 16.0 SDK. Перепробовали все, что можно, перед тем, как ставить xCode, у которого дефолт именно iOS 14.0
Вообще, звучит как баг библиотеки. Но уже стало интересно что ж там за магия такая, попробую сам её собрать и сообщу о результате.
не заметил никаких проблем с установкой нужной deployment target, в чем у вас там была загвоздка — непонятно...
не сразу нашел документацию на построение из исходников, но в ней оказалась полезная ссылка на .bazelrc файл. В нем достаточно легко найти способ указания деплоймент таргета для Макос (--macos_minimum_os=11.0
), тогда можно даже чисто наугад предположить как должна называться настройка для iOS.
Построим свежий релиз (2.17) командой, указанной в статье, получим ожидаемый результат (использовал хкод 15.4):
> vtool -show-build bazel-bin/tensorflow/lite/libtensorflowlite.dylib
bazel-bin/tensorflow/lite/libtensorflowlite.dylib:
Load command 10
cmd LC_BUILD_VERSION
cmdsize 32
platform IOS
minos 17.5
sdk 17.5
ntools 1
tool LD
version 1053.12
А теперь передадим флажок --ios_minimum_os 15.0
:
> vtool -show-build bazel-bin/tensorflow/lite/libtensorflowlite.dylib
bazel-bin/tensorflow/lite/libtensorflowlite.dylib:
Load command 10
cmd LC_BUILD_VERSION
cmdsize 32
platform IOS
minos 15.0
sdk 17.5
ntools 1
tool LD
version 1053.12
Хотел также проверить на релизе 2.12, который указан в статье, но там при сборке что-то пошло не так, видимо проблема с питоном 3.12: ModuleNotFoundError: No module named 'distutils'.
Мы пробовали использовать инструкции из этой документации и ничего особо не получалось. Не могу точно вспомнить, в чем конкретно была причина, но у нас не получилась. Оглядываясь сегодня, понимаю, что стоит повнимательнее посмотреть, как там через Bazel
это собирается и решается проблема минимального iOS таргета. Спасибо за ссылку, видимо стоит в конце статьи собрать полезные материалы :)
-
Работа с кодом на C++ в Swift