Xcode 11 перекомпилирует слишком много

12

Xcode 11 перекомпилирует (почти?) Весь мой проект, даже если я просто изменяю локальную частную переменную или меняю значение константы в локальной области видимости, иногда даже в области локальной приватной функции. Иногда я могу получить 2 или 3 изменения с быстрой сборкой, как и ожидалось, но достаточно скоро он решает перекомпилировать все заново (что занимает слишком много времени).

Есть идеи, что может происходить? Разве Xcode не может определить, что изменилось, почему он перекомпилирует так много других вещей (даже других модулей).

Любой совет высоко ценится, спасибо!

Николай Суванджиев
источник
2
Я бы посоветовал: убедитесь, что вы делаете отладочные сборки с инкрементной сборкой, а не оптимизацией всего модуля. Выйдите и очистите DerivedData. И обновить до Xcode 11.4, он иногда компилируется так быстро, что я даже не вижу, как это происходит.
Мат
1
Эта ветка может ответить на ваш вопрос: stackoverflow.com/questions/25537614/…
Endanke
Это очень зависит от проекта, необходимо проанализировать журнал сборки на предмет того, что происходит. Я не наблюдаю такого поведения с Xcode 11.2+, хотя у меня очень большие проекты. Вы бы как-нибудь предоставили доступ к источникам вашего проекта, иначе все советы бессмысленны?
Аспери
Проверьте свойство Legacy Build System, оно должно быть отключено, если вы не
изменяете

Ответы:

8

У нас была такая же проблема, и мы ее исправили. Дважды.

Инкрементная сборка (то же строение):

до: ~ 10м после: ~ 35с

КАК?

Давайте начнем с нашего опыта в первую очередь. У нас был крупный проект Swift / Obj-C, и это было главной заботой: время сборки было медленным, и вам пришлось создавать новый проект для реализации новой функции (буквально). Бонусные баллы за неработающую подсветку синтаксиса.

теория

Чтобы действительно это исправить, вы должны по- настоящему понять, как работает система сборки. Например, давайте попробуем этот фрагмент кода:

import FacebookSDK
import RxSwift
import PinLayout

и представьте, что вы используете все эти операции импорта в своем файле. А также этот файл зависит от другого файла, который зависит от других библиотек, которые в свою очередь используют другие библиотеки и т. Д.

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

Дерево зависимостей

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

Таким образом, на первом шаге каждой инкрементной сборки XCode решает, какие файлы необходимо перекомпилировать, и создает дерево AST . Если вы изменяете файл, который действует как « надежный » для других файлов, то каждый другой файл, который действует как « зависимый », должен быть перекомпилирован.

Связь

Поэтому первый совет - снизить сцепление . Части вашего проекта должны быть независимы друг от друга.

Obj-C / Swift Bridge

Проблема с этими деревьями, если вы используете мост Obj-C / Swift, Xcode должен пройти больше фаз, чем обычно:

Безупречный мир:

  1. Создает код Obj-C
  2. Построить код Swift

Swift / Obj-C мост

Obj-C / Swift Bridge:

  1. [REPEATABLE STEP] Сборка кода Swift, необходимого для компиляции кода Obj-C
  2. [REPEATABLE STEP] Сборка кода Obj-C, необходимого для компиляции кода Swift
  3. Повторяйте 1 и 2, пока у вас не останется только надежный код Swift & Obj-C
  4. Построить код Obj-C
  5. Построить код Swift

Obj-C / Swift Bridge

Так что если вы что-то измените с шага 1 или 2, у вас возникнут проблемы. Лучшее решение - минимизировать Obj-C / Swift Bridge (и удалить его из вашего проекта).

Если у вас нет моста Obj-C / Swift, это здорово, и вы можете перейти к следующему шагу:

Swift Package Manager

Пора переходить на SwiftPM (или, по крайней мере, лучше настраивать свои Cocoapods).

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

Чтобы проверить это, создайте пустой проект с одной зависимостью, например PinLayout, и попробуйте написать этот код с Cocoapods (конфигурация по умолчанию) и SwiftPM.

import PinLayout

final class TestViewController: UIViewController {

}

Спойлер: Cocoapods скомпилирует этот код, потому что Cocoapods будет импортировать КАЖДЫЙ ИМПОРТ PinLayout (включая UIKit), а SwiftPM - нет, потому что SwiftPM импортирует фреймворки атомарно.

Грязный хак

Вы помните, что сборка Xcode является многопоточной?

Что ж, вы можете злоупотребить этим, если вам удастся разделить ваш проект на множество независимых частей и импортировать их все как независимые фреймворки в ваш проект. Это снижает связь, и это было фактически первое решение, которое мы использовали, но на самом деле оно не было очень эффективным, потому что мы могли только сократить время инкрементной сборки до ~ 4-5 м, что НИЧЕГО по сравнению с первым методом.

x0 z1
источник
Удачи, приятель. Поделитесь своим опытом, как вы снизили связь в своем проекте. До свидания!
x0 z1
3

Здесь нет золотой пули, но есть много вещей, которые нужно проверить:

  • Убедитесь, что вы действительно используете конфигурацию Debug в своей схемеРедактор схемы XCode, использующий конфигурацию отладки

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

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

  • Если проект очень большой, вы можете рассмотреть возможность реорганизации логических групп исходных файлов в каркасы, но это может быть слишком радикальным изменением, чем вы предпочитаете

Это может помочь, если вы предоставите более подробную информацию о проекте: статически ли вы связываете какие-либо библиотеки? Это фреймворк или цель приложения? Насколько большой и какой быстрой версией вы пользуетесь? Есть ли у вас какие-либо пользовательские фазы сборки, такие как линтеры или генерация кода, которые иногда можно пропустить?

nteissler
источник