Давайте рассмотрим, как я пытался добавить динамическую структуру в свой инструмент командной строки, и обсудим, что пошло не так на каждом этапе этого пути.
Шаг 1. Добавьте его в раздел «Связанные платформы и библиотеки».
Вот что происходит, когда вы запускаете приложение:
dyld: Library not loaded: @rpath/libswiftAppKit.dylib Referenced from: /Users/seanberry/Library/Developer/Xcode/DerivedData/TestCommandLineTool-fnrmhjvjmugvqueaqvbklzwhqvuv/Build/Products/Debug/ThirdParty.framework/Versions/A/ThirdParty Reason: image not found
ThirdParty.framework
пытается найти libswiftAppKit.dylib
(который является частью стандартных библиотек Swift) в каталоге @rpath
.
Мы можем увидеть, как ThirdParty.framework
определяет @rpath
, запустив
$ oTool -l ThirdParty.framework/Versions/Current/ThirdParty Load command 27 cmd LC_RPATH cmdsize 48 path @executable_path/../Frameworks (offset 12) Load command 28 cmd LC_RPATH cmdsize 40 path @loader_path/Frameworks (offset 12)
Хорошо стреляйте. Они не имеют отношения к нашему инструменту командной строки. У нас нет папок с именами / Frameworks или ../Frameworks. Почему он ищет там стандартные библиотеки Swift?
Потому что он создан для приложений iOS и Mac. Вот структура каталогов внутри приложения Mac:
Это объясняет path @executable_path/../Frameworks
А для iOS структура каталогов внутри приложения следующая:
И это объясняет path @loader_path/Frameworks (offset 12)
Но как насчет нас, скромных разработчиков инструментов командной строки? Стандартные библиотеки Swift статически связаны внутри нашего исполняемого файла, но наши сторонние платформы не могут их найти. К сожалению, они не хранятся в стандартном месте на каждом Mac. Разработчики могут получить к ним доступ, скрытый внутри Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx
(но, пожалуйста, не требуйте от пользователей установки Xcode).
Так что же нам делать? Стандартная практика, которую я видел, - это создание пользовательского фреймворка для вашего проекта, импорт в него всех ваших зависимостей, а затем также копирование быстрых стандартных библиотек.
Шаг 2. Создайте собственный фреймворк и скопируйте стандартные библиотеки Swift.
Идеально! Теперь давайте запустим наш инструмент командной строки ...
objc[2335]: Class _TtC8Dispatch16DispatchWorkItem is implemented in both /Users/seanberry/Library/Developer/Xcode/DerivedData/TestCommandLineTool-fnrmhjvjmugvqueaqvbklzwhqvuv/Build/Products/Debug/FirstParty.framework/Versions/A/Frameworks/libswiftDispatch.dylib (0x1016c8530) and /Users/seanberry/Library/Developer/Xcode/DerivedData/TestCommandLineTool-fnrmhjvjmugvqueaqvbklzwhqvuv/Build/Products/Debug/TestCommandLineTool (0x1005c7698). One of the two will be used. Which one is undefined. REPEAT THE ABOVE ERROR IN 20 DIFFERENT WAYS
Теперь ваше приложение видит две разные копии стандартных библиотек Swift: те, которые статически связаны внутри вашего исполняемого файла, и те, которые находятся в папке / Frameworks.
Отсюда есть два решения.
Шаг 3 (вариант A): вместо этого создайте приложение для Mac и извлеките исполняемый файл.
Я исследовал известные инструменты командной строки Carthage и SwiftLint, чтобы увидеть, как они справляются с этой проблемой. Оказывается, они не настроены как инструменты командной строки! Это приложения для Mac! Почему? Потому что приложение Mac не связывает статически стандартные библиотеки. Они развертываются как инструменты командной строки, добавляя этап выполнения, который извлекает исполняемый файл из пакета приложения.
#!/bin/bash ## Extracts the carthage CLI tool from its application bundle. Meant to be run # as part of an Xcode Run Script build phase. cp -v "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}" "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_NAME}"
Вы можете пойти дальше и сделать это так, без проблем. Но я нашел другой способ обойти эту проблему.
Шаг 3 (вариант B): отключить статическое связывание
Добавьте их в свои пользовательские настройки сборки:
SWIFT_FORCE_DYNAMIC_LINK_STDLIB YES SWIFT_FORCE_STATIC_LINK_STDLIB NO
Это заставит ваш исполняемый файл динамически связывать все библиотеки. Обязательно сообщите Xcode, где их найти, добавив каталог фреймворка в «Пути поиска пути выполнения».
@executable_path/FirstParty.framework/Versions/Current/Frameworks
Удачи вам с вашим инструментом командной строки!
Шон пытается заставить Xcode скомпилировать в Livefront