Как справиться с проблемой (компиляции) большой базы кода?

10

Хотя я умею кодировать, у меня пока нет опыта работы над большими проектами. До сих пор я занимался написанием небольших программ, которые компилируются за считанные секунды (различные упражнения на языке c / c ++, такие как алгоритмы, принципы программирования, идеи, парадигмы, или просто тестирование API-интерфейсов ...) или работой над небольшими проектами, которые были сделано на скриптовом языке (ах) (python, php, js), где компиляция не требуется.

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

В качестве примера я возьму Wordpress. Это довольно легко попытаться понять, как создать плагин для него. Сначала вы создаете простой плагин «Hello World», затем создаете простой интерфейс для админ-панели, чтобы познакомиться с API, затем создаете его и делаете что-то более сложное, в то же время изменяя его внешний вид. раз ... Идея перекомпилировать что-то такое большое, как WP, снова и снова, после каждого незначительного изменения, пытаясь "если это работает" и "как это работает / чувствует", кажется неэффективной, медленной и неправильной.

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

Я хотел бы узнать больше о том, как это делается правильно. Каковы некоторые общие практики, подходы и проекты (шаблоны), чтобы справиться с этим? Как эта «модульность» называется в мире программистов и для чего мне нужно поискать в Google? Часто ли проекты вырастают из своих первых масштабов, что через некоторое время становится проблематичным? Есть ли способ избежать долгой компиляции не очень хорошо разработанных проектов? Способ как-то их модульно (возможно, исключить не жизненно важные части программы при разработке (какие-либо другие идеи?))?

Спасибо.

pootzko
источник
4
Обь. XKCD и соответствующая футболка thinkgeek * 8 ')
Марк Бут
1
Если вы работаете над достаточно большим проектом с достаточно большим бюджетом, вы можете получить серверы сборки, которые сделают компиляцию за вас :)
SoylentGray
@Chad - я знаю это, но это только мой домашний настольный компьютер gnu / linux и я на данный момент :)
pootzko
@ Чад Хорошо, вы говорите нам, что нам нужны выделенные серверы для работы с Java (или любым другим компилируемым языком)? Это полное дерьмо
Каньон Колоб
1
@KolobCanyon - Нет, я говорю, что есть шкала, над которой вы могли бы работать, которая требовала бы их. и что теперь они достаточно дешевы, поскольку наличие виртуальной машины по требованию, предназначенной для быстрой компиляции и автоматизации тестов, достаточно просто, чтобы масштаб не был таким большим.
SoylentGray

Ответы:

8

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

В C / C ++ компиляция довольно проста. Вы компилируете, переводите каждый исходный файл в машинный код (мы называем их объектными файлами * .o) и затем связываете все свои объектные файлы в один большой исполняемый файл.

Как упоминалось в MainMa, некоторые библиотеки встроены в отдельные файлы, которые будут динамически связаны во время выполнения с исполняемым файлом. Эти библиотеки называются общими объектами (* .so) в Unix и динамически связанными библиотеками (DLL) в Windows. Динамические библиотеки имеют много преимуществ, одним из которых является то, что вам не нужно их компилировать / связывать, если только их исходный код не изменится.

Существуют инструменты автоматизации сборки, которые помогут вам:

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

Самые известные из них (make, ant, maven, ...) могут автоматически определять, какие части кода были изменены с момента последней компиляции, и какой именно объект / двоичный файл необходимо обновить.

Однако это связано с (относительно небольшими) затратами на написание «сценария сборки». Это файл, содержащий всю информацию о вашей сборке, например определение целей и их зависимостей, определение компилятора, который вы хотите и какие параметры использовать, определение среды сборки, путей к библиотекам, ... Возможно, вы слышали о файлах Makefile (очень распространенный в мире Unix), или build.xml (очень популярный в мире Java). Это то, что они делают.

rahmu
источник
2
Ant (Java) не может определить, что нужно перекомпилировать. Он обрабатывает тривиальную часть работы, перекомпилирует измененный исходный код, но совсем не понимает зависимости классов. Мы полагаемся на IDE для этого, и они идут неправильно, если сигнатура метода изменяется таким образом, что не требует изменения в вызывающем коде.
Кевин Клайн
@kevincline Я второй это - ANT компилирует все, если вы не указываете что-то другое в build.xmlфайле
Каньон
7

