Главная страница » Что такое сборка в программировании

Что такое сборка в программировании

  • автор:

Сборки .NET

Когда мы создаем приложение в результате компиляции в Visual Studio или в консоли, результатом этой работы является файл exe или dll (в зависимости от выбранных настроек), который называется сборкой приложения. Сборка является базовой структурной единицей в .NET, на уровне которой проходит контроль версий, развертывание и конфигурация приложения.

Сборки кристаллизуют всю библиотеку классов .NET — при написании кода и создании сборки своего приложения мы используем пространства имен, которые размещены в других сборках .NET.

Сборки имеют следующие составляющие:

Манифест, который содержит метаданные сборки

Метаданные типов. Используя эти метаданные, сборка определяет местоположение типов в файле приложения, а также места размещения их в памяти

Собственно код приложения на языке MSIL, в который компилируется код C#

Все эти компоненты могут находиться в одном файле, и тогда сборка представляет один единственный файл в формате exe или dll.

Компоненты сборки в .NET

Но также может быть, что эти компоненты хранятся в отдельных файлах. Например, есть основной файл exe, который имеет метаданные сборки и типов и который использует дополнительные файлы ресурсов — различные изображения, звуковые файлы, вспомогательные модули, элементы интерфейса, локализованные для различных культур.

Манифест сборки

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

Манифест хранит следующие данные:

Номер версии : основной и дополнительный номера. Используется для управления версиями

Язык и региональные параметры : информация о языке и региональных параметрах, которые поддерживает сборка

Информация о строгом имени : открытый ключ издателя

Список всех файлов сборки : хэш и имя каждого из входящих в сборку файлов

Список ссылок на другие сборки , которые использует текущая сборка

Список ссылок на типы , используемые сборкой

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

Атрибуты сборки

По умолчанию Visual Studio при создании проекта добавляет файл AssemblyInfo.cs, который можно найти в узле Properties:

Файл AssemblyInfo в C#

Это обычный файл на языке C# и в моем случае выглядит так:

Смысл этого файла состоит в том, что он задает настройки манифесту сборки. Через атрибуты типа [assembly: AssemblyVersion(«1.0.0.0»)] можно установить значения в манифесте. Префикс assembly: перед атрибутом указывает на то, что это атрибут уровня сборки, в данном случае атрибут номера версии сборки.

В принципе, исходя из названия, я думаю, предназначение многих атрибутов итак понятно:

AssemblyCompany : название компании

AssemblyConfiguration : конфигурация сборки (Retail или Debug)

AssemblyCopyright : авторское право на программу

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

AssemblyDescription : краткое описание сборки

AssemblyProduct : информация о продукте

AssemblyTitle : название сборки как информационного продукта

AssemblyTrademark : сведения о торговой марке

AssemblyCulture : задает язык и региональные параметры, поддерживаемые сборкой (например, установка русской культуры: [assembly:AssemblyCultureAttribute(«ru»)] )

AssemblyInformationalVersion : полная версия сборки

AssemblyVersion : версия сборки

AssemblyFileVersion : номер версии файла Win32. По умолчанию совпадает с версией сборки.

Также есть графический способ определения информации о сборке. Для этого нажмем в окне Solution Explorer (Обозреватель решений) на название проекта правой кнопкой мыши и выберем в появившемся меню пункт Properties (Свойства). В открывшемся окне нажмем на кнопку Assembly Information. , и нам предстанет окно изменения атрибутов:

Сборки

Какой бы язык .NET не выбирался для программирования, важно понимать, что хотя двоичные .NET-единицы имеют такое же файловое расширение, как и двоичные единицы СОМ-серверов и неуправляемых программ Win32 (* . dll или * . ехе), внутренне они устроены абсолютно по-другому. Например, двоичные .NET-единицы * .dll не экспортируют методы для упрощения взаимодействия с исполняющей средой СОМ (поскольку .NET — это не СОМ). Более того, они не описываются с помощью библиотек СОМ-типов и не регистрируются в системном реестре. Пожалуй, самым важным является то, что они содержат не специфические, а наоборот, не зависящие от платформы инструкции на промежуточном языке (Intermediate Language — IL), а также метаданные типов. На следующей схеме показано, как все это выглядит:

Компиляция инструкций IL и метаданных

Отсюда следует, что сборка (assembly) — это логическая единица, содержащая скомпилированный код для .NET Framework, т.е. это полностью самодостаточный и скорее логический, нежели физический элемент. Это значит, что он может быть сохранен в более чем одном файле (хотя динамические сборки хранятся в памяти, а вовсе не в файлах). Если сборка хранится в более чем одном файле, то должен существовать один главный файл, содержащий точку входа и описывающий остальные файлы.

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

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

Тот факт, что сборка содержит метаданные программы, означает, что приложение или другие сборки, которые вызывают код данной, не нуждаются в обращении к реестру или любому другому источнику данных, чтобы узнать, как конкретную сборку следует использовать. Это существенный прорыв по сравнению со старым способом работы СОМ, когда GUID-идентификаторы компонентов и интерфейсов необходимо было извлекать из реестра, а подробности методов и свойств в некоторых случаях читать из библиотеки типов.

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

Сборки бывают двух видов: разделяемые и приватные.

Приватные сборки

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

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

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

Поскольку приватная сборка полностью самодостаточна, процесс ее развертывания весьма прост. Вы просто помещаете соответствующий файл (или файлы) в соответствующую папку системы (никаких записей вносить в реестр не потребуется). Этот процесс известен как установка с нулевым воздействием или установка с помощью хсору (zero impact (хсору) installation).

Разделяемые сборки

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

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

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

Решение этих проблем включает размещение разделенных сборок в специальном поддереве каталогов файловой системы, известном под названием глобальный кэш сборок (global assembly cache — GAC). В отличие от приватных сборок, это не может быть сделано простым копированием сборки в определенную папку — сборку понадобится специальным образом установить в кэше GAC. Данный процесс может быть реализован с помощью множества утилит .NET и включает в себя выполнение необходимых проверок устанавливаемой сборки, а также создание небольшой иерархии папок в пределах GAC, используемых для обеспечения целостности сборок.

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

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

Однофайловые и многофайловые сборки

В большом количестве случаев между сборками .NET и файлами двоичного кода (*.dll или *.ехе) соблюдается простое соответствие «один к одному». Следовательно, получается, что при построении *.dll-библиотеки .NET, можно спокойно полагать, что файл двоичного кода и сборка представляют собой одно и то же, и что, аналогичным образом, при построении исполняемого приложения для настольной системы на файл *.ехе можно ссылаться как на саму сборку. Однако это не совсем так. С технической точки зрения, сборка, состоящая из одного единственного модуля *.dll или *.ехе, называется . В однофайловых сборках все необходимые CIL-инструкции, метаданные и манифесты содержатся в одном автономном четко определенном пакете.

, в свою очередь, состоят из множества файлов двоичного кода .NET, каждый из которых называется модулем (module). При построении многофайловой сборки в одном из ее модулей (называемом первичным или главным (primary) модулем) содержится манифест всей самой сборки (и, возможно, СIL-инструкции и метаданные по различным типам), а во всех остальных — манифест, CIL-инструкции и метаданные типов, охватывающие уровень только соответствующего модуля. Как нетрудно догадаться, в главном модуле содержится описание набора требуемых дополнительных модулей внутри манифеста сборки.

Сборка ПО

Сборка ПО (англ. Software Build), также известная как интеграция — процесс преобразования файлов с исходным кодом и их компиляция в артефакты, составляющие приложение, такие как бинарные и исполняемые файлы.

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

Процесс компиляции в случае, если функция обозначена как внешняя, не проверяет такая функция действительно существует.

Для сложных программ после компиляции (выполняемый специальной программой — компилятором) происходит процесс связывания (нахождение реального положения всех функций, обозначенных как внешние). Это выполняется специальной программой — Линкером. Процесс линковки представляет собой замену относительных адресов функций внешних библиотек на реальные адреса которые будут использоваться программой в процессе её выполнения.

Со сборкой связано понятие версии приложения. Линкер часто может автоматически устанавливать (увеличивать) номер версии.

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

Процесс создания компьютерной программы, как правило, управляется с помощью инструмента сборки — программы которая координирует и контролирует другие программы. Примерами таких программ являются сделать, Apache Ant, Apache Maven, SCons и Phing. Утилите для сборки необходимо выбрать и слинковать различные файлы, в правильном порядке.

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

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

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

Что такое сборщик продукта

Когда вы открываете любой сайт — например, google или facebook, вы видите конечный продукт. Но чтобы этот продукт увидеть, и пощупать, нужно:

Написать код приложения

Поднять его на сервере приложения

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

Содержание

Что это такое и зачем он нужен

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

Сначала весь код его мини-программ хранился в одном файле — Main.java. Чтобы запустить приложение, достаточно было дважды кликнуть этот файл. И всё!

Потом Вася освоил Page Object Pattern и стал разносить логику по разным классам. Но всё равно это были простые программы, и для запуска оставался главный класс.

А потом Вася. Устроился на работу. Да-да, зеленым новичком, и такое бывает! Старший разработчик Николай на собеседовании разглядел в нем потенциал. Так Вася стал джуниор-разработчиком в компании ООО «Котики».

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

