Статическая библиотека с использованием фреймворков в конкретных проектах - PullRequest
19 голосов
/ 15 мая 2011

Я создал статическую библиотеку, содержащую все мои общие классы. Некоторые из этих классов используют фреймворки.

Теперь у меня есть два проекта, один из которых использует некоторые классы, использующие фреймворки, и другой, который не использует ни один из классов, использующих фреймворки.

Потому что статические библиотеки не поддерживают в том числе фреймворки (если я прав). Я должен включить фреймворки в проект, который их использует. Но когда я компилирую проект, который не использует ни один из классов-фреймворков, компилятор ломается, потому что он все еще требует фреймворков. Теперь я знаю, что он пытается скомпилировать все (неиспользуемые) классы из библиотеки, потому что я использую флаг компоновщика '-ObjC' для предотвращения ошибок 'нераспознанного селектора'.

Кто-нибудь знает, как скомпилировать только необходимые исходные файлы для проекта? И не допустить включения всех фреймворков во все проекты, использующие мою статическую библиотеку?

Ответы [ 4 ]

15 голосов
/ 23 мая 2011

Прежде всего, вы правы в том, что статическая библиотека не может включать в себя ни фреймворк, ни другие статические библиотеки, это просто набор всех объектных файлов (* .obj), которые составляют эту конкретную статическую библиотеку.

Кто-нибудь знает, как скомпилировать только необходимые исходные файлы для проекта?

Компоновщик по умолчанию будет связывать только в объектных файлах из статической библиотеки, которые содержат символы, на которые ссылается приложение. Таким образом, если у вас есть два файла a.m и b.m в вашей статической библиотеке и вы используете только символы из a.m в своей основной программе, то b.o (объектный файл, сгенерированный из b.c) не появится в ваш окончательный исполняемый файл. В качестве дополнительного случая, если b.m использует функцию / класс c, которая только объявлена ​​(не реализована), вы не получите никаких ошибок компоновщика. Как только вы включите некоторые символы из b.m в свою программу, b.o также будет связан, и вы получите ошибки компоновщика из-за отсутствующей реализации c.

Если вы хотите, чтобы этот вид выделения происходил на уровне символа, а не на уровне детализации на уровне объекта, включите очистку мертвого кода в XCode. Это соответствует опции gcc -Wl, -dead_strip (= опция компоновщика -dead_strip в информационной панели настроек сборки для вашего проекта). Это обеспечит дальнейшую оптимизацию.

В вашем случае, однако, как вы правильно сказали, именно использование компоновщика "-ObjC" побеждает этот механизм. Так что это на самом деле зависит от вас. Если вы уберете флаг -Objc, вы получите бесплатное поведение, в то же время потеряв более строгую проверку селекторов.

И запретить включение всех фреймворков во все проекты, использующие мою статическую библиотеку?

Xcode / GCC поддерживают опцию связывания, которая называется " слабое связывание ", которая позволяет лениво загружать фреймворк или статическую библиотеку, т. Е. Только когда фактически используется один из его символов. «Слабое связывание» может быть включено либо через флаг компоновщика (см. выше документ Apple), либо через пользовательский интерфейс Xcode (Цель -> Информация -> Общие -> Связанные библиотеки).

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

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


Что еще хуже, GCC не поддерживает функцию, известную как «автоматическое связывание» с компиляторами Microsoft, которая позволяет указать, какую библиотеку связывать, с помощью комментария #pragma в исходном файле. Это может предложить обходной путь, но его там нет.


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

  1. убрать флаг -ObjC;

  2. разбить вашу статическую библиотеку на две или более частей в соответствии с их зависимостями от внешних платформ;

  3. прибегнуть к непосредственному включению исходных файлов.

5 голосов
/ 17 мая 2011

По второй части вашего вопроса вы можете пометить связанный фреймворк как Optional: Optional framework

Что касается первой части, мне не ясно, что вы собираетесь делать:

  • Библиотека, объявленная в проекте
  • Проект, объявляющий, какие файлы скомпилированы (через Target> Фазы сборки> Исходники компиляции)
  • Если не устанавливать сложные правила сборки для включения или отсутствия файлов, что, если я хорошо помню, можно сделать с помощью файлов .xcconfig, я не вижу никаких других решений, кроме разделения вашей библиотеки. Что я бы порекомендовал, для его удобства. Вы должны даже сделать несколько целей в одном проекте ... Вы также можете просто использовать прекомпилятор MACROS (#ifdef ...), но это зависит от того, что вы хотите сделать.
0 голосов
/ 17 мая 2011

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

Поскольку у вас есть исходный код библиотеки, почему бы просто не добавить код непосредственно в каждое приложение?Таким образом, вы можете точно контролировать, что входит в каждое приложение.Вы по-прежнему можете хранить свои общие классы вместе в одном месте и использовать один и тот же код в обоих приложениях, но вы избегаете хлопот, связанных с использованием библиотеки.

0 голосов
/ 17 мая 2011

Звучит так, будто у тебя есть библиотека. Для того, чтобы все было мало, я думаю, что вам нужно реорганизовать вашу библиотеку в отдельные библиотеки с минимальными зависимостями. Вы можете попробовать включить «Dead Code Stripping» в разделе «Linker Flags» в информации о цели сборки (Xcode 3.x), чтобы увидеть, выполняет ли это то, что вам нужно (не требует фреймворков, используемых классами, которые полностью удалены) .)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...