Вы не перекомпилируете весь проект каждый раз. Например, если это приложение на C / C ++, есть вероятность, что оно будет разделено на библиотеки (библиотеки DLL в Windows), каждая библиотека будет скомпилирована отдельно.

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

Арсений Мурзенко
источник
3
Если я не перекомпилирую все это, то когда у меня будет время поиграть с моим Trebuchet
SoylentGray
5

Я думаю, что все ответы до сих пор тоже намекали на то, что крупные программные проекты почти всегда разбиты на гораздо более мелкие части. Каждый кусок обычно хранится в своем собственном файле.

Эти части индивидуально скомпилированы для создания объектов. Объекты затем связываются вместе, чтобы сформировать конечный продукт. [В каком-то смысле это похоже на создание чего-то из Легоса. Вы не пытаетесь изготовить окончательную вещь из одного большого куска пластика, вместо этого вы комбинируете кучу меньших кусков, чтобы сделать это.]

Разбиение проекта на части, которые скомпилированы по отдельности, позволяет делать некоторые интересные вещи.

Инкрементное здание

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

Это порождает идею постепенного наращивания . При инкрементной сборке перекомпилируются только части, на которые повлияло изменение. Это значительно ускоряет время разработки. Правда, вам, возможно, все еще придется ждать, пока все будет перекомпоновано, но это все равно экономия на необходимости перекомпилировать и перекомпоновывать все. (Кстати: некоторые системы / языки поддерживают инкрементное связывание, поэтому необходимо пересвязывать только те вещи, которые изменились. Обычно это связано с низкой производительностью и размером кода.)

Модульное тестирование

Второе, что позволяют делать маленькие кусочки, это посмотреть на индивидуальное тестирование кусочков до их объединения. Это известно как модульное тестирование . В модульном тестировании каждый модуль тестируется индивидуально, прежде чем он интегрируется (комбинируется) с остальной частью системы. Модульные тесты обычно пишутся так, чтобы их можно было быстро запускать без участия остальной системы.

Ограничительный случай применения тестирования можно увидеть в Test Driven Development (TDD). В этой модели разработки ни один код не написан / изменен, если он не предназначен для исправления неудачного теста.

Делать это проще

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

К счастью, программисты ленивы *, поэтому они изобретают множество инструментов, чтобы облегчить их работу. Для этого было написано много инструментов для автоматизации вышеуказанной задачи. Самые известные из них уже были упомянуты (make, ant, maven). Эти инструменты позволяют вам определить, какие части должны быть собраны вместе, чтобы сделать ваш окончательный проект и как части зависят друг от друга (то есть, если вы измените это, это необходимо перекомпилировать). В результате, если выполнить только одну команду, выясняется, что нужно перекомпилировать, компилирует и связывает все заново.

Но это все еще не позволяет понять, как вещи связаны друг с другом. Это большая работа, и, как я уже говорил, программисты ленивы. Таким образом, они придумали другой класс инструментов. Эти инструменты были написаны, чтобы определить зависимости для вас! Часто инструменты являются частью интегрированных сред разработки (IDE), таких как Eclipse и Visual Studio, но есть и некоторые автономные, используемые как для универсальных, так и для специальных приложений (makedep, QMake для программ Qt).

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

jwernerny
источник
5

Вот мой список вещей, которые вы можете попробовать ускорить сборку C / C ++:

  • Вы хотите восстановить только то, что изменилось? Большинство сред делают это по умолчанию. Нет необходимости перекомпилировать файл, если он или ни один из заголовков не изменился. Точно так же нет причин перестраивать dll / exe, если все ссылки в objs / lib не изменились.
  • Поместите сторонний материал, который никогда не меняется, и связанные заголовки в область библиотеки кода, доступную только для чтения. Вам нужны только заголовки и связанные двоичные файлы. Вы никогда не должны восстанавливать это из источника, отличного от одного раза.
  • При восстановлении всего, двумя ограничивающими факторами в моем опыте были количество ядер и скорость диска . Получите мощную четырехъядерную, многопоточную машину с действительно хорошим жестким диском, и ваша производительность улучшится. Рассмотрим твердотельный накопитель - имейте в виду, что дешевые могут быть хуже, чем хороший жесткий диск. Рассмотрите возможность использования рейда, чтобы увеличить ваш жесткий диск
  • Используйте распределенную систему сборки, такую ​​как Incredibuild, которая разделит компиляцию по другим рабочим станциям в вашей сети. (Убедитесь, что у вас есть надежная сеть).
  • Настройте единую сборку, чтобы избавить вас от постоянной перезагрузки заголовочных файлов.
Дуг Т.
источник
По моему опыту (не очень, но хорошо) скорость диска начинает становиться неактуальной, если ваш проект выходит за рамки «очень малого». Подумайте о том, что вы скажете в следующем пункте: вы используете сеть для ускорения компиляции. Если диск был большим узким местом, обращение к сети не кажется очень хорошим ходом.
Р. Мартиньо Фернандес
Другое дешевое решение - это скомпилировать в tmpfs. Может значительно повысить производительность, если процесс компиляции связан с IO.
Артефакт2
4

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

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

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

DeadMG
источник
1
Я полагаю, что мой вопрос не предназначался для интерпретации, а не для компиляции подхода. Вместо этого я просто попросил совета о том, как правильно разрабатывать большой (скомпилированный) проект. Спасибо за идею постепенного перестроения.
pootzko
@pootzko: Ну, довольно несправедливо обсуждать недостатки компиляции, когда вы не говорите также о недостатках интерпретации.
DeadMG
1
нет, это не так. это еще одна дискуссия и не имеет ничего общего с моим вопросом. Я не говорю, что это не должно обсуждаться. это должно, но не здесь.
pootzko
@pootzko: Тогда вам не следует посвящать большую часть вашего вопроса перечислению того, что вам не нравится в компиляции. Вы должны были написать что-то гораздо более короткое и лаконичное, например: «Как можно сократить время компиляции больших проектов?».
DeadMG
Я не знал, что должен был спросить кого-то о том, как я «должен» задать свой вопрос ..? O. Я написал это так же, как и я, чтобы лучше объяснить свою точку зрения, чтобы другие могли лучше понять ее и объяснить мне, как добиться того же / подобного в скомпилированных языках. Я снова - не - попросил кого-нибудь сказать мне, если интерпретируемые языки вызывают худшие требования к времени на ПК пользователя. Я знаю это, и это не имеет никакого отношения к моему вопросу - «как это делается со скомпилированными языками», извините. Другие люди, похоже, поняли, о чем я спрашиваю, поэтому я не думаю, что мой вопрос недостаточно ясен ..
pootzko
4
  • Частичное восстановление

Если в проекте реализована правильная DAG-зависимость для компиляции, вы можете избежать перекомпиляции только тех объектных файлов, на которые влияют ваши изменения.

  • Процесс множественной компиляции

Также при условии правильной зависимости DAG от компиляции вы можете компилировать, используя несколько процессов. Одна работа на ядро ​​/ процессор является нормой.

  • Исполняемые тесты

Вы можете создать несколько исполняемых файлов для тестирования, которые связывают только определенные объектные файлы.

dietbuddha
источник
2

В дополнение к ответу MainMa, мы также только что обновили машины, на которых работаем. Одной из лучших покупок, которые мы сделали, был SSD, когда вы не можете не перекомпилировать весь проект.

Другим предложением было бы попробовать другой компилятор. Когда-то мы перешли от компилятора Java к Jikes, и теперь мы перешли к использованию компилятора, поставляемого в комплекте с Eclipse (не знаю, есть ли у него имя), который использует преимущества многоядерных процессоров.

Наш 37000 файловый проект занял около 15 минут, чтобы скомпилировать с нуля, прежде чем мы внесли эти изменения. После изменений его сократили до 2-3 минут.

Конечно, стоит еще раз упомянуть точку зрения MainMa. Не перекомпилируйте весь проект каждый раз, когда вы хотите увидеть изменения.

RP.
источник