В первый рабочий день Николай подошел к Васе и стал рассказывать:

— Наш код хранится в git. Знаешь, что это такое?

— Ага, система контроля версий!

— Да. Вот тебе ссылочка, скачивай.

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

Николай только ухмыльнулся:

— Нет, так оно только для мелких проектов работает. А тебе нужно:

скомпилировать проект — из исходных текстов получить файлы классов с байт-кодом (которые потом будет исполнять JVM);

объединить вот эти классы в библиотеку Search.jar;

объединить вот эти классы в библиотеку Clean.jar;

объединить вот эти классы в библиотеку Update.jar;

объединить вот эти классы в библиотеку Report.jar;

объединить вот эти классы в библиотеку Link.jar;

а вот эти классы.

Вася в шоке выкатил глаза и промямлил:

— Ээээ, подожди. Мне это выучить надо?

— В учебных проектах тебе не надо заморачиваться. Запустил конкретный класс, и всё работает. Ну, может, еще одну-две библиотечки собрал, но это тоже несложно.

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

Поэтому эту работу автоматизируют. Можно написать скрипт сборки на коленке, но зачем, если уже есть стандартные сборщики? Скажем, для java это ant, maven, gradle. У нас используется maven, почитай пока о нем.

Сборщик уже настроен, так что тебе достаточно зайти через командную строку в директорию проекта и написать команду:

А дальше он сам всё сделает. На выходе получим cats.war. Это и есть наше приложение, которое мы потом подложим на сервер wildfly, чтобы его запустить.

— Ага, хорошо, спасибо!

Николай ушел, а Вася завороженно смотрел в экран, где в командной строке работал maven. Быстро-быстро бежали буквы по экрану. И вот, наконец, сборщик остановился. Он написал «BUILD SUCCESS». Значит, всё прошло хорошо. И в нужной директории Вася нашел архив «cats.war».

Пока Николая не было, Вася успел нагуглить это новое слово: «maven». И даже смог найти в проекте скрипт сборки, и начал разбираться, что конкретно там происходит. Всё-таки не зря его взяли на работу! Это отличное качество разработчика (да и не только его) — гуглить и копать самому, а не сидеть сложа ручки в ожидании ментора.

Когда Николай вернулся, он подытожил то, что Вася узнал:

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

Что нужно сделать с кодом-источником:

объединить классы в файл JAR или другую библиотеку;

установить набор зависимостей;

запустить конкретный класс или несколько классов.

И только после всех этих манипуляций у нас появляется ПО. Набор манипуляций зависит от конкретного проекта, но чем сложнее проект, тем больше действий надо сделать.

А если задача повторяется снова и снова, она становится первым кандидатом на автоматизацию. Ведь нам нужно что? За один шаг получить работающий проект! Этим и занимаются системы сборки!

— О, стой! Так в IDEA (среда для написания кода) же кнопка «Build» есть. Она ведь тоже билдит, то есть собирает код! Да? Это аналог maven-а?

— Не совсем. Это кнопка:

компилирует код — проверяет его на наличие простых синтаксических ошибок вида «забыл поставить точку с запятой в конце команды»

собирает нужные ресурсы (файлы конфигов и подобные) в одну папочку, из которой уже можно запускать программу

— Так если она все собирает и можно программу запускать, зачем maven нужен?)

— Она не собирает само приложение, так как не знает всех зависимостей. Поэтому нужна отдельная программа-сборщик кода.

— А в чем тогда смысл собирать ресурсы?

— Ну, например, для запуска автотестов. Когда мы их запускаем, там не используется полностью варник (приложение cats.war). Там вызываются конкретные функции + используются конкретные ресурсы типа справочника телефонных номеров.

Разработчик исправил код и нажимает «Build». Это обновляет ресурсы, которые используются в тестах. А если тебе нужен варник приложения, то собираешь maven-ом (ну или аналогом).

Комментарий коллеги-разработчика:

— Диалог правильный, но это подход 10-летней давности. Сейчас всё делегируют maven/gradle. В IDE даже галочка есть отдельная для этого. А уже в maven/gradle делаются гранулярные цели для каждой задачи.

— А вообще главное отличие сборщика от IDE — сборщик можно запустить из командной строки, на любом окружении, независимо от среды разработки + в CI/CD системе (TeamCity, Jenkins и тп). Это воспроизводимый билд.

То есть при желании IDEA можно настроить, чтобы она все это делала. Прописать все зависимости и другое, но это будет нерасширяемо.

Как работает сборщик

Сборщики работают примерно одинаково. Базовый функционал:

компилировать код (проверять на простейшие синтаксические ошибки)

создавать и удалять директории

Есть и более продвинутые программы, которые также позволяют автоматически извлекать зависимости в библиотеке или автоматизировать тестирование.

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

Давайте посмотрим, как такой скрипт выглядит, на примере Ant. Ant — инструмент компоновки для Java-проектов.

Файл компоновки Ant — это XML-документ. Он разбит на 4 основные части:

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

Проект

Всё в файле является частью проекта. Поэтому тег <project> является корневым в скрипте:

name — имя проекта

default — умолчательная (дефолтная) цель, срабатывающая при запуске скрипта.

Внутри проекта уже находится все остальное — цели, которых мы хотим достичь, и конкретные действия для их достижения.

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

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

Свойства

Свойства Ant похожи на константы. Один раз указали значение, и используем в скрипте хоть в 20 местах. А если значение изменилось, исправить надо будет одно место, а не двадцать. Сюда очень хорошо выносить версии продукта и зависимых библиотек, а также пути к директориям.

Записываются свойства в теге <property>:

У каждого свойства есть:

значение — value, или место — location (если указываем путь к директории)

Свойства можно переиспользовать, записав как $

Цель — это то, что мы хотим получить от сборщика. Краткое название для «я хочу скомпилировать проект» или «я хочу создать все нужные папочки».

Цели записываются в тегах <target>:

Основные атрибуты цели:

name — имя цели, которое мы будет указывать в командной строке, поэтому лучше делать его коротким. Обязательный параметр.

description — описание цели. Выводится при запросе информации по проекту.

depends — от кого эта цель зависит. То есть какую цель надо запустить перед выполнением текущей. Необязательный параметр

В примере цель ”build” зависит от цели ”compile”. Мы не можем начать сборку билда, пока не скомпилировали его. Поэтому, если мы вызываем ant с целью сборки билда, то он:

Выполнит цель ”compile”

Выполнит цель ”build

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

Обратите внимание на граф вызова целей. Исходно мы хотим выполнить цель D. Читая атрибут depends, можно подумать, что первой будет вызвана цель C, потом B, и потом A. Это не так! Читать блок depends надо так:

Таким образом, сначала мы вызываем цель A, потом B, и только потом C. То есть фактически читаем справа налево этот атрибут.

У цели могут быть и другие атрибуты. Например, условие «if». Но подробнее о них читайте в официальной документации Ant — статья «Targets».

Цель по умолчанию

Какой должна быть цель по умолчанию? Должна ли проводиться компиляция, группировка, генерирование документации или все вместе?

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

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

Задачи

Задача — это конкретное действие, которое нужно выполнить, чтобы достичь поставленной цели. Например, создать директорию, скопировать файлы, скомпилировать Java-код.

В Ant задача обычно отражает определенную команду: «javac», «mkdir» или даже «javadoc». Именно эта команда и будет названием тега:

Эти теги всегда будут внутри тегов <target>. Задача всегда относится к какой-то цели. А вот цель может не иметь задач. Правда, тогда она будет бесполезная =)

Внутри цели может быть одна задача. Например, для компиляции проекта нам нужно скомпилировать java-код в конкретной директории:

При вызове цели compile будет вызвана задача javac. Она компилирует код java в srcdir и складывает классы в destrdir.

Внутри цели может быть несколько задач, как одинаковых, так и разных. Например, мы хотим создать все нужные проекту директории, а их несколько. Вызываем несколько раз задачу mkdir. Она создает директорию, определяемую атрибутом dir:

При вызове цели init у нас будут созданы 2 директории — ”bin” и ”lib”.

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

Стандартная версия Ant содержит более 150 заданий. Вот некоторые из них:

echo – вывод сообщений в консоль

mkdir – создание директорий

copy — копирование файлов

delete – удаление файлов и директорий

move – перемещение файлов и директорий

replace — замещение фрагментов текста в файлах

javac – компиляция Java–кода

java – запуск class и jar файлов

jar – создание jar файла

junit – запуск тестов

exec — выполнение внешней команды

zip — создание архива в формате Zip

Доп ссылки

Writing a Simple Buildfile — официальная дока на английском

Как запустить сборку

Все зависит от сборщика. Но обычно это название сборщика + название цели, которую мы запускаем. Для Ant это выглядит так:

Целей может быть несколько:

Фишка ant в том, что вы можете назвать цель как угодно:

С одной стороны, это звучит даже забавно:

И все вокруг знают, что это означает пересобрать проект. Но такие хиханьки-хаханьки хороши лишь в умеренных дозах. Подумайте сами — если каждую цель назвать как-то «невпопад», то придется просто заучивать эти названия. Что неудобно.

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

Поэтому обычно используют стандартные названия целей

clean — чистка проекта: удаление файлов заготовок, которые остаются после компиляции. Приводит проект к виду, в котором он хранится в репозитории

compile — компиляция исходного кода

test — запуск тестов

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

Посмотрим на примере, который можно взять и пощупать — в проекте folks используется сборщик maven. А в статье «Как собрать проект и запустить тесты» (в старой версии, там возникли проблемки со сборщиком после обновления и команды заменили) мы видим такие команды:

Эти команды — типовые для maven-а. Давайте разберемся, что они означают.

mvn

Это сокращение от maven. Название сборщика, к которому мы обращаемся.

Первое слово, которое вы пишете в командной строке — это вызов команды. Это может быть путь к самой программе вида:

А может быть просто название команды:

В этом случае система (я говорю про винду) полезет в PATH и проверит: а есть ли там такое? Если есть, то запустит программу и по короткой команде. Подробнее про PATH можно почитать здесь.

Когда вы устанавливаете maven (ant или любой другой сборщик), вы прописываете путь к нему в переменную PATH. По крайней мере, в инструкции по установке есть такой пункт. Именно благодаря этому пункту команда «mvn» в командной строке начинает работать.

По сути, тут все то же самое, что и в ant — мы пишем название сборщика (mvn) и те цели, которые мы хотим запустить. Точнее, фазы. В maven это называется phases, и набор фаз вполне определенный. В этом отличие сборщиков, ant более гибкий и цели мы можем настраивать и называть так, как захотим. В maven не можем.

clean

В обеих командах сначала вызывается фаза clean. Она нужна для того, чтобы очистить созданные другими сборками артефакты. Так как я тестировщик, то объясню с точки зрения тестирования.

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

Теперь, когда мы просто запускаем тест, без clean, система переиспользует созданные артефакты. И это хорошо! Потому что так тесты гоняются намного быстрее. Система уже не тратит время на повторное создание артефактов.

Это как если у вас перед готовкой пустой холодильник или полный. Если пустой — надо идти в магазин. Если вы уже вчера туда сходили и продукты все есть, можно сразу приступать к готовке!

Да, переиспользование артефактов — это хорошо. Но иногда их надо почистить. Вот, скажем, если у вас яйца протухли, то и омлет станет отравой, и шарлотку есть будет нельзя. Любое блюдо будет испорчено из-за одного плохого ингредиента. Баг в исходнике «сломал» готовый продукт!

Что мы делаем в таком случае? Испорченные яйца выкидываем, идем в магазин за новыми. Примерно так и работает clean — чистит наш холодильник. Единственная проблема — она чистит всё. Удалять так удалять!

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

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

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

А потом, в процессе дня, мы фазу clean уже не вызываем:

Так вот, в коде обнаружился баг, который из кода «переехал» в артефакты. Разработчик баг исправил, даже проверил у себя локально — работает! Отдает вам, вы пересобираете проект — не работает! Как так?? Вы же пересобрали! Ведь вызвали же фазу «install».

При этом иногда над простыми ошибками тупят дольше всего. Разработчик снова ковыряется в коде, тратит время — должно же работать. Вы снова собираете — нет, не работает! И только когда разработчик приходит посмотреть, что именно вы делаете, он обращает внимание на команду:

— Стой! Ты же clean не делаешь!

— Ну да, я его только по утрам вызываю.

Это называется «делать на автомате», не задумываясь о своих действиях. Если вы не хотите думать над командой по сборке, то всегда вызывайте clean, не прогадаете. Да, сборка чуть дольше будет идти, но вы точно не огребете такую проблему.

Аналогичная ситуация может возникнуть при прогоне автотестов. Прогнали один тест — все хорошо, он работает. Прогоняете другой — он падает, причем очень странно. Тест пишет, что ожидает «Иванова», которого в вашем тесте нет вообще! Откуда же он взялся??

Да просто первый тест не почистил базу за собой! И Иванов остался в артефактах. А вы не вызвали фазу clean для экономии времени. Отсюда и баг. Поэтому при подозрительных падениях тестов из серии «откуда он взял эти данные» стоит перепрогнать тест с фазой clean.

install

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

Скачали исходный код продукта

Выполнили команду «mvn clean install»

Забрали готовый билд в определенной папочке!

Хотя по сути своей фаза install ничего не собирает. Она публикует собранный артефакт в локальном репозитории. Смотрите — в maven есть свой жизненный цикл (подробнее см в статье «Maven in 5 Minutes», раздел «Maven Phases»):

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *