Русский
Русский
English
Статистика
Реклама

Сборка

Recovery mode Сборка ядра Linux 5.12.10 c LLVM 12 Clang и LTO оптимизацией

14.06.2021 18:13:31 | Автор: admin

Технический прогресс не стоит на месте, появляются новые компьютерные архитектуры, компиляторы становятся умнее и генерируют более быстрый машинный код. Современные задачи требуют все более креативного и эффективного решения. В данной статье пойдет речь, на мой взгляд, про один из самых прогрессивных тулчейнов LLVM и компиляторы на его основе Clang и Clang++, для языков программирования С и C++ соответственно. Хоть GCC конкурент Clang, может агрессивнее оптимизировать циклы и рекурсию, Clang дает на выходе более корректный машинный код, и чаще всего не ломает поведение приложений. Плюс оптимизация программ не заканчивается только оптимизацией циклов, поэтому Clang местами дает лучшую производительность. В GCC же за счет переоптимизации вероятность получить unpredictable behavior значительно выше. По этой причине на многих ресурсах не рекомендуют использовать -O3 и LTO(Link Time Optimization) оптимизации для сборки программ. Плюс в случае агрессивной оптимизации, размер исполняемых файлов может сильно увеличиться и программы на практике будут работать даже медленнее. Поэтому мы остановились на Clang не просто так и опции компиляции -O3 и LTO работают в нем более корректно. Плюс современные компиляторы более зрелые, и сейчас уже нет тех детских болячек переоптимизации и LTO.

Что меня побудило написать эту статью? В первую очередь это несколько фактов:

  1. Впервые прочел про сборку ядра Linux с LTO оптимизацией и Clang из новостей, где упоминалась компания Google. Она использует Clang и LTO оптимизацию для сборки ядра Linux и получения лучшей производительности. Компания Google для меня является синонимом инноваций, лучших программистов в мире и поэтому для меня ее опыт является самым авторитетным. Плюс она привнесла очень много в развитие open source, и ее наработками пользуются тысячи компаний во всем мире.
  2. Хоть компания Google начала использовать Clang и LTO оптимизацию раньше, только с выходом ядра Linux 5.12.6 и 5.12.7 было закрыто большое количество багов, и сборка ядра c LTO оптимизаций стала доступна многим. До этого при сборке ядра с LTO оптимизацией многие драйвера давали сбой.
  3. Мною уже протестирована работа ядра с LTO на Ryzen 9 3900x + AMD Radeon 5700 XT. Плюс уже давно использую LLVM 12 и Clang для сборки системных программ. Инструментарий LLVM12 и Clang стали основными в моей системе по причине лучшей поддержки моего процессора и нужные мне программы работают быстрее при сборке с помощью Clang. Для программистов Clang дает лучший контроль ошибок, оптимизации и unpredictable behavior. -fdebug-macro, -fsanitize=address, -fsanitize=memory, -fsanitize=undefined, -fsanitize=thread, -fsanitize=cfi, -fstack-protector, -fstack-protector-strong, -fstack-protector-all, -Rpass=inline, -Rpass=unroll, -Rpass=loop-vectorize, -Rpass-missed=loop-vectorize, -Rpass-analysis=loop-vectorize и т.д.
  4. Данная возможность толком нигде не была описана в связи с п.2 и есть подводные моменты, которые будут рассмотрены в данной статье.


В этой статье будет описана сборка ядра Linux 5.12.10 c LLVM 12 + Clang и LTO оптимизацией. Но так как статья получилась бы короткой, то так же бонусом будет рассмотрен вопрос как сделать утилиты LLVM 12 и Clang сборочным инструментарием по умолчанию, и какие программы и библиотеки имеет смысл собрать вручную, чтобы получить лучший отклик и производительность от системы. GCC имеет более лояльную лицензию на использование, и поэтому он установлен во многих дистрибутивах по умолчанию.

Так как в новом ядре фиксится немалое количество багов для работы с моим оборудованием(Ryzen 9 3900x + AMD Radeon 5700 XT) будет рассмотрен вопрос автоматизации сборки и установки нового ядра, чтобы это сильно не отвлекало и занимало минимум времени. Думаю многим это будет полезно. Будет рассмотрен принцип работы моего сборочного скрипта. Все действия будут проводиться в Arch Linux. Если статья будет хорошо оценена, то она станет вводной частью в серию статей про оптимизацию Linux, где будут рассмотрены внутренние механизмы ОС, и как оптимизировать их работу, будут рассмотрены вредные советы и ошибки оптимизации, и будет дан ответ на вопрос оптимизации системы Что для русского хорошо, то для немца смерть!.

Хоть тема оптимизации описывалась многократно, не мало где дают вредные советы, и некоторые механизмы ОС описаны с ошибками. Чаще всего это происходит из-за сложностей перевода или минимальной документации в интернете к компонентам ядра Linux. Где-то информация вовсе устарела. Плюс некоторые вещи понимают программисты, но не понимают системные администраторы, и наоборот. Изначально после установки Linux работает относительно медленно, но благодаря оптимизации и гибкой настройке, можно добиться более высокой производительности и значительно улучшить отклик системы. Arch Linux у меня используется как основная система, и отклик системы, производительность лучше, чем в Windows 10.
Внимание, автор статьи не несет ответственность за причиненный вред в следствии использования данной статьи! Все действия вы выполняете на свой страх и риск! Все действия должны выполнять только профессионалы!


Немного теории



LTO или Link Time Optimization это оптимизация на этапе линковки(компоновки). Чтобы понять, что такое LTO рассмотрим как работают компиляторы. В большинстве компиляторов используется двух этапная модель: этап компиляции и этап линковки.

На этапе компиляции:

Парсятся исходные тексты программ, строится AST Абстрактное Синтаксическое Дерево.

  • Оптимизируется Абстрактное Синтаксическое Дерево. Оптимизируются циклы, удаляется мертвый код, результат которого нигде не используется. Раскрываются выражения, например 2+5 можно заменить на 7, чтобы при работе приложения не вычислять его значение каждый раз и тем самым сделать его быстрее и т.д.
  • Оптимизированное дерево может быть преобразовано в машинный псевдокод понятный компилятору. Псевдокод используется для дополнительной оптимизации, упрощает разработку универсального компилятора для разных архитектур процессора, например для x86-64 и ARMv7\. Так же как ASM листинг, этот псевдокод еще используется, чтобы понять, как компилятор генерирует машинный код, и служит для понимания работы компилятора, поиска ошибок, например, ошибок оптимизации и unpredictable behavior. Стоит заметить этот этап не является обязательным и в некоторых компиляторах отсутствует.
  • Происходит векторизация. Векторизация ,Automatic Vectorization, SIMD
  • Генерируется объектный файл. Объектный файл содержит в себе машинный код для компьютера, и специальные служебные структуры, в которых все еще есть неизвестные адреса функций и данных, поэтому этот файл все еще не может быть запущен на исполнение. Чтобы разрешить неизвестные адреса, был добавлен этап линковки.


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

На этапе линковки:

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


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

В Clang используется два вида LTO Оптимизации: Full LTO и Thin LTO. Full LTO это классическая реализация LTO оптимизации, которая обрабатывает конечный исполняемый файл за раз целиком и использует много оперативной памяти. Отсюда эта оптимизация занимает много времени, но дает на выходе самый быстрый код. Thin LTO это развитие LTO оптимизации, в которой нет оптимизации всего файла целиком, а вместо этого вместе с объектными файлами записывают дополнительные метаданные, и LTO оптимизатор работает с этими данными, что дает более высокую скорость получения оптимизированного исполняемого файла (скорость сравнима с линковкой файла без LTO оптимизации) и код сравнимый или чуть уступающий в производительности Full LTO. Но самое главное Full LTO может значительно увеличить размер файла, и код наоборот может из-за этого работать медленнее. Thin LTO лишен этого недостатка и в некоторых приложениях на практике мы можем получить лучшую производительность! Поэтому наш выбор будет сборка ядра Linux с Thin LTO.

Дополнительная информация:



Установка LLVM 12 и Clang



Поставить llvm и clang можно выполнив в консоли под root команду:

pacman -Syu base-devel llvm clang lld vim

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

Прошлая версия
На момент написания статьи, в дистрибутиве Arch Linux используются LLVM и Clang версии 11\. А LLVM и Clang версии 12 находятся в staging репозитории Arch Linux [LLVM](http://personeltest.ru/aways/archlinux.org/packages/staging/x86_64/llvm/). Staging репозиторий это репозиторий, где находятся версии пакетов, которые ломают приложения, зависящие от прошлой версии. Он используется для компиляции всех зависящих программ, и когда все они будут собраны, все пакеты за раз переходит в общий репозиторий. Например, в Arch Linux от LLVM и Clang версии 11 зависят blender, rust и qt creator и т.д. Если мы поставим LLVM и Clang версии 12, то они перестанут работать.
Upd. Пакет уже перешел в основной репозиторий. Так как мною одним из первых была произведена миграция на LLVM и Clang 12, то было придумано простое решение, создать пакет [llvm11-libs](http://personeltest.ru/aways/aur.archlinux.org/packages/llvm11-libs-bin/) с необходимыми библиотеками для обратной совместимости, который позволяет оставить зависимые программы рабочими. Но данный пакет работает только с моим сборочным пакетом [llvm12-git](http://personeltest.ru/aways/aur.archlinux.org/packages/llvm12-git/). Поэтому мы будем собирать LLVM и Clang 12 из исходников. Но вы можете дождаться, когда LLVM и Clang 12 появятся в основном репозитории Arch Linux или использовать 11 версию. Лично предпочитают новые версии ПО, и LLVM и Clang 12 лучше поддерживают мой процессор Ryzen 9 3900X. Плюс git версия закрыла часть багов компилятора и даже стабильнее релиза. Релизный архив с официального сайта у меня не проходит больше тестов при сборке чем git версия. Не стоит пугаться того, что часть тестов компилятор провалил, там нет критических багов для x84-64 архитектуры, и большая часть затрагивают другие компоненты, например openmp и lldb. За очень долгое время тестирования llvm и clang 12 мною не было замечено ни одного бага влияющего на работу системы. Стоит заметить, на данный момент 13 версия является очень сырой и нам не подходит!

Поставим llvm и clang 11 версии(Если 12 версия появилась в основном репозитории, то поставится 12я версия) можно выполнив в консоли под root команду:

pacman -Syu base-devel llvm clang lld libclc vim

Обновить Arch Linux и поставить новые версии программ можно командой(это будет полезно тем кто будет ждать официального выхода 12 версии, думаю это произойдет уже через пару дней):

pacman -Syu

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


Cборка LLVM 12 из Arch User Repository



Для сборки нам понадобиться git и нам надо будет собрать программу yay.

Поставим необходимые зависимости, для этого нам будут нужны права root: pacman -Syu base-devel git go vim

Если вы хотите собрать llvm 12 с помощью clang 11, то надо поставить еще их: pacman -S llvm clang

Отредактируем конфигурационный файл сборщика пакетов makepkg в Arch Linux и увеличим количество потоков для сборки программ. Это ускорит скорость сборки. Под root выполним: vim /etc/makepkg.conf

Найдем строки MAKEFLAGS и NINJAFLAGS. Нажмем латинскую букву A. Нам после -j надо указать количество потоков для сборки. Рекомендуется ставить ваше количество ядер или потоков процессора, если ядер 4, то ставим 4 или 8\. У меня это 20, 12 ядер 24 потока, 4 остаются запасными для других задач. Или используем автоматическое определение $(nproc).

В итоге получим:

MAKEFLAGS="-j20"NINJAFLAGS="-j20"

или

MAKEFLAGS="-j$(nproc)"NINJAFLAGS="-j$(nproc)"


Нажмем ESC, дальше SHIFT + :(буква Ж). Внизу появится : строка для ввода команд, вводим wq. w write, записать изменения в файл. q quit, выйти из vim. q! выход из vim без сохранения файла. Кому сложно разобраться с vim, в Linux есть замечательная программа, называется она vimtutor. Если у вас настроена правильно локаль, то vimtutor будет на русском, запустить его можно командой vimtutor. Стоит заметить, вопреки распространенному мнению, обучение у вас не займет много времени. Обычно новичков пугают мифом: vi и vim люди изучают очень долго, и осилить их могут только единицы. На самом деле это не так и там нет ничего сложного.

Под обычным пользователем клонируем репозиторий yay, собираем и устанавливаем:
git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -cfi

Импортирует открытый gpg ключ, он необходим для проверки подписи llvm12-git:
gpg --keyserver pgp.mit.edu --recv-keys 33ED753E14757D79FA17E57DC4C1F715B2B66B95

Поставим LLVM 12 и библиотеки совместимости с 11 версией. Стоит заметить, мой пакет LLVM 12 уже содержит все необходимые утилиты, включая Clang и LLD и их не надо ставить отдельно. Под обычным пользователем выполним команду: yay -Syu llvm12-git. Если llvm 12 есть в официальном репозитории, то llvm11-libs-bin не нужно ставить. Команда yay задаст вам несколько вопросов, нажмите Enter в ответ на все. Сборщик LLVM задаст 3 вопроса:

  • Build with clang and llvm toolchain? Собрать с помощью llvm и clang? Отвечаем Y или Enter если да, и N если нет. Рекомендую собирать LLVM с помощью Clang.
  • Skip build tests? Пропустить сборку тестов? Отвечаем Y или Enter. Так как во время сборки, не все тесты проходят проверку, то сборка будет прекращена. Поэтому мы пропускаем сборку тестов, и на самом деле сборка будет идти даже быстрее.
  • Skip build documentation? Пропустить сборку документации? Отвечаем Y или Enter если да, и N если нет. Если вам не нужна документация, то можно пропустить, это ускорит сборку. Лучше читать документацию на официальном сайте, это удобнее.
  • Skip build OCaml and Go bindings? Пропустить сборку OCaml и Go биндингов? Отвечаем Y или Enter если да, и N если нет. Для большинства ответ Y и их сборку можно смело пропустить в угоду скорости сборки. Для тех кому они нужны, а это очень маленькое количество людей могут ответить N.


Сборка может занять от 20 минут до пары часов. Ждете и в конце отвечаете Y на вопрос: хотите ли вы поставить собранные пакеты?

После установка LLVM надо собрать libclc12-git yay -S libclc12-git. libclc необходим для компиляции opencl и для сборки mesa.

Делаем LLVM и Clang сборочным тулчейном по умолчанию в Arch Linux



Большинство программ в Arch Linux собираются с помощью команды makepkg: man makepkg и PKGBUILD файлов. Поэтому в первую очередь внесем изменения в конфигурационный файл /etc/makepkg.conf. Выполним под root в консоли команду: vim /etc/makepkg.conf. Перейдем к строке CHOST="x86_64-pc-linux-gnu" поставим курсор на следующей пустой строке и нажмем латинскую букву A, и вставим после строки:

export CC=clangexport CXX=clang++export LD=ld.lldexport CC_LD=lldexport CXX_LD=lldexport AR=llvm-arexport NM=llvm-nmexport STRIP=llvm-stripexport OBJCOPY=llvm-objcopyexport OBJDUMP=llvm-objdumpexport READELF=llvm-readelfexport RANLIB=llvm-ranlibexport HOSTCC=clangexport HOSTCXX=clang++export HOSTAR=llvm-arexport HOSTLD=ld.lld

Дальше заменим строки CPPFLAGS, CXXFLAGS, LDFLAGS на содержимое ниже:

CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"

Если вкратце мы используем -O2 оптимизацию для всех программ, -fstack-protector-strong используем улучшенную защиту стека, что снижает вероятность потенциально опасных ошибок при работе со стеком в программах, она же включена у меня в ядре. Плюс на моем процессоре при сборке с Clang с -fstack-protector-strong код при работе с целыми числами работает чуть быстрее, при работе с числами с плавающей запятой есть небольшой оверхед. В GCC наоборот есть более заметный оверхед и производительность снижается. -march=native есть смысл заменить на ваш, у меня это -march=znver2 gcc.gnu.org/onlinedocs/gcc/x86-Options.html.

Изменим количество потоков в MAKEFLAGS и NINJAFLAGS для сборки программ. Это помогает ускорить сборку программ. После -j надо указать количество потоков для сборки. Рекомендуется ставить ваше количество ядер или потоков процессора, если ядер 4, то ставим 4 или 8\. У меня это 20, 12 ядер, 24 потока, 4 остаются запасными для других задач. Или используем автоматическое определение $(nproc).

В итоге получим:

MAKEFLAGS="-j20"
NINJAFLAGS="-j20"


или

MAKEFLAGS="-j$(nproc)"
NINJAFLAGS="-j$(nproc)"


Из DEBUG_CFLAGS и DEBUG_CXXFLAGS надо удалить -fvar-tracking-assignments. LLVM не поддерживает данный параметр.

Файл должен будет принять примерно такой вид:

CARCH="x86_64"CHOST="x86_64-pc-linux-gnu"CARCH="x86_64"CHOST="x86_64-pc-linux-gnu"#-- Compiler and Linker Flagsexport CC=clangexport CXX=clang++export LD=ld.lldexport CC_LD=lldexport CXX_LD=lldexport AR=llvm-arexport NM=llvm-nmexport STRIP=llvm-stripexport OBJCOPY=llvm-objcopyexport OBJDUMP=llvm-objdumpexport READELF=llvm-readelfexport RANLIB=llvm-ranlibexport HOSTCC=clangexport HOSTCXX=clang++export HOSTAR=llvm-arexport HOSTLD=ld.lldCPPFLAGS="-D_FORTIFY_SOURCE=2"CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"RUSTFLAGS="-C opt-level=2"#-- Make Flags: change this for DistCC/SMP systemsMAKEFLAGS="-j20"NINJAFLAGS="-j20"#-- Debugging flagsDEBUG_CFLAGS="-g"DEBUG_CXXFLAGS="-g"#DEBUG_CFLAGS="-g -fvar-tracking-assignments"#DEBUG_CXXFLAGS="-g -fvar-tracking-assignments"#DEBUG_RUSTFLAGS="-C debuginfo=2"

Нажмем ESC, дальше SHIFT + :(буква Ж). Внизу появится: строка для ввода команд, вводим wq. w write, записать изменения в файл. q quit, выйти из vim. q! выход из vim без сохранения файла. Кому сложно разобраться с vim, в Linux есть замечательная программа, называется она vimtutor. Если у вас настроена правильно локаль, то vimtutor будет на русском, запустить его можно командой `vimtutor`. Стоит заметить, вопреки распространенному мнению, обучение у вас не займет много времени. Обычно новичков пугают мифом: vi и vim люди изучают очень долго, и осилить их могут только единицы. На самом деле это не так и там нет ничего сложного.

Следующим этапом можно добавить настройки в файл .bashrc текущего пользователя. Не root, сборка программ под root очень плохая идея! Это относительно вредный совет и с помощью clang будут собираться все программы! Поэтому делайте это только если хорошо понимаете зачем это вам. Это можно сделать командой:

cat << 'EOF' >> "${HOME}/.bashrc"export CARCH="x86_64"export CHOST="x86_64-pc-linux-gnu"export CC=clangexport CXX=clang++export LD=ld.lldexport CC_LD=lldexport CXX_LD=lldexport AR=llvm-arexport NM=llvm-nmexport STRIP=llvm-stripexport OBJCOPY=llvm-objcopyexport OBJDUMP=llvm-objdumpexport READELF=llvm-readelfexport RANLIB=llvm-ranlibexport HOSTCC=clangexport HOSTCXX=clang++export HOSTAR=llvm-arexport HOSTLD=ld.lldexport CPPFLAGS="-D_FORTIFY_SOURCE=2"export CFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"export CXXFLAGS="-fdiagnostics-color=always -pipe -O2 -march=native -fstack-protector-strong"export LDFLAGS="-Wl,-O1,--sort-common,--as-needed,-z,relro,-z,now"export RUSTFLAGS="-C opt-level=2"export MAKEFLAGS="-j20"export NINJAFLAGS="-j20"export DEBUG_CFLAGS="-g"export DEBUG_CXXFLAGS="-g"EOF


Список системных библиотек и программ которые стоит собирать вручную


Внимание, сборка всех программ и все консольные команды надо выполнять под обычным пользователем, перед установкой у вас попросит пароль root. Сборка всех библиотек и программ из списка не занимает много времени. Все кроме Mesa у меня собирается в районе 1 минуты. Список дан в той в последовательности в которой рекомендуется сборка! К примеру от zlib-ng и zstd зависит Mesa, а от Mesa зависит xorg-server.

Самое первое, что надо сделать в Arch Linux это заменить zlib на zlib-ng. Это дает хороший выигрыш производительности в приложениях, которые зависят от zlib. Больше всего это заметно на веб браузерах и веб серверах, которые используют gzip сжатие для передачи данных. На высоко нагруженных серверах это дает очень значительную прибавку к производительности. Сборка довольно быстрая. Поставить можно командой(под обычным пользователем): yay -Syu zlib-ng. На вопрос хотите ли вы удалить zlib отвечайте Y. Не бойтесь библиотеки полностью взаимозаменяемы, и ничего не сломается!

Дальше у нас идет zstd это вторая по популярности библиотека используемая в ядре и в программах для сжатия данных. Поэтому имеет смысл собрать так же ее. Чтобы собрать, вам нужно скопировать содержимое zstd, создать директорию, например zstd, а в ней создать файл PKGBUILD и в него вставить содержимое по ссылке. Дальше в консоли перейти в директорию содержащую PKGBUILD, выполнить команду makepkg -cfi .

libjpeg-turbo Библиотека для работы c jpeg файлами. Ее очень часто используют браузеры и программы рабочего стола. libjpeg-turbo собранный с clang дает у меня лучшую производительность. Действия такие же, как в zstd. Создать директорию, и вставить в файл PKGBUILD содержимое по ссылке libjpeg-turbo. Дальше в консоли перейдите в директорию содержащую PKGBUILD, выполнить команду makepkg -cfi.

libpng Библиотека для работы с PNG файлами. По сборке и установке все то же самое. libpng. Для сборки вам понадобится патч: 72fa126446460347a504f3d9b90f24aed1365595.patch, его надо положить в одну директорию с файлом PKGBUILD. Для сборки надо внести изменения в PKGBUILD, заменить source и sha256sums на строки ниже, и добавить функцию prepare.

source=("https://downloads.sourceforge.net/sourceforge/$pkgname/$pkgname-$pkgver.tar.xz"  "72fa126446460347a504f3d9b90f24aed1365595.patch")sha256sums=('505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca'  '84298548e43976265f414c53dfda1b035882f2bdcacb96ed1bc0a795e430e6a8')prepare() {  cd $pkgname-$pkgver  patch --forward --strip=1 --input="${srcdir:?}/72fa126446460347a504f3d9b90f24aed1365595.patch"}


Mesa это святой грааль для всех графических приложений. Стоит собирать всегда вручную, дает хорошую прибавку в десктоп приложениях, улучшается отклик рабочего стола. Одно время сидел на git версии, чтобы получить лучшую поддержку новых видеокарт AMD. Вот мой PKGBUILD оптимизированный для сборки с помощью Clang.

Для сборки вам надо отредактировать файл mesa.conf и установить необходимые вам драйвера dri, gallium, vulkan для сборки. У меня сборка только под новые видеокарты AMD. Подглядеть можно тут: Mesa OpenGL, mesa-git package, Mesa Documentation. При выходе новой версии Mesa не забудьте сменить 21.1.2 на новую версию. А после смены версии обновите контрольные суммы файлов, выполнив в директории с PKGBUILD команду updpkgsums.

xorg-server X сервер с которым взаимодействуют почти все среды рабочего стола. Сборка дает заметное улучшение отклика рабочего стола. Сборка такая же через mapkepkg -cfi. Скачать необходимые файлы для сборки можно тут: xorg-server Сборочный пакет немного кривой и собирает пакет без оптимизаций. Поэтому его надо пропатчить. Для это после строки arch-meson ${pkgbase}-$pkgver build \ надо добавить строки:

  -D debug=false \  -D optimization=2 \  -D b_ndebug=true \  -D b_lto=true \  -D b_lto_mode=thin \  -D b_pie=true \

Полный список критических важных программ влияющих на производительность системы вы можете посмотреть в поем github репозитории arch-packages. Список был создан с помощью системного профилировщика perf. Все сборочные файлы оптимизированы для сборки с помощью llvm и сборка полностью автоматизирована. На моем ryzen 9 3900x сборка всего занимает около 20 минут. Единственный пакет который невозможно собрать с помощью clang и llvm это glibc. Его надо собирать вручную, и с оптимизацией -march= под ваш процессор, это самая часто вызываемая библиотека. Сборку glibc могут проводить только профессионалы, понимающие, что они делают. Не правильная сборка может сломать систему!

Для того, что бы воспользоваться автоматизированной сборкой надо выполнить(под обычным пользователем):
git clone https://github.com/h0tc0d3/arch-packages.git && cd arch-packages && chmod +x build.sh

Дальше нам надо установить все gpg сертификаты и зависимости необходимые для сборки, выполним ./build.sh --install-keys, а затем ./build.sh --install-deps

Для сборки программ достаточно просто запустить скрипт: ./build.sh --install, скрипт вам будет задавать вопросы, какие программы хотите собрать и поставить. На вопрос: хотите ли вы отправить все ваши деньги и пароли автору статьи? хотите ли вы заменить программы?(например, zlib-ng и zlib конфликтуют. Удалить zlib? [y/N] ) ответьте Y . Если вам нужна принудительная пересборка всех программ, то надо выполнить ./build.sh --install --force. По умолчанию, если пакет был уже собран и найден с нужной версией, то он не собирается, а просто устанавливается.

Для сборки mesa надо отредактировать файл mesa/mesa.conf и установить необходимые вам драйвера dri, gallium, vulkan для сборки.

С помощью команды ./build.sh --check можно проверить различия версий в моем репозитории и в официальном, помогает быстро адаптировать сборочные файлы и собрать актуальные версии программ. Слева версия в моем репозитории, справа от стрелки в официальном. Мой репозиторий может служить удобной тренировочной точкой на пути к созданию своего дистрибутива, создания LFS и развитию навыка пересборки ПО не ломая систему.

[+] zstd 1.5.0-1[+] libpng 1.6.37-3[+] libjpeg-turbo 2.1.0-1[+] mesa 21.1.2-1[+] pixman 0.40.0-1[-] glib2 2.68.3-1 -> 2.68.2-1[+] gtk2 2.24.33-2[+] gtk3 1:3.24.29-2[+] gtk4 1:4.2.1-2[+] qt5-base 5.15.2+kde+r196-1[+] icu 69.1-1[+] freetype2 2.10.4-1[+] pango 1:1.48.5-1[+] fontconfig 2:2.13.93-4[+] harfbuzz 2.8.1-1[+] cairo 1.17.4-5[+] wayland-protocols 1.21-1[+] egl-wayland 1.1.7-1[+] xorg-server 1.20.11-1[+] xorgproto 2021.4-1[+] xorg-xauth 1.1-2[+] xorg-util-macros 1.19.3-1[+] xorg-xkbcomp 1.4.5-1[+] xorg-setxkbmap 1.3.2-2[+] kwin 5.22.0-1[+] plasma-workspace 5.22.0-2[+] glibc 2.33-5


Сборка Ядра с помощью LLVM и Clang с LTO оптимизацией


Внимание! Сборку ядра необходимо выполнять под обычным пользователем. Перед установкой ядра у вас попросит sudo пароль. Не рекомендуется использовать патчи ядра linux-ck, linux-zen, MuQSS и т.д. Мною были протестированы все, при кажущемся увеличении производительности системы, происходят кратковременные лаги и снижается стабильность системы, некоторые подсистемы ядра работают не стабильно! С выходом ядра 5.11 стандартный планировщик работает не хуже и значительно стабильнее! Единственный патч который мною применяется это патч для применения оптимизации под процессор github.com/graysky2/kernel_gcc_patch Выбрать ваш процессор можно в меню конфигуратора ядра Processor type and features-->Processor family.

Сборка ядра с помощью LLVM описана в официальной документации Linux Kernel Build with LLVM. Но там есть несколько подводных моментов, которые не описаны. Первый подводный момент заключается в OBJDUMP=llvm-objdump, тут идет переопределение objdump, но так как параметры objdump в llvm имеет другой синтаксис, то при сборке будет пропущена часть тестов для проверки корректности сборки, и будет warning ругающийся на objdump. Правильно будет оставить родной objdump OBJDUMP=objdump

Неправильно:

make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \  READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ \  HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump


Правильно:

make CC=clang LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip \  READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ \  HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump

Второй подводный момент заключается в том, что если мы не добавим LLVM_IAS=1 в строку make, то нам не будет доступна LTO оптимизация в конфигураторе ядра!

Поэтому полная строка для сборки с LTO будет:

export BUILD_FLAGS="LLVM=1 LLVM_IAS=1 CC=clang CXX=clang++ LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump"make ${BUILD_FLAGS} -j$(nproc)

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

export BUILD_FLAGS="LLVM=1 LLVM_IAS=1 CC=clang CXX=clang++ LD=ld.lld AR=llvm-ar NM=llvm-nm STRIP=llvm-strip READELF=llvm-readelf HOSTCC=clang HOSTCXX=clang++ HOSTAR=llvm-ar HOSTLD=ld.lld OBJCOPY=llvm-objcopy OBJDUMP=objdump"tar -xf linux-5.12.10.tar.xz -C /tmpcd /tmp/linux-5.12.10zcat /proc/config.gz > .config # Берем конфигурацию запущенного ядра из /proc/config.gz и используем ее для сборкиecho "-mykernel" > .scmversionmake ${BUILD_FLAGS} oldconfigmake ${BUILD_FLAGS} -j$(nproc) nconfig

C помощью oldconfig конфигурация адаптируется под новое ядро и запускается конфигуратор nconfig. Подробнее о конфигураторах ядра можно прочесть в официальной документации [Kernel configurator](http://personeltest.ru/aways/www.kernel.org/doc/html/latest/kbuild/kconfig.html).

В конфигураторе переходим в General architecture-dependent option --> Link Time Optimization (LTO) и выбираем Clang ThinLTO (EXPERIMENTAL). Для дополнительной защиты стека в General architecture-dependent options ставим \* напротив Stack Protector buffer overflow detection и Strong Stack Protector. Жмем F9 и сохраняем новый конфигурационный файл. Далее идет список команд для сборки и установки нового ядра.

make ${BUILD_FLAGS} -j$(nproc)make ${BUILD_FLAGS} -j$(nproc) modulessudo make ${BUILD_FLAGS} -j$(nproc) modules_installsudo cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-mykernel

Следующий подводный момент заключается в DKMS, после установки ядра собранного с помощью Clang, DKMS пытается собрать модули ядра с помощью GCC. По этой причине сборка и установка DKMS модулей в новое ядро завершается ошибкой. Решение проблемы заключается в передаче DKMS компилятора Clang таким образом:

sudo ${BUILD_FLAGS} dkms install ${dkms_module} -k 5.12.10-mykernel


Автоматизация сборки ядра Linux



Для автоматизации сборки ядра мы будем использовать мой bash скрипт github.com/h0tc0d3/kbuild. Клонируем репозиторий и перейдем в рабочую директорию: git clone https://github.com/h0tc0d3/kbuild.git && cd kbuild && chmod +x kbuild.sh

Отредактируем файл build.sh или поместим содержимое ниже в файл ${HOME}/.kbuild. Рекомендуется второй способ vim "${HOME}/.kbuild" т.к. при обновлении скрипта наши настройки сохранятся. Если использовалось клонирование репозитория git, то в директории со скриптом можно выполнить команду git pull, чтобы обновить скрипт. Ниже даны параметры по умолчанию, они формируют поведение скрипта по умолчанию, если соответствующий параметр не был передан. Эти параметры в дальнейшем можно будет переопределить с помощью параметров командной строки для скрипта. Так же можно добавить команду в ваш .bashrc. Для этого в директории со скриптом kbuild.sh надо выполнить echo "alias kbuild='${PWD}/kbuild.sh" >> "${HOME}/.bashrc", ${PWD} автоматом заменит на текущую директорию. Или из любой другой директории можно указать полный пусть к скрипту echo "alias kbuild='полный-путь/kbuild.sh'" >> "${HOME}/.bashrc" После редактирования .bashrc необходимо перезапустить терминал! Теперь можно будет запускать скрипт командой kbuild --help .

KERNEL_VERSION='5.12.10'         # Версия Linux для сборки. Любая версия с официального сайта kernel.org, включая rc версии.KERNEL_POSTFIX='noname'         # Постфикс для названия ядра. Ядро будет иметь имя версия-постфикс, 5.12.10-noname, нужно для разделения в системе ядер с одной версией.KERNEL_CONFIG='/proc/config.gz' # Конфигурационный файл ядра. Поддерживает любые текстовые файлы и с жатые с расширением gz.KERNEL_CONFIGURATOR='nconfig'   # Конфигуратор ядра nconfig, menuconfig, xconfig.# Рекомендую использовать nconfig, он лучше menuconfig.# Можно писать полную строку, например MENUCONFIG_COLOR=blackbg menuconfig# Дополнительную информацию можно найти в документации к ядру https://www.kernel.org/doc/html/latest/kbuild/kconfig.htmlMKINITCPIO=1 # Запускать "mkinitcpio -p конфигурационный_файл" После сборки? 0 - Нет, 1 - Да.MKINITCPIO_CONFIG="${KERNEL_POSTFIX}" # Имя конфигурационного файла mkinitcpio, по умолчанию равно постфиксу.CONFIGURATOR=0      # Запускать конфигуратор ядра? 0 - Нет, 1 - Да. Если вам не нужно конфигурировать ядро, то можно поставить 0.LLVM=0              # Использовать LLVM Для сборки? 1 - Да, 0 - Нет(Будет использован GCC или другой системный компилятор по умолчанию)THREADS=8           # Количество поток для сборки. Ускоряет сборку. Для автоматического определения надо заменить на $(nproc)BUILD_DIR='/tmp'    # Директория в которой будет проходить сборки ядра. У меня 32gb оперативной памяти и сборка происходит в tmpfs.DOWNLOAD_DIR=${PWD} # Директория для сохранения архивных файлов с исходниками ядра. ${PWD} - в папке из которой запущен скрипт сборки.DIST_CLEAN=0    # Если директория с исходниками существует выполнять make disclean перед сборкой? 0 - Нет, 1 - ДаCLEAN_SOURCE=0  # Выполнять make clean после сборки ядра? 0 - Нет, 1 - ДаREMOVE_SOURCE=1 # Удалять директорию с исходными файлами ядра после сборки? 0 - Нет, 1 - Да.SYSTEM_MAP=0    # Копировать System.map в /boot После сборки? 0 - Нет, 1 - Да.PATCH_SOURCE=1                          # Применять патчи ядра? 0 - Нет, 1 - Да.PATCHES=("${HOME}/confstore/gcc.patch") # Список патчей ядра. Нельзя поменять с помощью параметров скрипта.DKMS_INSTALL=1                                        # Выполнять DKMS Install? 0 - Нет, 1 - Да.DKMS_UNINSTALL=1                                      # Выполнять DKMS Uninstall? 0 - Нет, 1 - Да.DKMS_MODULES=('openrazer-driver/3.0.1' 'digimend/10') # Список DKMS модулей, который нужно собрать и установить. Нельзя поменять с помощью параметров скрипта.

Внимание! Сборку ядра необходимо выполнять под обычным пользователем. Перед установкой ядра у вас попросит sudo пароль. Не рекомендуется использовать патчи ядра linux-ck, linux-zen, MuQSS и т.д. Мною были протестированы все, при кажущемся увеличении производительности системы, происходят кратковременные лаги и снижается стабильность системы, некоторые подсистемы ядра работают не стабильно. С выходом ядра 5.11 стандартный планировщик работает не хуже и значительно стабильнее! Единственный патч который мною применяется это патч для применения оптимизации под процессор github.com/graysky2/kernel_gcc_patch. Нас интересует файл more-uarches-for-kernel-5.8+.patch. Путь к нему имеет смысл указать в PATCHES. Выбрать ваш процессор можно в меню конфигуратора ядра Processor type and features-->Processor family.

Принцип работы скрипта:

1) set -euo pipefail скрипт переходит в строгий режим, в случае ошибок скрипт завершается с ошибкой. Является хорошим тоном, при написании bash скриптов. Скрипт проверяет запущен ли он под рут, если запущен под рут, то выдает ошибку и завершается. Загружается настройки пользователя из файла ${HOME}/.kbuild

2) Скрипт проверяет существование директории linux-версия в директории BUILD_DIR. Если существует, то исходники распакованы. Перед сборкой может выполняться команда make distclean, поведение задается переменной DIST_CLEAN. Если этой директории не существует, то проверяется существование файла linux-версия.tar.gz

или linux-версия.tar.xz. Если файл найден, то он распаковывается в BUILD_DIR. Иначе файл скачивается с kernel.org в директорию DOWNLOAD_DIR.

3) Скрипт применяет патчи ядра и устанавливает постфикс для версии ядра(записывает его в файл .scmversion ).

4) Скрипт копирует настройки ядра из файла KERNEL_CONFIG в .config и выполняет make oldcofig для адаптации настроек под новое ядро и запускает конфигуратор ядра.

5) Скрипт собирает ядро и модули.

6) Скрипт удаляет модули DKMS из ядра которое сейчас запущено, если это необходимо. Это необходимо, чтобы в списке dkms status не отображались мертвые ядра. Удаляет директорию `/lib/modules/версия-постфикс` если она существует. Она существует в том случае, если мы собираем одну и туже версию несколько раз. Это дополнительная защита от unpredictable behavior .

7) Скрипт устанавливает модули ядра, копирует ядро в /boot/vmlinuz-постфикс.

8) Скрипт собирает DKMS модули и устанавливает их. Копирует System.map в /boot/System-постфикс.map, если это необходимо.

9) Обновляет загрузочный img файл для ядра. Выполняет mkinitcpio -p конфиг.

10) Выполняет make clean если необходимо. Удаляет директорию linux-версия в директории BUILD_DIR, если это необходимо.

Собрать ядро с llvm можно командой ./kbuild.sh -v 5.12.10 --llvm --start или kbuild -v 5.12.10 --llvm --start, если был установлен alias. -v 5.12.10 указывает версию ядра для сборки, --llvm указывает собирать ядро с помощью llvm и clang. --start указывает, что надо запускать конфигуратор ядра. Получить справку по параметрам скрипта можно выполнив команду kbuild --help.

Русская справка
Параметры: Описание: Пример:
--version, -v Версия ядра для сборки --version 5.12.10 | -v 5.13-rc4
--postfix, -p Постфикс ядра --postfix noname | -p noname
--config, -c Файл конфигурации ядра --config /proc/config.gz | -c /proc/config.gz
--dir, -d Директории сборки --dir /tmp | -d /tmp
--download, -z Директория загрузки --download /tmp | -z /tmp
--threads, -t Количество потоков сборки --threads 8 | -t 8
--configurator, -x Конфигуратор ядра --configurator nconfig | -x "MENUCONFIG_COLOR=blackbg menuconfig"

--start, -s Запускать конфигуратор
--disable-start, -ds Не запускать конфигуратор

--mkinitcpio, -mk Запускать mkinitcpio после установки ядра
--disable-mkinitcpio, -dmk Не запускать mkinitcpio после установки ядра
--mkinitcpio-config, -mc Конфиг mkinitcpio --mkinitcpio-config noname | -mc noname

--llvm, -l Использовать LLVM
--disable-llvm, -dl Не использовать LLVM

--patch, -ps Применять патчи ядра
--disable-patch, -dp Не применять патчи ядра

--map, -m Копировать System.map в /boot/System-постфикс.map
--disable-map, -dm Не копировать System.map

--clean, -cs Чистить исходники после сборки. make clean
--disable-clean, -dc Не чистить исходники после сборки.
--distclean, -cd Чистить исходники перед сборкой. make distclean
--disable-distclean, -dd Не чистить исходники перед сборкой.
--remove, -r Удалять директорию с исходниками после сборки
--disable-remove, -dr Не удалять директорию с исходниками после сборки

--dkms-install, -di Устанавливать DKMS модули
--disable-dkms-install, -ddi Не устанавливать DKMS модули
--dkms-uninstall, -du Деинсталлировать DKMS модули перед их установкой
--disable-dkms-uninstall, -ddu Не деинсталлировать DKMS модули перед их установкой

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

--stop-download, -sd Стоп посл загрузки файла
--stop-extract, -se Стоп после распаковки архива с исходниками
--stop-patch, -sp Стоп после применения патчей ядрей
--stop-config, -sc Стоп после конфигуратора ядра
--stop-build, -sb Стоп после сборки ядра
--stop-install, -si Стоп после установки нового ядра и модулей




Как можно понять из статьи сборка ядра с LLVM и Clang относительно простая. И самое главное можно автоматизировать сборку и установку ядра, и в дальнейшем не тратить много времени на сборку новых ядер.

Всем кто дочитал до конца, спасибо! Комментарии и замечания приветствуются!


Подробнее..

Как я сделал свою сборку Gulp для быстрой, лёгкой и приятной вёрстки

03.06.2021 18:21:18 | Автор: admin

Серьёзно и профессионально я начал заниматься вёрсткой в 2019 году, хотя до этого ещё со школы интересовался данной темой как любитель. Поэтому новичком мне себя назвать сложно, но и профессионалом с опытом 5+ лет я тоже не являюсь. Тем не менее, я успел познакомиться со сборщиком Gulp, его плагинами и сделал для себя хорошую, как по мне, сборку для работы. О её возможностях сегодня и расскажу.

ВАЖНО! В этой статье речь пойдёт о самой последней версии сборки. Если вы пользуетесь версиями сборки, вышедшими до публикации этой статьи, информация будет для вас не релевантна, но полезна.

Какие задачи решает эта сборка?

  • вёрстка компонентами (вам не нужно в каждую страницу копировать head, header, footer и другие повторяющиеся элементы, вплоть до кнопок или кастомных чекбоксов);

  • вёрстка с препроцессорами (SASS/SCSS);

  • конвертация шрифтов из ttf в eot, woff, woff2;

  • лёгкое (почти автоматическое) подключение шрифтов;

  • лёгкое (почти автоматическое) создание псевдоэлементов-иконок;

  • обработка изображений "на лету";

  • минификация html/css/js файлов;

  • возможность вёрстки с использованием php;

  • выгрузка файлов на хостинг по FTP;

  • несколько мелких задач с помощью миксинов.

Для тех, кому лень читать и делать всё руками - сразу ссылка на сборку.

Собственно создание сборки

Начнём собирать нашу сборку (простите за тавтологию). Предварительно нам потребуется уже установленная на компьютере LTS-версия Node.js и NPM (входит в пакет Node.js) либо Yarn. Для нашей задачи не имеет значения, какой из этих пакетных менеджеров использовать, однако я буду объяснять на примере NPM, соответственно, для Yarn вам потребуется нагуглить аналоги NPM-команд.

Первое, что нам нужно сделать - это инициализировать проект. Открываем директорию проекта в командной строке (очень надеюсь, вы знаете, как это делается) и вводим команду npm init.

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

Далее будет намного удобнее работать через Visual Studio Code (поскольку у него есть встроенный терминал) или любой другой удобный вам редактор + терминал.

Прежде всего, нам нужно установить сам Gulp. Делается это двумя командами npm i gulp -global - устанавливаем Gulp глобально на систему и npm i gulp --save-dev - устанавливаем Gulp локально в проект. Ключ --save здесь отвечает за сохранение версии плагина при дальнейшей установке (без него вам может установить более новую, несовместимую с другими плагинами версию), а ключ -dev указывает на то, что этот пакет необходим только во время разработки проекта, а не во время его выполнения. Например, если мы устанавливаем в проект пакет Swiper, который содержит скрипты слайдера и будет отображаться на странице, мы будем устанавливать его без ключа -dev, поскольку он нужен для выполнения, а не для разработки.

После того, как Gulp установился, имеет смысл создать в корне проекта управляющий файл gulpfile.js, в котором мы и будем писать задачи для сборщика.

После этого нам нужно подключить Gulp в нашем файле, для того чтобы он исполнялся. Это делается с помощью require:

const gulp = require('gulp');

Далее, для каждой задачи будем использовать модули в отдельных файлах. Для того, чтобы не подключать каждый модуль отдельно, нужно установить и подключить плагин require-dir. Устанавливается он всё той же командой (как и все последующие плагины, поэтому далее повторяться не буду, просто знайте, что установить - это npm i $PLUGIN-NAME$ --save-dev). После установки подключаем его и прописываем путь к директории, в которую будем складывать модули (у меня это директория tasks):

const gulp = require('gulp');const requireDir = require('require-dir');const tasks = requireDir('./tasks');

Первая задача

Давайте проверим, всё ли мы правильно сделали. Создадим в директории tasks файл модуля с именем hello.js. В созданном файле напишем простейшую функцию, которая будет выводить в консоль строку "Hello Gulp!" (можете придумать что-то менее банальное, если хотите).

module.exports = function hello () {console.log("Hello Gulp!");}

Теперь вернёмся в gulpfile.js и зададим там задачу hello:

const gulp = require('gulp');const requireDir = require('require-dir');const tasks = requireDir('./tasks');exports.hello = tasks.hello;

Теперь командой gulp hello в терминале запустим нашу задачу. Если всё сделано правильно - в терминал должно вывестись приблизительно такое сообщение:

[13:17:15] Using gulpfile D:\Web projects\Easy-webdev-startpack-new\gulpfile.js[13:17:15] Starting 'hello'...Hello Gulp![13:17:15] The following tasks did not complete: hello[13:17:15] Did you forget to signal async completion?

Так же, можно получить список всех заданных задач командой gulp --tasks.

Файловая структура

Теперь, когда мы создали первую функцию, можно подумать о том, какая структура будет у наших проектов. Я предпочитаю использовать директорию (папку) /src для хранения исходных файлов и директорию /build для готовых файлов проекта.

В директории src/ нам понадобятся следующие поддиректории:
  • components/ - директория для компонентов

  • components/bem-blocks/ - директория для БЭМ-блоков

  • components/page-blocks/ - директория для типовых блоков страницы, таких как хедер, футер и т.п.

  • fonts/ - директория для шрифтов

  • img/ - директория для изображений

  • js/ - директория для файлов JavaScript

  • scss/ - директория для файлов стилей

  • scss/base/ - директория для базовых стилей, которые мы изменять не будем

  • svg/ - директория для файлов SVG

  • svg/css/ - директория для SVG-файлов, которые будут интегрироваться в CSS

Получиться в итоге должно приблизительно следующее:

 project/  build/ 
Подробнее..

Перевод Алюминиевый профиль как универсальный ресурс для сборки чего угодно. Часть 1

06.06.2021 16:09:40 | Автор: admin

Еще недавно профиль типа Т-слот (T-slot) был не самым популярным, но после того, как его стали применять в конструкции многих моделей 3D-принтеров, он появился везде и всюду. Теперь он используется для сборки тех же 3D-принтеров, лазерных резаков, станков с ЧПУ.

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

Почему профиль удобен?



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

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

Типы профилей и их особенности


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


Кстати, есть профили, изготовляемые по метрической системе, есть по имперской. Называют профиль (в данном случае квадратный) по его размерности. Например, квадратный профиль с длиной стороны 20мм будет называться профиль 20Х20. Официально такой профиль называется алюминиевый станочный профиль 20Х20.


Конечно, есть и другие формы профиля, некоторые из них весьма экзотические. Есть профили с полукруглым корпусом, есть с треугольным. У каждой формы собственное предназначение, все зависит от цели мастера и проекта. Пример такого проекта ниже. Авторы его, семейная пара, собрали шикарный стол из профиля и ДСП.


Крепление к профилю


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


Проще всего сразу вкрутить болт в кронштейн, навернуть гайку, потом вставить конструкцию в паз профиля, установить на место и потом уже закрутить гайку. Здесь стоит учитывать длину болта она должна быть такой, чтобы пройти через кронштейн и гайку, не касаясь профиля с другой стороны. Например, если толщина кронштейна 10мм, толщина гайки 6мм, то длина болта в идеале должна составлять 15 мм. Если болт будет слишком коротким, то закрепить деталь надежно не удастся, более того, гайка может просто соскочить в самый неожиданный момент.


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

Соединение профилей между собой


При необходимости концы профилей можно надежно закрепить друг с другом при помощи специальных коннекторов. Большинство вариантов соединений показаны вот в этом видео:


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

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

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

Аксессуары


Их огромное количество, продаются они там же, где и профили. Есть накладки, ножки, ролики, пружины, ручки и петли, равно, как и другие элементы. На любом сайте 3D-печати есть файлы как этих, так и любых других элементов для крепежей. Это могут быть держатели катушек, держатели для инструментов, лампы и т.п.

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

Где достать профиль?


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

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

Немного о 3D-печати креплений


Кронштейны и крепления можно печатать на принтере, о чем говорилось выше. Если есть достаточное количество пластика, можно распечатать и сам профиль. Т-гайки, о которых говорилось выше, тоже можно печатать.


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

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

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

Подробнее..

Готовьсь, цельсь, пли! Как не обжечься при сборке Gradle-приложения, и настолько ли всё серьезно?

18.03.2021 16:05:16 | Автор: admin

Доброго дня, читатель! Меня зовут Стручков Михаил и я Android-разработчик в команде мобильного оператора Yota.

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

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

Очень сложно рассмотреть работу всю работу с Gradle в одной статье, поэтому планирую последовательно пополнять список:

  1. Готовьсь, цельсь, пли! Как не обжечься при сборке Gradle-приложения, и настолько ли всё серьезно?

  2. Пишем свой Gradle-плагин

  3. Пишем эффективные Gradle-задачи

Для удобства навигации по статье, ниже представлено оглавление:

Структура проекта

Инициализация

Конфигурация плагинов

Подключение Gradle-проектов и композитная сборка

Конфигурация

Управление зависимостями

Типы зависимостей

Производительность конфигурации

Как сделать задачу для этапа конфигурации?

Немного о buildSrc

Куда вынести общую логику билдскриптов?

Сборка

Коротко про Gradle Task

Gradle Daemon

Несколько советов по оптимизации скорости сборки

Заключение

Список докладов

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

В этой статье поговорим про основные этапы сборки Gradle-приложения - инициализацию, конфигурацию и сборку, и про то, как нам с ними обращаться при работе. Для своих примеров я буду использовать Kotlin и конфигурацию на Kotlin DSL. Стильно, модно. Kotlin в сравнении c Groovy привносит много удобств. Ведь теперь мы можем легко выяснить - что и где, и какого оно типа, а Gradle API наконец начинает нам в этом помогать. С Groovy этого определенно не хватало. Кто еще не в курсе, в документации хорошо рассказано о том, как попробовать Kotlin DSL.

Структура проекта

Итак, главная сущность в мире Gradle это Project. Project-ом выступает само наше приложение, которое мы только что создали. У project-а могут быть subproject-ы, у subproject-а могут быть свои subproject-ы, и таким образом получается древовидная структура. Хорошей практикой является подход, при котором степень вложенности не превышает двух. Такая структура подходит для большинства проектов. При этом subproject-ы можно просто называть Gradle-модулями.

Если вы пользуетесь IDE от JetBrains или Android Studio, по умолчанию они не дадут вам создать иерархию больше двух (для стандартных проектов), что уже наталкивает на мысль, что так делать не стоит.

На картинке снизу subproject-ы (Gradle-модули) - это app и lib. Корнем Gradle-структуры является сам проект (вот эта маленькая точка сверху):

Project узнаёт обо всех своих subproject из файла конфигурации settings.gradle (.kts). Написанный здесь скрипт будет выполняться на этапе инициализации проекта.

Инициализация

Итак, в settings.gradle (.kts) мы определяем содержимое нашего приложения, и учим Gradle к нему подступаться. В самом начале задаем имя нашего проекта:

rootProject.name = "myproject"

Теперь мы можем легко его получить из любого subproject-а на последующих этапах.

Конфигурация плагинов

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

Внутри блока pluginsесть возможность указать дефолтную версию для плагина, если не используется никакая другая. При этом эту версию можно брать извне, например, из gradle.properties:

val helloPluginVersion: String by settingspluginManagement {plugins {id("com.example.hello") version "${helloPluginVersion}"}}

gradle.properties:

helloPluginVersion=1.0.0

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

По умолчанию все наши плагины подключаются из gradlePluginPortal. Если же плагин необходимо достать из другого репозитория, в блоке repositories можно его определить. Например, мы хотим подключить Android Gradle Plugin. Он лежит в гугловском репозитории, что и объявляем явно:

repositories {gradlePluginPortal()google()}

Готово! Теперь можно добавить зависимость Android Gradle Plugin в classpath (о котором чуть позже) и затем успешно подключать Android-плагины в билдскриптах.

В блоке resolutionStrategy мы можем определить правила для подключения плагинов, используемых проекте. На коде ниже приведен пример того, как можно хитрым образом динамически подключить Android Gradle Plugin на тот случай, если в проекте он начнёт использоваться:

resolutionStrategy {  eachPlugin {    if (requested.id.namespace == "com.android") {      useModule("com.android.tools.build:gradle:${requested.version}")    }  }}

После такого финта ушами, AGP автоматически подключится в classpath по необходимости.Здесь в поле requested находится реквест плагина, который мы явно сформировали:

build.gradle.kts (root):

plugins {  id("com.android.application") version "4.1.0" apply false}

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

Важный момент: версию плагинов в явном виде стоит определять именно в рутовом build.gradle (.kts). Если сделать это как-то по-другому, чаще всего будет появляться следующее:

Caused by: org.gradle.plugin.management.internal.InvalidPluginRequestException: Plugin request for plugin already on the classpath must not include a version

Реже следующее:

Caused by: java.lang.IllegalArgumentException: org.gradle.api.internal.initialization.DefaultClassLoaderScope@68d65269 must be locked before it can be used to compute a classpath!

Полный зоопарк. Я не буду загружать подробностями (ибо у автора тоже с них взрывается мозг), но суть такова, что рутовый build.gradle (.kts) является для этого централизованным местом.

Подключение Gradle-проектов и композитная сборка

Далее с помощью includeобъявляем существующие в нашем проекте подпроекты (они же по-простому gradle-модули). При этом, если модуль лежит где-то в другом месте и вообще он гриб, можно явно указать, как и где его найти с помощью project:

include("some-subproject")project("some-subproject").projectDir = file("../somesubproject")project(":some-subproject ").buildFileName = "some-subproject.gradle"

И последнее, но не менее интересное includeBuild. С помощью него можно определить проект, который мы бы хотели собрать, и определить интерфейс до сборки основного проекта. Таким образом, имеем возможность организовать композитную сборку:

includeBuild("some-other-project") {  dependencySubstitution {    substitute(module("org.sample:mysample")).with(project(":"))   }}

C помощью лямбды в dependencySubstitution можно подменить зависимости, используемые в includeBuild-проекте, в том числе на те, что предоставляет наш проект, как на примере выше.

Где можно использовать композитную сборку?

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

После этого можно пользоваться всеми радостями отладки от IDE: ставить брейкпоинты, просматривать значения переменных и т.д. при выполнении кода Gradle-плагина.

P.S. Отладить таким образом можно не только Gradle-плагин, но и все содержимое build.gradle (kts), и в том числе на Groovy!Где ещё может пригодиться композитная сборка, поговорим немного дальше по ходу статьи.

Также settings.gradle (.kts) может с успехом отсутствовать. В этом случае Gradle поймёт, что других модулей проекте нет, и на этом успокоится.

Многие уже привыкли видеть settings.gradle (.kts) как скрипт, где только перечислены все известные в приложении Gradle-проекты. По опыту починки различных поломок с Gradle могу сказать, что сюда посмотрят в последнюю очередь. Если есть возможность не дописывать сложную логику сюда, лучше этого не делать. В большинстве случаев эту логику можно реализовать в build.gradle (.kts) рутового Gradle-проекта, что будет более очевидно для других разработчиков.

После выполнения инициализации Gradle создает объекты типа Project, с которыми мы продолжаем работу уже на этапе конфигурации.

Конфигурация

Также известна под именами Sync Project With Gradle Files, Load Gradle Changes, Reload All Gradle Projects. На данном этапе главными игроками выступают билдскрипты build.gradle (.kts).

Механизм достаточно простой - для построенного дерева Gradle-проектов на этапе инициализации последовательно вызывается соответствующий билдскрипт. Здесь выполняется следующее:

  1. Резолвятся и загружаются зависимости для каждого из известного в settings.gradle (.kts) Gradle-проекта;

  2. Строится граф выполнения Gradle-задач для этапа сборки;

  3. Определяются переменные и конфигурируются данные для выполнения задач на этапе сборки.

О подкапотном пространстве 2 и 3 этапов предлагаю поговорить в статье про Gradle-задачи и в комментариях, а сейчас давайте немного сосредоточимся на том, как быть с зависимостями.

Управление зависимостями

Для подключения зависимостей в Gradle-проект существует два ключевых блока: repositoriesи dependencies.

repositories {  mavenCentral()  maven(url = "https://www.myrepo.io")  flatDir {    dirs("lib1", "lib2")}} dependencies {  implementation(kotlin("stdlib"))}

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

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

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

В блоке buildscript определяются зависимости, которые необходимо загрузить и положить в classpath для их доступности на этапе конфигурации:

buildscript {  repositories {    //...  }  dependencies {    classpath("com.android.tools.build:gradle:$agpVersion")}}

На примере выше я добавляю зависимость от Android Gradle Plugin чтобы использовать com.android.* плагины для конфигурации Android-приложения.

Для подключения зависимостей на этапе сборки, блоки dependencies и repositoriesдобавляются в корень билдскрипта build.gradle (.kts). В качестве зависимостей могут быть как другие gradle-проекты, так и внешние/локальные библиотеки:

dependencies {  runtimeOnly(group = "org.springframework", name = "spring-core", version = "2.5")  implementation(fileTree(mapOf("include" to listOf(".jar"), "dir" to "libs")))  implementation(kotlin("stdlib"))  implementation(project(:project-a))}

Для подключения Gradle-проектов используется символ :. С его помощью мы определяем путь, по которому лежит подключаемый Gradle-проект относительно рутового Gradle-проекта.

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

Could not resolve project :project-a.Required by:    project :project-b

, а в худшем - c NullPointerException, и проблему тогда станет искать намного сложнее.

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

Типы зависимостей

У Gradle бывают два типа зависимостей - runtime и compile-time. Хорошо объясняет положение вещей следующий рисунок:

При подключении зависимостей в compileClasspath, мы получим runtime exception при попытке достучаться до кода зависимости во время выполнения, поскольку зависимость не попала в приложение. Но в то же время код зависимости будет доступен на этапе сборки проекта. Подключая зависимости в runtimeClasspath, мы гарантируем их попадание в приложение, а значит, и безопасность выполнения кода в runtime. Здесь-то и приходит понимание, что implementation и api добавляют зависимости в оба classpath-а. При этом api также позволяет получить доступ к коду gradle-проекта в случае его транзитивного подключения.

В качестве apiElements и runtimeElements на рисунке обозначен код, который мы хотим отдать на использование в другие gradle-модули.

Производительность конфигурации

Gradle старается, насколько это возможно, оптимизировать процесс конфигурации. Наша задача этому не мешать, а именно, стараться не взаимодействовать с другими gradle-проектами на этапе конфигурации напрямую. Это приводит к связности проектов и замедляет скорость конфигурации.

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

subprojects {  apply(plugin = "java")    repositories {    mavenCentral()  }    tasks.register<MyTask>("myTask")}

Такие блоки можно определить в root-проекте, поскольку он и так неявно связан со всеми подпроектами. Но стоит помнить, что выполнение подобного трюка в дочернем проекте оставит негативный след на скорости конфигурации. Если потребность всё же есть, лучше сделать зависимость между Gradle-задачами на этапе сборки.

Как сделать задачу для этапа конфигурации?

У Gradle есть на этот случай колбэки. Самый простой способ добавить колбэк для этапа конфигурации определить блоки afterEvaluate или beforeEvaluate. Блок afterEvaluate можно использовать, например, в случае, когда мы хотим добавить задачу в граф выполнения и хотим, чтобы она выполнялась по определенному правилу. Например, после задачи myTask, как на примере ниже:

аfterEvaluate {  tasks.all {    if (this is org.jetbrains.kotlin.gradle.tasks.KotlinCompile) {      dependsOn(tasks.named("myTask"))    }  }}
Почему не следует использовать dependsOn

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

Чтобы избежать подобных проблем, задачи следует связывать с помощью их inputs и outputs. В этом случае в качестве бонуса мы получим еще и инкрементальность (aka up-to-date проверки), что значительно снизит время повторной сборки. Чтобы во всем разобраться, можно посмотреть доклад Степана Гончарова (таймкод) и пример из документации.

Немного о buildSrc

Еще одна вещь, о которой я не могу не упомянуть, это buildSrc. Модуль buildSrc собирается каждый раз перед конфигурацией нашего рутового проекта и поставляется на этап конфигурации в виде jar. Его довольно удобно использовать для объявления зависимостей, а также содержать общую логику для билдскриптов. Подробнее о том, как использовать buildSrc в Gradle-проекте хорошо описано в этой статье.

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

P.S. Сейчас в нашем проекте несколько десятков модулей и сложно сказать, что проблема buildSrc ощутимо по нам ударила. Но я не исключаю, что в относительно близкое время композитный билд действительно станет нашим будущим.

Куда еще можно вынести общую логику билдскриптов?

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

build.gradle (Gradle-модуля):

 apply from: common.gradle

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

Если вы пишете подключаемые билдскрипты на Kotlin DSL, то они обязательно должны лежать в buildSrc. Связано это с тем, что Kotlin-скрипт должен быть скомпилирован перед использованием. При этом для подключения нужно выполнить небольшой финт ушами и в build.gradle (.kts) модуля buildSrc добавить следующее:

build.gradle.kts (buildSrc):

plugins {`kotlin-dsl``kotlin-dsl-precompiled-script-plugins`}

Теперь можем добавить Kotlin-скрипт в buildSrc/src/main/kotlin (java):

common.gradle.kts:

dependencies {  add("implementation", "org.sample:some-shared-dependency:1.0.0")}

И подключить его вот так:

build.gradle.kts (Gradle-модуля):

apply(id = "common")//...

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

Для того, чтобы связать Kotlin и Groovy, в Kotlin-скрипты можно подключать стандартные *.gradle с помощью того же apply:

build.gradle.kts (Gradle-модуля):

apply(from = "common.gradle")//...

Сборка

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

Коротко про Gradle Task

Gradle Task представляет собой единицу работы, которую выполняет сборка. К примеру, это может быть компиляция классов, создание JAR, создание документации Javadoc или публикация в репозиторий.

Простейшим вариантом написать задачу для этапа сборки является реализация лямбды в doFirst/doLast, как на примере ниже:

tasks.register("printAllProjectNames") {  group = project names  description = Prints all projects names  doFirst {    println(Start execution)  }  doLast {    println("Root project name is: ${project.name}") project.subprojects.forEach { project ->      println("Child project name is: ${project.name}")    }  }

Задаче очень желательно добавлять description и group,чтобы без лишних телодвижений было понятно, чем она занимается. После добавления group задачу будет удобно искать и запускать:

Задачу можно выполнить также и через консоль с помощью команды:

gradle ${your_task_name}

Gradle Daemon

Непосредственным выполнением сборки занимается Gradle Deamon. Он включен по умолчанию для Gradle версии 3.0 и выше. Gradle Daemon является долгоживущим системным процессом, периодически осуществляющим сборку, когда мы этого хотим. Внутри него происходит много in-memory кеша, оптимизации работы с файловой системой и оптимизации кода выполнения сборки. Если коротко - всё идет на пользу. Пожалуй, исключение только одно - он довольно прожорлив, и Gradle любит держать несколько демонов на разные случаи жизни. Если система начинает ощутимо лагать, всегда можно всех за раз прибить командой

gradle --stop

Несколько советов по оптимизации скорости сборки

Нетрудно понять, что сборка - это самый трудозатратный этап, занимающий львиную долю всего времени работы Gradle. Есть несколько базовых рекомендаций для того, как нам её ускорить, первая из которых - запастись терпением:

  1. Параллельное выполнение тасок.

    Всё просто - org.gradle.parallel=true в вашем gradle.properties, и Gradle будет стараться максимально распараллелить выполнения тасок на этапе сборки. Этот параметр по умолчанию включен при создании проекта.

  2. Обновление Gradle.

    Gradle важно периодически обновлять. Связано это с тем, что с каждой версией в Gradle привносят улучшения по скорости сборки, исправления багов и новые интересные плюшки. Для удобства обновления, был придуман Gradle Wrapper (или просто Wrapper).Это ни что иное, как обычная Gradle-задача. Теперь для обновления версии можно написать в рутовом build.gradle (.kts) следующее:

    tasks.withType<Wrapper> {  val projectGradleVersion = "6.8.3"  gradleVersion = projectGradleVersion}
    

    , а затем выполнить команду gradle wrapper. Или же выполнить

    gradle wrapper --gradle-version ${gradle_version}
    

    , где вместо gradle_version указываем желаемую версию Gradle. Тем самым Gradle сам загрузит нужную версию и положит её в папку с проектом. Она же будет использоваться в дальнейшем по умолчанию, а счастливые мы сможем запускать задачи с помощью скрипта gradlew, который появится в папке с нашим проектом.

  3. Правильное использование api/implementation.

    При изменении реализации зависимости Gradle пересобирает "на холодную" все зависящие от неё модули. Я уже упомянул про api и implementation в разговоре о способах подключения зависимостей, и теперь понятно, что при подключении зависимости через api, она также транзитивно попадает в classpath-ы модулей, в которые мы подключили наш модуль. Тем самым увеличивается количество модулей, которые gradle будет пересобирать при изменении зависимости. Если нет необходимости в транзитивном использовании кода из зависимости, для её подключения следует использовать implementation.

  4. Инкрементальность и build-кеш.

    Оптимизация Gradle позволяет нам пропускать выполнение задачи при определенных условиях. У Gradle существует 5 состояний задач - EXECUTED, UP-TO-DATE, FROM-CACHE, SKIPPED и NO-SOURCE. В разговоре про кеш нам интересны два из них - UP-TO-DATE и FROM-CACHE. Они сигнализируют о том, что результаты выполнения наших тасок были успешно подтянуты гредлом из результатов предыдущей сборки. Об остальных состояниях можно почитать в документации.

    UP-TO-DATE. Возникает в случае, если разработчик задачи позаботился о ней и самостоятельно реализовал инкрементальность её выполнения (проверки на up-to-date), или же все зависимости этой задачи, если они есть, были успешно взяты из кеша, или признаны гредлом up-to-date.

    FROM-CACHE. Это состояние возникает в случае, если Gradle смог восстановить outputs задачи из билд-кеша. При этом по умолчанию build-cache выключен. Build-cache довольно удобно использовать на CI, таким образом ускорив выполнение пайплайнов Gradle-сборки. Как организовать build-cache всегда можно узнать тут.

    При использовании билд-кеша в локальных сборках, знаменитый Clean/Rebuild теряет свою магическую силу, поскольку параметры для задач всегда будут тянуться из Gradle-кеша. Однако для больших проектов отсутствие кеша может быть проблемой, поскольку время сборки "на холодную" способно занимать несколько десятков минут. Если это ваш случай, и вы сталкивались с проблемами инвалидации кеша, напишите в комментариях.

Бонус для дочитавших до конца: Gradle-плагины

Gradle-плагины являются своеобразными контейнерами, в которых может содержаться логика инициализации, конфигурации и сборки. Как правило, плагины используются для внедрения какой-то законченной бизнес-логики в Gradle. На самом деле, плагин есть ни что иное как обычный интерфейс с одним методом apply, где в качестве generic-типа чаще всего выступает Project:

public interface Plugin<T> {  void apply(T target);}

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

Пожалуй, самыми яркими примерами будут являться представители из Android Gradle Plugin: "com.android.application" и "com.android.library". Подключая их в билдскрипты, мы получаем возможность собирать и конфигурировать сборку Android-приложений.

Подключать плагины в наши билдскрипты мы можем с помощью apply:

apply(plugin = "com.android.application")

, или в блоке plugins:

plugins {  `application`}

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

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

Заключение

Gradle действительно мощный инструмент для сборки проектов, хоть и работа с ним не всегда проста. После появления возможности использовать Kotlin для реализации своих Gradle-задумок, магия постепенно начинает уходить и на stackoverflow хочется заходить реже. К тому же Gradle ведут работу над созданием хорошей документации, что, несомненно, очень радует (правда, её космический объём не остановит только настоящих энтузиастов).

И конечно же, Gradle это open-source. Можете с удовольствием скрасить один из вечеров в репозитории Gradle на Github.

К сожалению, показать весь Gradle в одной, и даже в двух статьях очень сложно. Думаю, теперь самое время ответить для себя на риторический вопрос - на самом ли деле всё настолько серьёзно?

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

Список докладов

Степан Гончаров - Gradle [A-Z]. Доклад про Gradle под капотом, объясняет способы реализации Gradle-тасок и (о боже) про недостатки Kotlin DSL.

Stefan Oehme - Composite Builds with Gradle. Доклад про суть композитной сборки в Gradle и способах ее применения (на английском).

Филипп Уваров - Gradle Plugin Development. Доклад с AppsConf про разработку Gradle-плагинов. Раскрывает область применения плагинов, способы их реализации и по каждому их преимущества/недостатки.

Подробнее..

Сборка ArmorPaint из исходников

20.10.2020 18:21:10 | Автор: admin
Главное окно программыГлавное окно программы

Итак, прежде всего, что такое ArmorPaint? Это автономный программный пакет для рисования PBR текстур на 3D моделях. Автор продает готовые сборки за 16 евро, но сборка из исходных текстов на GitHub бесплатна. Сам пакет автором рекомендуется использовать в связке с ArmorEngine - игровой движок интегрированный в Blender.

Кому не хочется читать

Итак, приступим. Нам потребуется следующее ПО:

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

Visual Studio нам потребуется версия Community 2019, в установщике устанавливаем следующие опции:

Скачиваем и устанавливаемСкачиваем и устанавливаем

Далее Git:

Создаем папку под скачанные исходники, лучше поместить их корневой директории диска, например D:/apbuild

Запускаем GitCMD через администратора:

Здесь будем вводить команды из гитхабЗдесь будем вводить команды из гитхаб

Вводим следующие команды:

Тут мы переходим в папку которую создалиТут мы переходим в папку которую создали

Потом вводим следующее по очереди:

git clone --recursive https://github.com/armory3d/armorpaintcd armorpaint

Первая команда скачает исходники а второй вы перейдете в папку armorpaint которая создастся в apbuild. Далее вводим в Git по очереди следующие команды до # Open generated Visual Studio project

node armorcore/make -g direct3d11cd armorcore# Unpack `v8\libraries\win32\release\v8_monolith.7z` using 7-Zip - Extract Here (exceeds 100MB)// это архивgit apply patch/window_handling.diff --directory=Kincnode Kinc/make -g direct3d11# Open generated Visual Studio project# Set `Project - Properties - Debugging - Command Arguments` to `..\..\build\krom`# Build for x64 & release

Затем мы компилируем шейдеры командой 1, переходим в armorcore, в проводнике по пути v8\libraries\win32\release\v8_monolith.7z распаковываем архив monolith.7z. В архиве библиотека, помещаем ее в ту же папку с архивом.

Выполнив команды до строк с хэштегом, открываем Visual Studio. но сначала переходим в проводнике apbuild/armorpaint/kromx/build, ищем файл Krom.vcxproj. Щелкаем по нему и переходим в Visual Studio.

Копируем и вставляем в свойства проекта VS следующую строчку ..\..build\krom

Нажимаем OK и закрываем окноНажимаем OK и закрываем окно

Сборка и релиз

В верхнем тулбаре выставляем release и x64. Правой кнопкой мыши по проекту Krom (справа), вызываем контекстное меню и нажимаем собрать. Сборка завершена. Нажимаем локальный отладчик windows, собранная программа запускается. Для обновления исходников, по мере обновления можно вставить перед сборкой следующие строчки по очереди:

git pull origin mastergit submodule update --init --recursive

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

Подробнее..

Как восстановить данные с RAID 50 контроллер HP P410 Smart Arraу. Гайд для новичков

25.04.2021 00:12:13 | Автор: admin
Гайд для новичков по восстановлению данных с аппаратного RAID 50, который собран на контроллере HP P410. Также расскажем, как собирать такой RAID, заменить неисправный носитель и что предпринять если контроллер HP P410 перестал работать.

image



Сам по себе RAID 5 один из самых надежных типов массивов, в то же время, производительность у него не на столь высоком уровне. Но, если объединить несколько таких групп, мы получим RAID 50, который показывает высокий уровень производительности. А также более высокую эффективность использования места RAID массива по сравнению с обычным пятым типом.

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

Как собрать RAID50 в BIOS контроллера и с помощью программы


Чтобы собрать RAID50 вам понадобиться как минимум шесть дисков. Контроллер HP P410 позволяет собрать дисковый массив с помощью БИОСа и специальной утилиты.

Чтобы попасть в БИОС контроллера во время загрузки, после инициализации устройства нажмите клавишу F8.

image

Далее, если все носители пустые и не состояли в других массивах откройте пункт Create Logical Drive. Если с этих накопителей ранее уже собирался RAID его нужно сперва удалить так как в процессе построения контроллер может их не отобразить.

image

Для этого перемещаемся ниже до пункта Delete Logical Drive, чтобы открыть его жмем Enter. Здесь клавишами навигации вверх/вниз выбираем не нужные нам носители и удаляем их F8, а также F3 для подтверждения. После записи конфигурации нажмите Enter.

image

Теперь переходим непосредственно к процессу создания RAID 50. Переходим в пункт Create Logical Drive пробелом отмечаем все накопители, из которых будем собирать наш будущий массив.

image

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

image

Для подтверждения записи конфигурации нажмите F8 и Enter для продолжения. Чтобы посмотреть информацию о массиве откройте View logical Drive, если все верно, жмем клавишу Esc для выхода из меню настроек и дальнейшей загрузки.

image

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

image

Собираем массив с помощью HP Array Configuration Utility


Для того чтобы собрать массив из загруженной операционной системы, воспользуйтесь утилитой HP Array Configuration Utility или HPE Smart Storage Administrator, скачать ее можно с официального сайта производителя контроллера.

На вкладке Configuration выберите ваш контроллер, в правой части окна нажмите Create Array.

image

Отметьте носители, из которых будет состоять ваш будущий RAID и нажмите Ok.

image

Далее кликните по Create logical Drive, выбираем тип, число групп, размер блока, если нужно задайте определенный размер, активируйте кеширование, а затем Save для подтверждения. Массив создан, осталось его разметить в управлении дисками.

image

Как заменить диск


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

image

Если, есть дополнительный слот для подключения, можно вставить новый носитель без замены и назначить его запасным. После чего контроллер автоматически определит битый диск и начнет ребилд с новым носителем. Назначить носитель запасным можно в BIOS, в разделе Create Logical Drive. В этом пункте отметить его как запасной.

Процесс ребилда можно проконтролировать в HPE Smart Storage Administrator.

Как восстанавливать данные


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

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

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

image

Программа отображает все доступные о RAID данные.

image

Кликаем по иконке диска ПКМ и запускаем Быстрое сканирование. Отмечаем нужные файлы и каталоги и нажимаем Восстановить. Далее, указываем путь для их сохранения, опять кликаем Восстановить. Когда процесс сохранения завершиться, все файлы будут лежать указанном вами каталоге.

image

Если Быстрое сканирование не помогло, и большинство файлов восстановить не удалось, то запустите Полный анализ.

Восстановление без двух дисков, как собрать в RAID конструкторе


Если программа не смогла правильно определить тип массива в автоматическом режиме, RAID можно пересобрать вручную с помощью RAID-конструктором. Для этого вам понадобиться вспомнить всю информацию о вашем массиве.

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

Указав все параметры нажмите Добавить. Теперь он появится в менеджере дисков. Осталось его просканировать и вернуть оставшиеся данные.

image

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

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

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru