• Дистрибутив собранный в Yocto Project

    Berserk

    Мультимедиа центр - платформой для которого является Raspberry PI базируется на версии Kodi 17.6 Версия операционной системы собрана с помощью системы сборки "Yocto Project". читать далее

    Коди в Yocto Project
  • Yocto Project

    Роутер на Raspberry PI

    Сборка маршрутизатора c "нуля" для Raspberry Pi c использованием системы сборки "Yocto Project" читать далее

    Маршрутизатор с нуля
  • Феерический хранитель экрана

    Kodi Universe

    Проект является простым плагином для Kodi. Проект показывает как можно создать очень красивый хранитель экрана целиком опираясь на работу "open source" мирового сообщества. читать далее

    Феерический Хранитель экрана
  • примеры проектов

    Raspberry Pi

    Разное → Raspberry Pi — что можно сделать на основе «малинки»?read more

    Ссылка на статью с Хабрахабра
  • Дистрибутив собранный в Yocto Project

    Berserk

    Мультимедиа центр - платформой для которого является Raspberry Pi базируется на версии Kodi 17.6 Версия операционной системы собрана с помощью системы сборки "Yocto Project". читать далее

Мультимедиа центр Kodi
и Yocto Project





дата: 14.09.2019 (версия 0.2.5)

Основная статья находится на Хабре



предыдущая версия статьи: Мультимедиа центр Kodi и Yocto Project (09.07.2018 версия v0.2.1)



Введение в Yocto Project


Yocto Project - это совместный Open Source проект для упрощения разработки дистрибутивов для встраиваемых систем. Yocto содержит большое количество шаблонов, метаданных и инструментальных средств сборки. В Yocto Project вы можете подключить большое количество BSP (пакет поддержки платформы) слоев для всевозможных аппаратных платформ.

Основное назначение статьи - это попытка показать сборку типового дистрибутива в Yocto Project
на примере хорошо известного мультимедиа центра Kodi, версии 17.6 для платы прототипирования "Raspberry Pi" 3B.

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

Статья является сугубо практической и демонстрирует возможности использования наработок Yocto Project и OpenEmbedded для сборки мультимедиа центра "Kodi". Управление слоями Yocto осуществляется с помощью утилиты Repo от Google.

Итак: поехали


Знакомство с Yocto Project

Показать/Скрыть

The Yocto Project – это Open Source-проект, целью которого является упрощение разработки специальных дистрибутивов Linux для встраиваемых систем и обеспечение их переносимости между различными платформами.





Знакомство с Yocto Project


Будучи проектом совместного сотрудничества (иногда такие проекты называются "зонтичными"), Yocto Project охватывает различные составляющие процесса разработки. Эти составляющие именуются проектами в рамках общего проекта Yocto Project и включают в себя инструменты для сборки, метаданные инструкций по сборке (называемые рецептами), библиотеки, утилиты и графические интерфейсы.



Poky


Poky – это эталонная система сборки в рамках проекта Yocto Project. Она включает в себя BitBake, OpenEmbedded-Core, пакет поддержки платформы (Board Support Package, BSP), а также прочие пакеты и компоненты, объединенные в единую сборку. Название Poky также относится к эталонному дистрибутиву Linux, который создается этой системой сборки и может быть чрезвычайно минималистичным (core-image-minimal) или же представлять собой полноценную систему Linux с графической оболочкой (core-image-sato)


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


Для всех систем сборки требуется наличие инструментария toolchain, состоящего из компилятора, ассемблера, линковщика и прочих двоичных утилит, необходимых для создания исполняемых файлов для той или иной архитектуры. Poky использует набор GNU Compiler Collection (GCC), но вы можете указать и другие наборы компиляторов. В Poky используется механизм кросс-компиляции: использование набора компиляторов одной архитектуры для создания исполняемых файлов другой архитектуры (например, сборка ARM-дистрибутива, выполняемая на компьютере с x86-архитектурой). Разработчики часто используют кросс-компиляцию при разработке встраиваемых систем, поскольку их рабочие компьютеры намного мощнее, чем типичная встраиваемая система.


Набор метаданных


Набор метаданных разделен на слои, каждый из которых обладает дополнительной функциональностью по отношению к нижележащим слоям. Базовый слой называется OpenEmbedded-Core (или oe-core) и содержит общие рецепты, классы и связанные с ними функции, необходимые для любой сборки. Эти сборки впоследствии можно настраивать под собственные нужды, добавляя новые слои поверх слоя oe-core.


OpenEmbedded-Core совместно поддерживается проектами Yocto Project и OpenEmbedded. Слой, отделяющий проект Yocto Project от проекта OpenEmbedded, называется meta-yocto и содержит конфигурацию дистрибутива Poky, а также базовый набор эталонных BSP-пакетов. Сам по себе проект OpenEmbedded является отдельным Open Source-проектом, обладающим собственными схожими рецептами и задачами, но со своей отдельной командой руководителей и областью применения.






Описание мультимедиа центра Kodi

Показать/Скрыть

Kodi — универсальный мультимедиа центр, ранее известный как XBMC (Xbox Media Center).


XBMC (Xbox Media Center) — изначально задуманный и разрабатывающийся как открытый мультимедиа плеер для игровой приставки XBox, позже портированный на GNU / Linux. За более чем десятилетний срок разработки приложение не один раз сменило имя, в августе 2014 года было принято решение дать проекту имя Kodi, сохраняя порядок версий и функционал.


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


Расширения Kodi имеет открытый API, что позволяет сторонним разработчикам создавать множество расширений: плагины, скрипты, темы оформления, Web-интерфейсы и многое другое. Разработчики Kodi поощряют создание и распространение пользовательских расширений, предоставляя возможность их установки непосредственно из Kodi. Последние релизы построены по новой архитектуре Addons Framework’а, включают в себя Addons Manager GUI, клиент децентрализованного распространения расширений, который использует сторонние сервисы, предоставляющие контент для Kodi. «Addons Manager» («Addons Browser») позволяет пользователям напрямую загружать расширения.






Содержание:


	Установка Yocto Project в Ubuntu
	Механизм сборки дистрибутива в Yocto Project
	Использование OpenEmbedded совместно c Yocto Project
	Пакет поддержки платформы (BSP)
	Управление слоями Yocto c помощью Repo
	    Установка Repo 
	    Манифест для сборки дистрибутива
	    Содержимое Манифеста
	    Описание Манифеста
	    Структура bs-manifest
	    Инициализация переменных Poky
	    Инициализация Repo
	    Синхронизация Repo
	Создание конфигурации Yocto Project
	    Конфигурационный файл build/conf/local.conf
	    Конфигурационный файл build/conf/bblayers.conf 
	Слой для сборки мультимедиа центра
	    Структура слоя
	    Конфигурация слоя
	    Состав recipes-berserk
	    Состав recipes-core
	    Состав recipes-kernel
	    Состав recipes-mediacentre
	    Состав recipes-multimedia
	    Дополнение рецепта для сборки Kodi
	    Добавление нового пункта в меню настроек Kodi
	    Максимальные настройки буферизации для видео
	Просмотр телевидения по протоколу IPTV
	Просмотр Youtube с помощью Kodi плагина
	Консольное shell расширение конфигурации сети    
	Описание хранителя экрана
	Рецепт сборки дистрибутива
	Краткая инструкция по созданию образа дистрибутива
	Постскриптум
	


Установка Yocto Project в Ubuntu


Для сборки дистрибутива с помощью Yocto Project в Ubuntu вам необходимо установить следующие пакеты:

	
	sudo apt-get install -y --no-install-suggests --no-install-recommends \
	gawk wget git-core diffstat unzip texinfo gcc-multilib \
	build-essential chrpath socat cpio python python3 python3-pip python3-pexpect \
	xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \
	xterm
	
	

Пакеты устанавливаются с помощью команды apt-get install и команды повышения привилегий - sudo.
В системе Ubuntu это широко распространенная практика, когда для выполнения административных действий используется команда sudo (при создании основного пользователя системы, он автоматически прописывается в группу "sudo").

Более подробную инструкцию по установки вы можете посмотреть здесь: здесь:

Механизм сборки дистрибутива в Yocto Project


В Yocto Project каждая программная единица описывается с помощью рецепта сборки. Язык описания рецепта напоминает "bash" c возможностью вставок частей кода на языке "python". Основную информацию по синтаксису вы можете почерпнуть из руководства Yocto Project . Набор рецептов сборки в зависимости от назначения можно объединять в отдельные слои сборки.

Слои разделяются на аппаратно зависимые - BSP слои, UI слои (пользовательского интерфейса), специфические Yocto слои, а также слои реализующие определенную функциональность:
например слои из OpenEmbedded => multimedia, python, perl, ruby, networking, systemd, webserver и т.д.



Использование OpenEmbedded совместно c Yocto Project


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

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



Пакет поддержки платформы (BSP)


Пакет поддержки платформы (Board Support Package, BSP) - это отдельный, специализированный слой(и) для конкретной платы, который определяет аппаратные особенности платформы т.е. реализует те специфические вещи, которые отличают одну плату от другой: особенности процессора, прерывания, адресация, особенности загрузчика, особенности видео адаптера (GPU) и т.д.

В этой статье используется BSP слой - meta-raspberrypi
Репозиторий слоя располагается по адресу: https://git.yoctoproject.org/git/meta-raspberrypi



Управление слоями Yocto c помощью Repo


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

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

Repo - это основной инструмент для управления GIT репозиториями при сборке операционной системы "Андроид" с его большой кодовой базой. Repo позволяет в одном проекте управлять десятком, если не сотней отдельных гит репозиториев, версии которых вы можете аккуратно указать в одном xml файле Манифеста

и для правильной синхронизации всех версий всех репозиториев вам достаточно выполнить одну команду

repo sync

Установка Repo


c помощью следующего набора команд вы можете установить Repo в ваш домашний каталог ~/bin (команду curl можно установить отдельно: sudo apt-get install curl)

        mkdir ~/bin
	curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
	chmod a+x ~/bin/repo 

Примечание:
в ОС Ubuntu каталог HOME/bin должен добавляться с стандартный путь запуска автоматически,
вы можете в этом убедиться проверив файл HOME/.profile
пример наличие строки:

PATH="$HOME/bin:$HOME/.local/bin:$PATH"

и в дальнейшем вам достаточно использовать в консоли команду: repo



Манифест для сборки дистрибутива


Дистрибутив, собираеммый в рамках статьи, мне нужно как то назвать. Пусть это будет имя Torvin
Под кодовым названием Torvin будет содержаться минималистический Linux дистрибутив со сборкой одной единственной программы. Имеется ввиду одна прикладная пользовательская программа - Kodi, и ничего лишнего (все остальное системный уровень). Для мультимедиа центра на мой взгляд этого вполне достаточно.
История названия Показать/Скрыть

	
	Примечание hehehe:
	Это не тот Torvin, который дуболом, а тот Torvin который дубощит 
	или скорее этот:
	
	Перед ним небольшая долина, укрытая от взглядов. На земле кругом сидят 
	сорок-пятьдесят человек. У всех мечи или топоры, но копья воткнуты 
	в землю, щиты лежат. Они сидят в пределах огороженного пространства. 
	По краям воткнуты копья, между ними протянуты нити. А на нитях яркие 
	гроздья рябины, теперь, осенью, они уже красные. В центре огороженного
	пространства горит костер, вокруг него и сидят люди. Рядом с костром 
	одно копье, острием вверх, наконечник блестит серебром. У костра и копья
	стоит человек спиной к тайным зрителям, он говорит о чем-то, убеждая,
	приказывая. В отличие от всех остальных, его одежда не из естественной
	окраски домотканой материи, она не окрашена в зеленый, синий или коричневый
	цвет. Одежда ослепительно белая, как белок яйца. На боку у человека молот, 
	с короткой рукоятью, с двусторонней головкой, – кузнецкий молот.
	...
	           "Гарри-Гаррисон, роман: Молот и крест"
	
	
	

Содержимое Манифеста


Для управления слоями дистрибутива используется файл torvin-0.2.5.xml


	<?xml version="1.0" encoding="UTF-8"?>
	<manifest>
	
	  <default sync-j="4" revision="rocko"/>
	
	  <remote fetch="https://git.yoctoproject.org/git" name="yocto"/>
	  <remote fetch="https://github.com/openembedded" name="oe"/>
	  <remote fetch="https://github.com/berserktv" name="bs"/>
	
	
	  <project remote="bs" revision="master" name="bs-manifest" path="sources/bs-manifest">
	    <linkfile dest="setup-environment" src="setup-environment"/>
	    <linkfile dest="shell.sh" src="raspberry/shell.sh"/>
	    <linkfile dest="sources/base" src="raspberry/rocko"/>
	  </project>
	
	  <project remote="yocto" revision="rocko" name="poky" path="sources/poky"/>
	  <project remote="oe"    revision="rocko" name="meta-openembedded" path="sources/meta-openembedded"/>
	  <project remote="yocto" revision="rocko" name="meta-raspberrypi"  path="sources/meta-raspberrypi"/>
	  <project remote="bs"    revision="rocko" name="berserk" path="sources/berserk"/>
	
	</manifest>
	

Описание Манифеста


В начале манифеста тегами remote обозначены два основных GIT репозитория и один вспомогательный:
  • https://git.yoctoproject.org/git - Yocto репозиторий, именованный как yocto
  • https://github.com/openembedded - OpenEmbedded репозиторий, именованный как oe
  • https://github.com/berserktv - вспомогательный GIT репозиторий, именованный как bs

  • В следующей части манифеста с помощью сокращенных именований осуществляется работа с проектами расположенными в этих репозиториях, тег project содержит следующие атрибуты:
  • remote - имя удаленного именованного репозитория
  • revision - название ветки или hash версии
  • name - имя проекта в указанном репозитории
  • path - локальный путь проекта в вашей файловой системе

  • 	Пример работы тега
    	<project remote="bs" revision="master" name="bs-manifest" path="sources/bs-manifest">
    	</project>
    	
    	данный xml тег описывает выполнение следующей команды:
    	 
    	git clone https://github.com/berserktv/bs-manifest -b master sources/bs-manifest
    	

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

    	Пример указания тегов linkfile
    	<project remote="bs" revision="master" name="bs-manifest" path="sources/bs-manifest"> 
    	  <linkfile dest="setup-environment" src="setup-environment">
    	  <linkfile dest="shell.sh" src="raspberry/shell.sh">
    	  <linkfile dest="sources/base" src="raspberry/rocko">
    	</project>
    	
    	Создание символической ссылки разворачивается примерно
    	в следующую команду: ln -s src dest
    	т.е.
    	      # создание двух ссылок на файлы
    	      ln -s sources/bs-manifest/setup-environment  setup-environment
    	      ln -s sources/bs-manifest/raspberry/shell.sh shell.sh 
    	      
    	      # создание ссылки на каталог, разворачивается
    	      # примерно в следующий набор команд
    	      cd sources
    	      ln -s bs-manifest/raspberry/rocko base 
    	

    Структура bs-manifest


    	├── COPYING.MIT
    	├── raspberry
    	│   ├── rocko
    	│   │   ├── conf
    	│   │   │   ├── bblayers.conf
    	│   │   │   └── local.conf
    	│   │   └── torvin-0.2.5.xml
    	│   └── shell.sh
    	├── README.md
    	└── setup-environment
    	

    Проект bs-manifest используется для гибкого управления конфигурациями, с учетом сборок разных версий дистрибутива. У меня это версия - 0.2.5



    Инициализация переменных Poky


    Скрипт начальной инициализации setup-environment был взят из проекта Freescale Community. Скрипт отвечает за стартовую инициализацию переменных системы сборки Poky, скрипт создает структуру каталогов, в которой очень хорошо разделяется:

    • build - каталог сборки
    • source - исходный код рецептов сборки
    • download - каталог загрузки кода программ (git базы, tar.gz архивы)

    Содержимое скрипта setup-environment: Показать/Скрыть
     
    	#!/bin/sh
    	# -*- mode: shell-script; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
    	#
    	# Copyright (C) 2012, 2013, 2016 O.S. Systems Software LTDA.
    	# Authored-by:  Otavio Salvador <otavio@ossystems.com.br>
    	#
    	# This program is free software; you can redistribute it and/or modify
    	# it under the terms of the GNU General Public License version 2 as
    	# published by the Free Software Foundation.
    	#
    	# This program is distributed in the hope that it will be useful,
    	# but WITHOUT ANY WARRANTY; without even the implied warranty of
    	# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    	# GNU General Public License for more details.
    	#
    	# You should have received a copy of the GNU General Public License along
    	# with this program; if not, write to the Free Software Foundation, Inc.,
    	# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    	#
    	# Add options for the script
    	# Copyright (C) 2013 Freescale Semiconductor, Inc.
    	
    	CWD=`pwd`
    	PROGNAME="setup-environment"
    	
    	usage()
    	{
    	    echo -e "\nUsage: source $PROGNAME <build-dir>
    	    <build-dir>: specifies the build directory location (required)
    	
    	If undefined, this script will set \$MACHINE to 'imx6qsabresd'.
    	"
    	
    	    ls sources/poky/*/conf/machine/*.conf > /dev/null 2>&1
    	    if [ $? -eq 0 ]; then
    	        echo -e "
    	Supported machines: `echo; ls sources/poky/*/conf/machine/*.conf \
    	| sed s/\.conf//g | sed -r 's/^.+\///' | xargs -I% echo -e "\t%"`
    	
    	To build for a machine listed above, run this script as:
    	MACHINE=<machine> source $PROGNAME <build-dir>
    	"
    	    fi
    	}
    	
    	clean_up()
    	{
    	   unset EULA LIST_MACHINES VALID_MACHINE
    	   unset CWD TEMPLATES SHORTOPTS LONGOPTS ARGS PROGNAME
    	   unset generated_config updated
    	   unset MACHINE SDKMACHINE DISTRO OEROOT
    	}
    	
    	# get command line options
    	SHORTOPTS="h"
    	LONGOPTS="help"
    	
    	ARGS=$(getopt --options $SHORTOPTS  \
    	  --longoptions $LONGOPTS --name $PROGNAME -- "$@" )
    	# Print the usage menu if invalid options are specified
    	if [ $? != 0 -o $# -lt 1 ]; then
    	   usage && clean_up
    	   return 1
    	fi
    	
    	eval set -- "$ARGS"
    	while true;
    	do
    	    case $1 in
    	        -h|--help)
    	           usage
    	           clean_up
    	           return 0
    	           ;;
    	        --)
    	           shift
    	           break
    	           ;;
    	    esac
    	done
    	
    	if [ "$(whoami)" = "root" ]; then
    	    echo "ERROR: do not use the BSP as root. Exiting..."
    	fi
    	
    	if [ -z "$MACHINE" ]; then
    	    usage && clean_up
    	    return 1
    	fi
    	
    	# Check the machine type specified
    	LIST_MACHINES=`ls -1 $CWD/sources/poky/*/conf/machine $CWD/sources/*/conf/machine`
    	VALID_MACHINE=`echo -e "$LIST_MACHINES" | grep ${MACHINE}.conf$ | wc -l`
    	if [ "x$MACHINE" = "x" ] || [ "$VALID_MACHINE" = "0" ]; then
    	    echo -e "\nThe \$MACHINE you have specified ($MACHINE) is not supported by this build setup"
    	    usage && clean_up
    	    return 1
    	else
    	    if [ ! -e $1/conf/local.conf.sample ]; then
    	        echo "Configuring for ${MACHINE}"
    	    fi
    	fi
    	
    	if [ -z "$SDKMACHINE" ]; then
    	    SDKMACHINE='i686'
    	fi
    	
    	if [ -z "$DISTRO" ]; then
    	    DISTRO='poky'
    	fi
    	
    	OEROOT=$PWD/sources/poky
    	if [ -e $PWD/sources/oe-core ]; then
    	    OEROOT=$PWD/sources/oe-core
    	fi
    	
    	# Ensure all files in sources/base are kept in sync with project root
    	updated=
    	#for f in $CWD/sources/base/*; do
    	#    file="$(basename $f)"
    	#    if [ "$file" = "conf" ] || echo $file | grep -q '~$'; then
    	#        continue
    	#    fi
    	#
    	#    if ! cmp -s "$file" "$f"; then
    	#        updated="true"
    	#        [ -e $file ] && chmod u+w $file
    	#        cp $f $file
    	#    fi
    	#done
    	if [ "$updated" = "true" ]; then
    	    echo "The project root content has been updated. Please run '$PROGNAME' again."
    	    return
    	fi
    	
    	. $OEROOT/oe-init-build-env $CWD/$1 > /dev/null
    	
    	# if conf/local.conf not generated, no need to go further
    	if [ ! -e conf/local.conf ]; then
    	    clean_up && return 1
    	fi
    	
    	# Clean up PATH, because if it includes tokens to current directories somehow,
    	# wrong binaries can be used instead of the expected ones during task execution
    	export PATH="`echo $PATH | sed 's/\(:.\|:\)*:/:/g;s/^.\?://;s/:.\?$//'`"
    	
    	generated_config=
    	if [ ! -e conf/local.conf.sample ]; then
    	    mv conf/local.conf conf/local.conf.sample
    	
    	    # Generate the local.conf based on the Yocto defaults
    	    TEMPLATES=$CWD/sources/base/conf 
    	    grep -v '^#\|^$' conf/local.conf.sample > conf/local.conf
    	    cat >> conf/local.conf <<EOF
    	
    	DL_DIR ?= "\${BSPDIR}/downloads/"
    	EOF
    	    # Change settings according environment
    	    sed -e "s,MACHINE ??=.*,MACHINE ??= '$MACHINE',g" \
    	        -e "s,SDKMACHINE ??=.*,SDKMACHINE ??= '$SDKMACHINE',g" \
    	        -e "s,DISTRO ?=.*,DISTRO ?= '$DISTRO',g" \
    	        -i conf/local.conf
    	
    	    cp $TEMPLATES/* conf/
    	
    	    for s in $HOME/.oe $HOME/.yocto; do
    	        if [ -e $s/site.conf ]; then
    	            echo "Linking $s/site.conf to conf/site.conf"
    	            ln -s $s/site.conf conf
    	        fi
    	    done
    	
    	    generated_config=1
    	fi
    	
    	cat <<EOF
    	
    	Welcome to Freescale Community BSP
    	
    	The Yocto Project has extensive documentation about OE including a
    	reference manual which can be found at:
    	    http://yoctoproject.org/documentation
    	
    	For more information about OpenEmbedded see their website:
    	    http://www.openembedded.org/
    	
    	You can now run 'bitbake <target>'
    	
    	Common targets are:
    	    core-image-minimal
    	    meta-toolchain
    	    meta-toolchain-sdk
    	    adt-installer
    	    meta-ide-support
    	
    	EOF
    	
    	if [ -n "$generated_config" ]; then
    	    cat <<EOF
    	Your build environment has been configured with:
    	
    	    MACHINE=$MACHINE
    	    SDKMACHINE=$SDKMACHINE
    	    DISTRO=$DISTRO
    	EOF
    	else
    	    echo "Your configuration files at $1 have not been touched."
    	fi
    	
    	clean_up
    	


    Содержимое скрипта shell.sh: Показать/Скрыть
     
    	#!/bin/bash
    	
    	MACHINE='raspberrypi3' source ./setup-environment build
    	
    	echo "you may try 'bitbake core-image-minimal'"
    	bash
    	

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

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


    Для инициализации repo необходимо выполнить команду:

    
    	mkdir torvin
    	cd torvin
    	repo init -u https://github.com/berserktv/bs-manifest -m raspberry/rocko/torvin-0.2.5.xml
    	

    где -u https://github.com/berserktv/bs-manifest указывает GIT путь к проекту манифеста

    примечание: можно еще указать -b имя_ветки , если ключ -b не указывать, то подразумевается ветка master (по умолчанию)

    где путь -m raspberry/rocko/torvin-0.2.5.xml к конфигурационному файлу указывает следующее:

    1. имя аппаратной платформы для которой осуществляется сборка — raspberry
    2. имя основной рабочей ветки Yocto/OpenEmbedded — rocko
    3. кодовое имя версии — torvin (все версии серии 0.2.x)
    4. и наконец цифровой номер версии которая собирается — 0.2.5


    Синхронизация Repo


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


    repo sync
    которая заберет все последние версии GIT проектов указанных в файле манифеста (обычно указываются ветки), если же у вас указан hash коммита или имя тега в атрибуте revision, то версия для данного git репозитория не измениться. Имя тега можно указать так: revision="refs/tags/v0.2.5"


    Создание конфигурации Yocto Project


    После того, как будет выполнена команда repo sync, можно приступать к созданию основной конфигурации Yocto Project:


    ./shell.sh

    после завершения работы скрипта, будет создан каталог build/conf:

    c двумя основными файлами:
    • local.conf - управляющие переменные сборки:
      название платформы, тип дистрибутива и пакетов сборки и т.д.
    • bblayers.conf - конфигурация подключенных слоев Yocto Project

    по умолчанию скрипт setup-environment ищет по пути sources/base/conf
    начальную конфигурацию, и если файлы local.conf и bblayers.conf
    существуют, то они копируются в build/conf
    (см. переменную TEMPLATES в setup-environment)

    т.е. файлы берутся из sources/bs-manifest/raspberry/rocko/conf
    см. создание символической ссылки на base


    Конфигурационный файл build/conf/local.conf

    Показать/Скрыть
    	
    	MACHINE ??= 'raspberrypi3'
    	DISTRO ?= 'poky'
    	PACKAGE_CLASSES ?= "package_deb"
    	EXTRA_IMAGE_FEATURES ?= "debug-tweaks"
    	USER_CLASSES ?= "buildstats image-mklibs image-prelink"
    	PATCHRESOLVE = "noop"
    	BB_DISKMON_DIRS = "\
    	    STOPTASKS,${TMPDIR},1G,100K \
    	    STOPTASKS,${DL_DIR},1G,100K \
    	    STOPTASKS,${SSTATE_DIR},1G,100K \
    	    STOPTASKS,/tmp,100M,100K \
    	    ABORT,${TMPDIR},100M,1K \
    	    ABORT,${DL_DIR},100M,1K \
    	    ABORT,${SSTATE_DIR},100M,1K \
    	    ABORT,/tmp,10M,1K"
    	PACKAGECONFIG_append_pn-qemu-native = " sdl"
    	PACKAGECONFIG_append_pn-nativesdk-qemu = " sdl"
    	CONF_VERSION = "1"
    	
    	DL_DIR ?= "${BSPDIR}/downloads/"
    	
    	# size memory GPU for Raspberry Pi
    	GPU_MEM = "128"
    	GPU_MEM_256 = "112"
    	GPU_MEM_512 = "160"
    	GPU_MEM_1024 = "320"
    	
    	# for libs: "mpeg2dec libmad ffmpeg x264"
    	LICENSE_FLAGS_WHITELIST += "commercial"
    	
    	
    	


    Конфигурационный файл build/conf/bblayers.conf

    Показать/Скрыть
    	
    	# POKY_BBLAYERS_CONF_VERSION is increased each time build/conf/bblayers.conf
    	# changes incompatibly
    	LCONF_VERSION = "6"
    	POKY_BBLAYERS_CONF_VERSION = "2"
    	
    	BBPATH = "${TOPDIR}"
    	BSPDIR := "${@os.path.abspath(os.path.dirname(d.getVar('FILE', True)) + '/../..')}"
    	BBFILES ?= ""
    	
    	BBLAYERS ?= " \
    	  ${BSPDIR}/sources/poky/meta \
    	  ${BSPDIR}/sources/poky/meta-poky \
    	  ${BSPDIR}/sources/poky/meta-yocto-bsp \
    	  ${BSPDIR}/sources/meta-openembedded/meta-oe \
    	  ${BSPDIR}/sources/meta-openembedded/meta-python \
    	  ${BSPDIR}/sources/meta-openembedded/meta-networking \
    	  ${BSPDIR}/sources/meta-openembedded/meta-multimedia \
    	  ${BSPDIR}/sources/meta-openembedded/meta-filesystems \
    	  ${BSPDIR}/sources/meta-raspberrypi \
    	  ${BSPDIR}/sources/berserk/meta-berserk \
    	  "
    	
    	
    	



    основные переменные файла local.conf - на которые нужно обратить внимание:

    • MACHINE - название платформы под которую осуществляется сборка
    • DISTRO - название категории дистрибутива
    • PACKAGE_CLASSES - формат пакетов для установки ПО
    • LICENSE_FLAGS_WHITELIST - использование дополнительных лицензий



    специфические настройки для семейства плат Raspberry Pi
    • GPU_MEM = "128" - количество видео памяти для видео адаптера GPU (выделяется из ОЗУ)
    • GPU_MEM_256 = "112" - то же самое только для плат с общим размером ОЗУ = 256Мб
    • GPU_MEM_512 = "160" - то же самое только для плат с общим размером ОЗУ = 512Мб
    • GPU_MEM_1024 = "320" - то же самое только для плат с общим размером ОЗУ = 1024Мб

    примечание: например если оставить только переменную GPU_MEM = "128", то для всех плат RPI, RPI2, RPI3 не зависимо от количества реальной оперативной памяти на плате будет всегда выделено для GPU - 128Мб (и общий размер ОЗУ уменьшиться на это значение),

    в случае указания всех переменных,
    директивы GPU_MEM_256, GPU_MEM_512, GPU_MEM_1024 являются более приоритетными

    Для сборки Мультимедиа центра, помимо штатных слоев Yocto см. файл bblayers.conf

    	${BSPDIR}/sources/poky/meta \
    	${BSPDIR}/sources/poky/meta-poky \
    	${BSPDIR}/sources/poky/meta-yocto-bsp \
    	
    я подключил четыре слоя с дополнительной функциональностью из OpenEmbedded.
    Мультимедиа Центр Kodi - является сложной программой, которая использует большое количество внешних библиотек и каждую библиотеку нужно собрать с помощью рецепта сборки, поэтому по возможности я буду использовать все рецепты из OpenEmbedded в категории Multimedia,


    итак, у меня подключен слой Multimedia и слои от которых он зависит
    	${BSPDIR}/sources/meta-openembedded/meta-oe \
    	${BSPDIR}/sources/meta-openembedded/meta-python \
    	${BSPDIR}/sources/meta-openembedded/meta-networking \
    	${BSPDIR}/sources/meta-openembedded/meta-multimedia \
    	
    затем подключен еще один слой OpenEmbedded, для работы с файловыми системами
    	${BSPDIR}/sources/meta-openembedded/meta-filesystems \
    	
    далее подключен основной BSP слой для платформы Raspberry Pi
    	${BSPDIR}/sources/meta-raspberrypi \
    	
    ну и в самом конце подключен дополнительный слой, отвечающий за сборку образа дистрибутива с функциональностью "Мультимедиа центра"
    	${BSPDIR}/sources/berserk/meta-berserk \
    	



    Слой для сборки мультимедиа центра


    На мой взгляд Yocto Project является промышленным комбайном для создания встраиваемых дистрибутивов. Но если вы когда нибудь работали с системой сборки Buildroot, то Yocto может вам показаться достаточно громоздким. Он использует огромное количество свободного места на жестком диске. Для нормальной работы Yocto требуется порядка 80 - 100 Гб свободного пространства и это обычно с учетом сборки только под одну платформу.

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

    Итак, вся функциональность, для сборки "Мультимедиа центра" находиться с отдельном слое:

    	https://github/berserktv/berserk
    	
    (Название взято из моей любимой книги "Молот и крест", писателя Гарри Гаррисона.)
    (Torvin также является персонажем данной книги.)

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

    Структура слоя


    
    	├── COPYING.MIT
    	├── meta-berserk
    	│   ├── conf
    	│   │   └── layer.conf
    	│   ├── recipes-berserk
    	│   │   ├── bs-net
    	│   │   ├── first-run
    	│   │   ├── images
    	│   │   └── tv
    	│   ├── recipes-core
    	│   │   ├── init-ifupdown
    	│   │   └── psplash
    	│   ├── recipes-kernel
    	│   │   └── linux
    	│   ├── recipes-mediacentre
    	│   │   ├── kodi
    	│   │   └── kodi-plugins
    	│   └── recipes-multimedia
    	│       └── ffmpeg
    	├── README.md
    	└── changelog.txt
    	

    Состав слоя:

    • conf - конфигурация слоя
    • recipes-berserk - рецепт сборки дистрибутива, рецепты настройки тв, сети и первого запуска
    • recipes-core - базовые рецепты, в частности модификация рецепта стартовой заставки
    • recipes-kernel - рецепты сборки Linux ядра
    • recipes-mediacentre - рецепты сборки Kodi и его плагинов
    • recipes-multimedia - мультимедиа рецепты, сборка ffmpeg


    конфигурация слоя


    включает файл layer.conf

    
    	  # We have a conf and classes directory, add to BBPATH
    	  BBPATH .= ":${LAYERDIR}"
    	  
    	  # We have a packages directory, add to BBFILES
    	  BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
    	              ${LAYERDIR}/recipes-*/*/*.bbappend"
    	  
    	  
    	  # BerSerk
    	  BBFILE_COLLECTIONS += "bs"
    	  BBFILE_PATTERN_bs := "^${LAYERDIR}/"
    	  BBFILE_PRIORITY_bs = "5"
    	  
    	  
    	  DISTRO_FEATURES_append += " wifi x11"
    	  
    	  PREFERRED_VERSION_ffmpeg = "3.1.11"
    	  SYSVINIT_ENABLED_GETTYS  = "1"
    	  
    	  PREFERRED_VERSION_linux-raspberrypi ?= "4.9%"
    	  

    Файл содержит указание версии библиотеки ffmpeg, номер версии linux ядра, а также количество виртуальных консолей (tty), и включает особенности дистрибутива - wifi x11
    	DISTRO_FEATURES_append += " wifi x11"
    	
    	PREFERRED_VERSION_ffmpeg = "3.1.11"
    	SYSVINIT_ENABLED_GETTYS  = "1"
    		  
    	PREFERRED_VERSION_linux-raspberrypi ?= "4.9%"
    	


    состав recipes-berserk


    
    	├── bs-net
    	│   └── bs-net_0.1.3.bb
    	├── first-run
    	│   ├── files
    	│   │   └── first-run.sh
    	│   └── first-run.bb
    	├── images
    	│   └── berserk-image.bb
    	└── tv
    	    ├── files
    	    │   └── berserk.m3u8
    	    ├── tv-config.bb
    	    └── tv-dir.inc
    	
    где:
    • bs-net_0.1.3.bb
      
      	# Simple network "shell" extension for wlan/ethernet 
      	# Project "Berserk", autor Alexander Demachev, site https://berserk.tv
      	# license -  The MIT License (MIT)
      	
      	DESCRIPTION = "Simple network shell extension for wlan/ethernet"
      	SECTION = "nets"
      	PR = "r1"
      	LICENSE = "MIT"
      	MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
      	LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
      	
      	SRC_URI = "git://github.com/berserktv/bs-net.git;branch=master"
      	SRCREV = "2d95807ffd285f66f60eae021baaed645d68fb43"
      	
      	require recipes-mediacentre/kodi/kodi-dir.inc
      	
      	NET_DIR = "/etc/network"
      	UDEV_DIR = "/etc/udev/rules.d"
      	ETH_CONFIGS = "${KODI_USERDATA}/eths"
      	WLAN_CONFIGS = "${KODI_USERDATA}/wlans"
      	
      	S = "${WORKDIR}/git"
      	
      	PACKAGES = "${PN}"
      	FILES_${PN} = "${NET_DIR} ${UDEV_DIR} ${KODI_HOME_DIR}"
      	
      	RDEPENDS_${PN} += "ntp wpa-supplicant iw gawk"
      	
      	do_install_append() {
      	    install -d ${D}${UDEV_DIR}
      	    install -d ${D}${sysconfdir}/network
      	    install -d ${D}${ETH_CONFIGS}
      	    install -d ${D}${WLAN_CONFIGS}
      	
      	    install -m 0755 ${S}${NET_DIR}/dh-func.sh ${D}${sysconfdir}/network
      	    install -m 0755 ${S}${NET_DIR}/eth-manual ${D}${sysconfdir}/network 
      	    install -m 0755 ${S}${NET_DIR}/tools-wifi.sh ${D}${sysconfdir}/network
      	    install -m 0755 ${S}${NET_DIR}/wlan ${D}${sysconfdir}/network
      	    install -m 0755 ${S}${NET_DIR}/wlan-runner ${D}${sysconfdir}/network
      	    install -m 0644 ${S}${NET_DIR}/eth0 ${D}${ETH_CONFIGS}
      	
      	    install -m 0644 ${S}${UDEV_DIR}/80-wifi-start.rules ${D}${UDEV_DIR} 
      	    install -m 0644 ${S}${UDEV_DIR}/85-automount.rules  ${D}${UDEV_DIR}
      	}
      	
      - рецепт сборки shell расширения для WLAN/Ethernet интерфейсов
    • first-run.bb
      
      	DESCRIPTION = "First run script"
      	SECTION = "configs"
      	PR = "r1"
      	LICENSE = "MIT"
      	MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
      	LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
      	
      	# секция установки скрипта первого запуска
      	SRC_URI = "file://first-run.sh"
      	
      	inherit update-rc.d
      	
      	S = "${WORKDIR}"
      	
      	
      	INITSCRIPT_NAME = "first-run.sh"
      	# вызов скрипта определяющего первое включение компьютера на уровень исполнения S
      	# вызывается после S03mountall.sh S04udev S05modutils.sh
      	#                  S06alignment.sh S06checkroot.sh S07bootlogd
      	INITSCRIPT_PARAMS = "start 07 S ."
      	
      	
      	
      	PACKAGES = "${PN}"
      	FILES_${PN} = "first.bs.run /etc/init.d"
      	
      	do_install_append() {
      	    install -d ${D}${sysconfdir}/init.d
      	    install -m 0755  ${WORKDIR}/first-run.sh ${D}${sysconfdir}/init.d
      	    # FIRST_RUN="/first.bs.run"
      	    touch ${D}/first.bs.run
      	}
      	
      - рецепт первого запуска, дополнительное разбиение дисков
    • first-run.sh
      
      	#!/bin/sh
      	
      	# скрипт предназначен для создания нового раздела диска microSDHC
      	# диск создается при первом включении в неразмеченной области,
      	# autor Alexander Demachev, project: berserk (site: https://berserk.tv)
      	#
      	# исходная разметка диска /dev/sdX при создании образа:
      	# где sdX - обобщенное название карты памяти microSDHC, точное название см. /etc/fstab
      	# первый раздел /dev/sdX1 => fat16 будет содержать ядро, загрузчик и драйверы
      	#                            для поддержки Raspberry Pi (dtb образы)
      	# второй раздел /dev/sdX2 => ext3  будет содержать корневую файловую систему, rootfs
      	#
      	# оставшиеся место не занято,
      	# и здесь будет создан третий раздел /dev/sdX3 для хранения мультимедиа информации
      	# после создания, раздел будет монтироваться в каталог /media/data
      	#
      	# последовательность действий:
      	# в каталоге /etc/rcS.d необходимо создать символическую ссылку S07first-run.sh
      	# ссылка на файл ../init.d/first-run.sh
      	#
      	FIRST_RUN="/first.bs.run"
      	DISK_DEV=/dev/mmcblk0
      	DISK_ROOTFS=/dev/mmcblk0p2
      	DISK_MEDIA=/dev/mmcblk0p3
      	MOUNT_MEDIA=/media/data
      	
      	
      	#######################################################################
      	# section func
      	
      	check_need_create() {
      	    local disk="$1"
      	    # в случае отсутствия раздела, его необходимо создать
      	    if [ -b "$disk" ]; then return 1
      	    else return 0; fi
      	}
      	
      	create_partition_fat32() {
      	    local dev_disk="$1"
      	    local dev2="$2"
      	    local dev3="$3"
      	    local name="DATA"
      	    local END2_MBYTE=`parted -s -m $dev_disk unit MB print \
      	          | grep "^2:" | cut -d":" -f3 \
      	          | tr "MB" " " | sed "s/\.[0-9]*//" `
      	    local START_MBYTE="$END2_MBYTE"
      	    #local START_MBYTE=`expr $END2_MBYTE + 1`
      	    local com_args="-s -a optimal $dev_disk mkpart primary \
      	                    fat32 $START_MBYTE 100% print quit"
      	
      	    parted $com_args
      	    local code=$?
      	    sync
      	    if [ $? -eq 0 ]; then echo "SUCCESS => parted $com_args"
      	    else echo "FAIL => parted $com_args"; return 1; fi
      	
      	    com_args="-F 32 -n $name $dev3"
      	    mkfs.vfat $com_args
      	    code=$?
      	    sync
      	    if [ $code -eq 0 ]; then echo "SUCCESS => mkfs.vfat $com_args"
      	    else echo "FAIL => mkfs.vfat $com_args"; fi
      	    return $code
      	}
      	
      	# отключил изменение размера rootfs (ext3), 
      	# так как операция resize2fs /dev/раздел занимает 6-7минут (размер раздела 3GB)
      	# как нибудь посмотрю время изменения раздела ext4 через ioctl EXT4_IOC_RESIZE_FS
      	#if [ -d "/mnt/.psplash" ]; then 
      	#echo "MSG Resizing the disk space on the first running ..." > $fifo; 
      	#fi
      	#resize_root_partition $DISK_DEV
      	resize_root_partition() {
      	    local dev_disk="$1"
      	    local full_size_byte=`fdisk -l $dev_disk | grep "${dev_disk}:" | cut -d" " -f5`
      	    if [ -z "$full_size_byte" ]; then return 1; fi
      	
      	    local END2_BYTE=`parted -s -m $dev_disk unit B print | grep "^2:" \
      	                     | cut -d":" -f3 | tr -d "B" | sed "s/\.[0-9]*//"`
      	    local size_part=$(($full_size_byte-$END2_BYTE))
      	    if [ $? -ne 0 ] || [ -z "$size_part" ]; then return 2; fi
      	
      	    local ten_persent=$(($size_part/10))
      	    if [ $? -ne 0 ] || [ -z "$ten_persent" ]; then return 3; fi
      	
      	    local NEW_END2_BYTE=$(($END2_BYTE+$ten_persent))
      	    local com_args="-s -a optimal $dev_disk unit B resizepart 2 $NEW_END2_BYTE"
      	    parted $com_args
      	    local code=$?
      	    sync
      	    if [ $code -eq 0 ]; then echo "SUCCESS => parted $com_args"; return 0;
      	    else echo "FAIL => parted $com_args"; return 4; fi
      	}
      	
      	mount_create_partition_fat32() {
      	    local dev="$1"
      	    local media="$2"
      	    local code=1
      	    if mount | grep -q "$media"; then 
      	        echo "$dev already mount on $media, exit"; return 0; 
      	    fi
      	    if [ ! -d "$media" ]; then mkdir $media;  fi
      	
      	    sync
      	    com_args="-n -t vfat -o rw $dev $media"
      	    mount $com_args
      	    if mount | grep -q "$media"; then code=0;
      	    else mount $com_args; code=$?; fi
      	
      	    if [ $code -eq 0 ]; then echo "SUCCESS => mount $com_args"
      	    else echo "FAIL => mount $com_args"; fi
      	    return $code
      	}
      	
      	add_disk_in_fstab() {
      	    local disk="$1"
      	    local point="$2"
      	    # example
      	    #/dev/mmcblk0p     /media/card     auto       defaults,sync,noauto  0  0
      	    echo "$disk        $point          auto       defaults 1  1" >> /etc/fstab
      	    sync
      	}
      	
      	#######################################################################
      	# section start
      	# в корне раздела находиться файл по которому определяется первое включение устройcтва
      	fifo="/mnt/.psplash/psplash_fifo"
      	if [ ! -f "$FIRST_RUN" ]; then
      	    if [ -d "/mnt/.psplash" ]; then
      	        echo "MSG  ver 0.2.5 TORVIN     \"Along Came a Hammersmith\"" > $fifo
      	    fi
      	    exit 0
      	fi
      	
      	
      	# файл используется для вывода окна настройки сети во время первого запуска Kodi
      	touch "/tmp/$FIRST_RUN"
      	
      	if check_need_create $DISK_MEDIA; then
      	    if create_partition_fat32 $DISK_DEV $DISK_ROOTFS $DISK_MEDIA; then
      	      if [ -d "/mnt/.psplash" ]; then 
      	          echo "MSG Creating a new partition on the first running ..." > $fifo; 
      	      fi
      	      if mount_create_partition_fat32 $DISK_MEDIA $MOUNT_MEDIA; then 
      	          add_disk_in_fstab $DISK_MEDIA $MOUNT_MEDIA;
      	      else echo "ERROR_2, not mount_create_partition_fat32 $DISK_MEDIA $MOUNT_MEDIA"; fi
      	    else
      	      echo "ERROR_1, not create_partition_fat32 $DISK_DEV $DISK_ROOTFS $DISK_MEDIA"
      	    fi
      	fi
      	
      	rm -f "$FIRST_RUN"
      	exit 0
      	
      - shell скрипт первого запуска (запускается на уровне исполнения S)
    • berserk-image.bb
      
      	# Project: "Berserk" - build Kodi for the Raspberry Pi platform
      	#           autor: Alexander Demachev, site: https://berserk.tv
      	# license - The MIT License (MIT)
      	
      	DESCRIPTION = "Berserk - the image for the Raspberry PI"
      	LICENSE = "MIT"
      	MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
      	LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
      	
      	IMAGE_FEATURES += "ssh-server-dropbear splash"
      	
      	# немного увеличиваю размер rootfs в кило байтах (250000kB=~250Mb)
      	IMAGE_ROOTFS_EXTRA_SPACE_append += "+ 250000"
      	
      	
      	# BS - BerSerk, version 0.2.5 - "Torvin"
      	# Base this image on core-image-minimal
      	include recipes-core/images/core-image-minimal.bb
      	
      	# Set default password for 'root' user
      	inherit extrausers
      	ROOTUSERNAME = "root"
      	ROOTPASSWORD = "berserk"
      	EXTRA_USERS_PARAMS = "usermod -P ${ROOTPASSWORD} ${ROOTUSERNAME};"
      	
      	
      	# стартовая заставка, которая выводиться во время загрузки
      	SPLASH = "psplash-berserk"
      	
      	BS_DEBUG_TOOLS = "ldd strace ltrace"
      	
      	BS_GLIBC = "glibc-thread-db \
      	            glibc-gconv-utf-16 \
      	            glibc-gconv-utf-32 \
      	            glibc-binary-localedata-en-us \
      	            glibc-binary-localedata-ru-ru \
      	            glibc-charmap-utf-8 \
      	            "
      	
      	BS_BASE = "kernel-modules \
      	           lsb \
      	           pciutils \
      	           parted \
      	           tzdata \
      	           dosfstools \
      	           ntp \
      	           ntpdate \
      	           e2fsprogs-resize2fs \
      	           ntfs-3g \
      	           ntfsprogs \
      	           "
      	
      	BS_WLAN = "kernel-module-rt2800usb \
      	           kernel-module-rt2800lib \
      	           kernel-module-rt2x00lib \
      	           kernel-module-rt2x00usb \
      	           kernel-module-cfg80211 \
      	           kernel-module-nls-utf8 \
      	           kernel-module-ath9k-common \
      	           kernel-module-ath9k-hw \
      	           kernel-module-ath9k-htc \
      	           kernel-module-ctr \
      	           kernel-module-ccm \
      	           kernel-module-arc4 \
      	           "
      	
      	BS_WIFI_SUPPORT = " \
      	        iw \
      	        dhcp-client \
      	        wireless-tools \
      	        wpa-supplicant \
      	        linux-firmware \
      	        "
      	
      	BS_SOFT = "mc \
      	           kodi \
      	           kodi-runner \
      	           kodi-settings \
      	           kodi-language-ru \
      	           kodi-pvr-iptvsimple \
      	           bs-net \
      	           tv-config \
      	           first-run \
      	           script-berserk-network \
      	           screensaver-kodi-universe \
      	           plugin-video-youtube \
      	           script-module-requests \
      	           "
      	
      	
      	
      	# Include modules in rootfs
      	IMAGE_INSTALL += " \
      	    ${BS_BASE} \
      	    ${BS_WLAN} \
      	    ${BS_WIFI_SUPPORT} \
      	    ${BS_GLIBC} \
      	    ${BS_SOFT} \
      	    ${BS_DEBUG_TOOLS} \
      	    "
      	
      - рецепт сборки образа дистрибутива
    • tv-config.bb
      
      	DESCRIPTION = "TV config for Berserk Image"
      	SECTION = "configs"
      	PR = "r1"
      	LICENSE = "MIT"
      	MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
      	LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
      	
      	require tv-dir.inc
      	
      	S = "${WORKDIR}"
      	
      	SRC_URI += " \
      	    file://${TV_CONFIG} \
      	    "
      	
      	PACKAGES = "${PN}"
      	
      	FILES_${PN} +=  "${TV_CONFIG_DIR} \
      	                "
      	
      	do_install() {
      	    install -d "${D}${TV_CONFIG_DIR}"
      	    install -m 0644 "${S}/${TV_CONFIG}" "${D}${TV_CONFIG_DIR}/${TV_CONFIG}"
      	}
      	
      - рецепт настройки конфигурации ТВ каналов по протоколу IPTV (формат m3u8)
    • berserk.m3u8
      
      	#EXTM3U
      	#EXTINF:0 group-title="Новости",Euronews Russian
      	http://evronovosti.mediacdn.ru/sr1/evronovosti/playlist.m3u8
      	#EXTINF:0 group-title="Новости",ABC News English
      	http://abclive.abcnews.com/i/abc_live4@136330/master.m3u8?b=500,300,700,900,1200
      	#EXTINF:0 group-title="Новости",France 24 English
      	http://static.france24.com/live/F24_EN_LO_HLS/live_ios.m3u8
      	#EXTINF:0 group-title="Новости",Tagesschau24
      	http://tagesschau-lh.akamaihd.net/i/tagesschau_1@119231/master.m3u8
      	#EXTINF:0 group-title="Новости",France 24 French
      	http://static.france24.com/live/F24_FR_LO_HLS/live_ios.m3u8
      	#EXTINF:0 group-title="Новости",Bloomberg
      	http://liveproduseast.akamaized.net/btv/desktop/us_live.m3u8
      	#EXTINF:0 group-title="Новости",CBN NEWS
      	http://bcliveuniv-lh.akamaihd.net:80/i/news_1@194050/index_900_av-p.m3u8
      	#EXTINF:0 group-title="Док",Russia Today Док
      	http://rtmp.api.rt.com/hls/rtdru.m3u8
      	#EXTINF:0 group-title="Новости",Russia Today HD
      	http://secure-streams.akamaized.net/rt/index2500.m3u8
      	#EXTINF:0 group-title="Новости",CBN
      	http://bcliveuniv-lh.akamaihd.net/i/iptv1_1@194050/index_2000_av-b.m3u8
      	
      - конфигурация общедоступных телевизионных каналов


    состав recipes-core


    
    	├── init-ifupdown
    	│   ├── files
    	│   │   └── interfaces
    	│   └── init-ifupdown_1.0.bbappend
    	└── psplash
    	    ├── files
    	    │   └── psplash-berserk-img.h
    	    └── psplash_git.bbappend
    	
    где:
    • interfaces
      
      	# /etc/network/interfaces -- configuration file for ifup(8), ifdown(8)
      	 
      	# The loopback interface
      	auto lo
      	iface lo inet loopback
      	
      	
      	auto eth0
      	iface eth0 inet manual
      	    up /etc/network/eth-manual $IFACE up
      	    down /etc/network/eth-manual $IFACE down
      	
      - файл с текущей настройкой сети
    • init-ifupdown_1.0.bbappend
      
      	FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
      	
      	INITSCRIPT_PARAMS = "start 98 2 3 4 5 . stop 10 0 6 1 ."
      	
      - расширение для рецепта конфигурации сети
    • psplash-berserk-img.h - изображение стартовой заставки
      заголовочный файл получен с помощью утилиты gdk-pixbuf-csource
    • psplash_git.bbappend
      
      	FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
      	SRC_URI += "file://psplash-berserk-img.h"
      	
      	SPLASH_IMAGES = "file://psplash-berserk-img.h;outsuffix=berserk"
      	
      - расширение рецепта сборки стартовой заставки


    Конфигурация сети на целевом устройстве находиться в файле:

    /etc/network/interfaces
    Добавив расширение рецепта init-ifupdown, я заменяю штатный конфигурационный файл на собственный, и меняю порядок (приоритет) запуска скрипта для уровней исполнения
    INITSCRIPT_PARAMS = "start 98 2 3 4 5 . stop 10 0 6 1 ."


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

    Для этого необходимо:

    1. FILESEXTRAPATHS_prepend - добавить каталог для ресурсов
    2. SRC_URI - добавить заголовочный файл с произвольной картинкой
    3. SPLASH_IMAGES изменить управляющую переменную пакета
      • где указать какой заголовочный файл в пакет с каким суффиксом будет интегрирован:
      • т.е. базовое название пакета psplash-outsuffix (у меня это название "psplash-berserk")


    и далее в рецепте образа "berserk-image.bb" необходимо добавить
    в качестве особенностей образа - стартовую заставку splash

    IMAGE_FEATURES += "splash"

    и переменную с указанием конкретного названия пакета стартовой заставки

    SPLASH = "psplash-berserk"



    состав recipes-kernel


    	└── linux
    	    ├── files
    	    │   ├── db.txt.patch
    	    │   └── rbpi.cfg
    	    └── linux-raspberrypi_4.9.bbappend
    	
    где:
    • db.txt.patch - патч с базой Regulatory Domain (используется для WiFi)
    • rbpi.cfg
      
      	# use statically compiled regulatory rules database
      	CONFIG_CFG80211_INTERNAL_REGDB=y
      	# поддержка Wifi сетевого Asus USB-N53 chipset Ralink RT3572
      	CONFIG_RT2800USB=m
      	# поддержка wifi адаптера на чипсете Atheros D-Link DWA-126 802.11n (AR9271), 
      	# NetGear WNDA3200, NetGear WNA1100, TP-Link TL-WN722N (AR9271), 
      	# TL-WN322G v3, TL-WN422G и т.д. см. cateee.net
      	CONFIG_ATH9K_HW=m
      	CONFIG_ATH9K_HTC=m
      	# настройка Wifi драйверов для работы wpa_supplicant
      	CONFIG_WIRELESS=y
      	CONFIG_WEXT_CORE=y
      	CONFIG_WEXT_PROC=y
      	CONFIG_CRYPTO_AES=y
      	# поддержка семейства протоколов IPSec, без этих модулей Wifi авторизация 
      	# при подключении wpa_supplicant не работает
      	CONFIG_CRYPTO_CCM=m
      	CONFIG_CRYPTO_CTR=m
      	CONFIG_CRYPTO_ARC4=m
      	#########################
      	# оценка производительности
      	CONFIG_HAVE_PERF_EVENTS=y
      	CONFIG_PERF_EVENTS=y
      	CONFIG_HAVE_LATENCYTOP_SUPPORT=y
      	CONFIG_LATENCYTOP=y
      	# This option adds support for ASIX AX88xxx 
      	# based USB 2.0 10/100 Ethernet adapters.
      	CONFIG_USB_NET_AX8817X=m
      	
      - фрагмент конфигурации Linux ядра
    • linux-raspberrypi_4.9.bbappend
      
      	# дополнительный параметры конфигурации описываются в rpbi.cfg
      	FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
      	
      	SRC_URI += "file://db.txt.patch;patch=1 \
      	            file://rbpi.cfg \
      	            "
      	
      	# в BSP слое meta-raspberrypi не работают фрагменты конфигураций
      	# https://github.com/agherzan/meta-raspberrypi/issues/14
      	# поэтому делаю напрямую
      	# в методе do_kernel_configme конфигурация ядра 
      	# копируется из базы архитектур arch/ в рабочий каталог
      	do_kernel_configme_append() {
      	    cat ${WORKDIR}/rbpi.cfg >> ${WORKDIR}/defconfig
      	}
      	
      	# CMDLINE for raspberrypi
      	# default CMDLINE = "dwc_otg.lpm_enable=0 console=serial0,115200
      	# root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
      	CMDLINE = "quiet dwc_otg.lpm_enable=0 console=serial0,115200 \
      	           root=/dev/mmcblk0p2 rootfstype=ext4 rootwait"
      	
      - расширение рецепта сборки ядра 4.9 для Raspberry Pi


    Wi-Fi устройства работают на определенных частотах и для них существует такое понятие как управляющий домен (regulatory domain) – именно в этом параметре указана страна, в которой, как предполагается, работает данное устройство.

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

    В самом простом случае эту базу можно включить непосредственно в ядро статически, указав параметр:
    CONFIG_CFG80211_INTERNAL_REGDB=y
    что собственно я и сделал, подключив патч c этой базой db.txt.patch

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

    В дополнении рецепта bbappend, также можно изменить параметры, которые передаются ядру во время запуска: т.е. переопределить переменную CMDLINE см. файл linux-raspberrypi_4.9.bbappend



    состав recipes-mediacentre


    
    	├── kodi
    	│   ├── kodi
    	│   ├── kodi_17.bbappend
    	│   ├── kodi-dir.inc
    	│   ├── kodi-runner.bb
    	│   ├── kodi-settings.bb
    	│   └── kodi-version.inc
    	└── kodi-plugins
    	    ├── files
    	    ├── kodi-language-ru_3.0.10.bb
    	    ├── kodi-pvr-iptvsimple.bb
    	    ├── plugin-video-youtube_5.5.1.bb
    	    ├── screensaver-kodi-universe_0.1.2.bb
    	    ├── script-berserk-network_0.2.5.bb
    	    └── script-module-requests_2.12.4.bb
    	
    где:
    1. kodi/
      • kodi - каталог содержит подкаталоги icon,run,settings
        и патчи для исходного кода и конфигурации запуска мультимедиа центра
      • kodi_17.bbappend
        
        	  require kodi-version.inc
        	  
        	  # убираю не работающий патч (был для версии 17.3)
        	  SRC_URI_remove = "file://0013-FTPParse.cpp-use-std-string.patch"
        	  
        	  # отключаю патч, так как systemd не использую
        	  SRC_URI_remove = "file://0004-handle-SIGTERM.patch"
        	  
        	  # добавляю патч обратного портирования для RPI взятого из libreelec
        	  SRC_URI_append += "file://kodi-krypton-rpb-backports.patch"
        	  
        	  # исправление error adding symbols: DSO missing from command line
        	  SRC_URI_append += "file://vchostif.patch"
        	  
        	  
        	  MENU_ICON = "addons/skin.estuary/media/icons/settings"
        	  # добавление нового пункта в меню настроек (значок шестеренки)
        	  SRC_URI_append += "file://bs-menu.patch file://icon/bs-network.png"
        	  do_configure_prepend() {
        	      install -m 0644 ${WORKDIR}/icon/bs-network.png ${S}/${MENU_ICON}
        	  }
        	  
        	  # дополнительные зависимости для kodi plugins
        	  RRECOMMENDS_${PN}_append = "\
        	                    python-xml python-misc python-db \
        	                    python-crypt python-threading python-math python-email \
        	                    python-io python-netserver python-urllib3 python-datetime"
        	  
        	  
        	  # специфическии опции для плат Raspberry Pi
        	  # реализация OPENGL обязательно должна быть --enable-gles
        	  # для kodi зависимости сборки указаны в docs/README.linux => libxmu libxinerama 
        	  #                                                            libxtst xdpyinfo
        	  # для сборки этих библиотек в DISTRO_FEATURES необходима зависимость "x11"
        	  # но сам kodi для RPI1 и RPI2,3 собирается с опцией --disable-x11
        	  
        	  BS_RPI = " --disable-gl --enable-openmax --enable-player=omxplayer \
        	             --with-platform=raspberry-pi --disable-x11"
        	  
        	  BS_RPI3 = " --disable-gl --enable-openmax --enable-player=omxplayer \
        	              --with-platform=raspberry-pi2 --disable-x11"
        	  
        	  EXTRA_OECONF_append = "${@bb.utils.contains('MACHINE', 'raspberrypi', \
        	                                                         '${BS_RPI}', '', d)}"
        	                         
        	  EXTRA_OECONF_append = "${@bb.utils.contains('MACHINE', 'raspberrypi2', \
        	                                                         '${BS_RPI3}', '', d)}"
        	  
        	  EXTRA_OECONF_append = "${@bb.utils.contains('MACHINE', 'raspberrypi3', \
        	                                                         '${BS_RPI3}', '', d)}"
        	  
        	  # опция для появления всплывающего сообщения в Kodi о подключении 
        	  # внешнего носителя, например USB или microSDHC диска (через картридер)
        	  EXTRA_OECONF_append = " --enable-optical-drive"
        	  
        - дополнение для рецепта сборки мультимедиа центра Kodi
      • kodi-dir.inc
        
        	  KODI_HOME_DIR = "/home/root/.kodi"
        	  KODI_USERDATA = "${KODI_HOME_DIR}/userdata"
        	  KODI_ADDON_DIR = "${KODI_HOME_DIR}/addons"
        	  
        - общие пути расположения Kodi и его плагинов
      • kodi-runner.bb
        
        	  DESCRIPTION = "runner for KODI Media Center"
        	  SECTION = "configs"
        	  PR = "r1"
        	  LICENSE = "MIT"
        	  MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
        	  
        	  FILESEXTRAPATHS_prepend := "${THISDIR}/kodi:"
        	  
        	  # секция установки скрипта запуска
        	  SRC_URI = "file://run/kodi.init file://run/restarter.sh"
        	  
        	  inherit update-rc.d
        	  
        	  S = "${WORKDIR}/run"
        	  
        	  
        	  INITSCRIPT_NAME = "kodi"
        	  INITSCRIPT_PARAMS = "start 01 2 3 4 5 . stop 90 0 1 6 ."
        	  
        	  
        	  PACKAGES = "${PN}"
        	  FILES_${PN} = "/etc/init.d"
        	  
        	  do_install_append() {
        	      # скрипт запуска
        	      install -d ${D}/etc/init.d
        	      install -m 0755 ${S}/kodi.init ${D}/etc/init.d/kodi
        	      install -m 0755 ${S}/restarter.sh ${D}/etc/init.d/restarter.sh
        	  }
        	  
        - рецепт запуска Kodi на определенном уровне исполнения
      • kodi-settings.bb
        
        	  DESCRIPTION = "settings for KODI Media Center"
        	  SECTION = "configs"
        	  PR = "r1"
        	  LICENSE = "MIT"
        	  MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
        	  
        	  
        	  FILESEXTRAPATHS_prepend := "${THISDIR}/kodi:"
        	                      
        	  S = "${WORKDIR}"
        	  
        	  require kodi-dir.inc
        	  require recipes-berserk/tv/tv-dir.inc
        	  
        	  PVR_IPTVSIMPLE_SETTINGS = "${KODI_USERDATA}/addon_data/pvr.iptvsimple"
        	  VIDEO_YOUTUBE_SETTINGS = "${KODI_USERDATA}/addon_data/plugin.video.youtube"
        	  
        	  
        	  SRC_URI += " \
        	      file://settings/guisettings.xml \
        	      file://settings/settings-pvr-iptvsimple.xml \
        	      file://settings/advancedsettings.xml \
        	      file://settings/settings-video-youtube.xml \
        	      "
        	  
        	  
        	  
        	  PACKAGES = "${PN}"
        	  
        	  FILES_${PN} +=  "${KODI_USERDATA} \
        	                  "
        	  
        	  FIND_M3U_PATH = "m3uPath. value=."
        	  REPLACE_M3U_PATH = "${TV_CONFIG_DIR}/${TV_CONFIG}"
        	                  
        	  do_install() {
        	      # Kodi guisettings
        	      install -d "${D}${KODI_USERDATA}"
        	      install -m 0644 "${S}/settings/guisettings.xml" "${D}${KODI_USERDATA}"
        	      install -m 0644 "${S}/settings/advancedsettings.xml" "${D}${KODI_USERDATA}"
        	      
        	      # addon pvr.iptvsimple and plugin.video.youtube
        	      install -d "${D}${PVR_IPTVSIMPLE_SETTINGS}"
        	      install -d "${D}${VIDEO_YOUTUBE_SETTINGS}"
        	      
        	      # change path show tv-config.bb
        	      sed -i "s|${FIND_M3U_PATH}|&${REPLACE_M3U_PATH}|" \
        	             "${S}/settings/settings-pvr-iptvsimple.xml" 
        	             
        	      install -m 0644 "${S}/settings/settings-pvr-iptvsimple.xml" \
        	                      "${D}${PVR_IPTVSIMPLE_SETTINGS}/settings.xml"
        	                      
        	      install -m 0644 "${S}/settings/settings-video-youtube.xml" \
        	                      "${D}${VIDEO_YOUTUBE_SETTINGS}/settings.xml"
        	  }
        	  
        - рецепт размещения конфигурационных файлов Kodi
      • kodi-version.inc
        
        	  FILESEXTRAPATHS_prepend := "${THISDIR}/kodi:"
        	  
        	  # ветка Krypton
        	  SRCREV = "a9a7a20071bfd759e72e7053cee92e6f5cfb5e48"
        	  PV = "17.6+gitr${SRCPV}"
        	  
        - общий файл с информацией о собираемой версии Kodi
    2. kodi-plugins/
      • files - каталог с tar.gz архивами с исходным кодом плагинов
      • kodi-language-ru_3.0.10.bb
        
        	  DESCRIPTION = "resource.language.ru_ru for KODI Media Center"
        	  # как альтернативный вариант можно взять русскую локализацию
        	  # из официального репозитория "https://github.com/xbmc/translations.git"
        	  # но проект весит 1.2 Гб вместе с базой git, что не очень быстро загружается
        	  # поэтому локализацию пока добавил в качестве архива
        	  
        	  SECTION = "configs"
        	  PR = "r0"
        	  
        	  LICENSE = "GPL-2.0"
        	  MD5_SUM = "md5=801f80980d171dd6425610833a22dbe6"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;{MD5_SUM}"
        	  
        	  require ../kodi/kodi-dir.inc
        	  LANG_PACKAGE = "resource.language.ru_ru"
        	  
        	  SRC_URI = "file://${LANG_PACKAGE}.tar.gz"
        	  
        	  S = "${WORKDIR}"
        	  
        	  PACKAGES = "${PN}"
        	  
        	  FILES_${PN} +=  "${KODI_ADDON_DIR}"
        	  
        	  
        	  do_install() {
        	      # Kodi addons
        	      install -d "${D}${KODI_ADDON_DIR}/${LANG_PACKAGE}"
        	      install -d "${D}${KODI_ADDON_DIR}/${LANG_PACKAGE}/resources"
        	  
        	      install -m 0644 ${S}/${LANG_PACKAGE}/icon.png \
        	                      ${D}${KODI_ADDON_DIR}/${LANG_PACKAGE}
        	                      
        	      install -m 0644 ${S}/${LANG_PACKAGE}/addon.xml \
        	                      ${D}${KODI_ADDON_DIR}/${LANG_PACKAGE}
        	      
        	      install -m 0755 ${S}/${LANG_PACKAGE}/resources/* \
        	                      ${D}${KODI_ADDON_DIR}/${LANG_PACKAGE}/resources
        	      chown root:root -R ${D}
        	  }
        	  
        - рецепт добавления русской локализации (перевод меню Kodi)
      • kodi-pvr-iptvsimple.bb
        
        	  SUMMARY = "pvr.iptvsimple addons for KODI Media Center"
        	  
        	  ADDONS_NAME = "pvr.iptvsimple"
        	  LICENSE = "GPL-2.0"
        	  MD5_SUM = "md5=801f80980d171dd6425610833a22dbe6"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;${MD5_SUM}"
        	  
        	  require ../kodi/kodi-dir.inc
        	  require ../kodi/kodi-version.inc
        	  
        	  DB_DIR = "${KODI_USERDATA}/Database"
        	  SRC_URI = "git://github.com/xbmc/xbmc.git;branch=Krypton \
        	             file://db/Addons27.db \
        	            "
        	            
        	  FULL_OPTIMIZATION_armv7a = "-fexpensive-optimizations \
        	                              -fomit-frame-pointer -O4 -ffast-math"
        	  BUILD_OPTIMIZATION = "${FULL_OPTIMIZATION}"                  
        	  
        	  inherit cmake gettext
        	  
        	  S = "${WORKDIR}/git"
        	  
        	  
        	  DEPENDS = "gettext bcm2835-bootfiles kodi unzip-native zip-native"
        	  RDEPENDS_${PN} = "userland"
        	  
        	  PACKAGES = "${PN}-dbg ${PN}"
        	  PROVIDES = "${PACKAGES}"
        	  
        	  FILES_${PN} = "/lib /share ${KODI_ADDON_DIR} ${DB_DIR}"
        	  FILES_${PN}-dbg = "/lib/kodi/addons/${ADDONS_NAME}/.debug"
        	  
        	  INSANE_SKIP_${PN} = "dev-so"
        	  
        	  PARALLEL_MAKE = ""
        	  
        	  # явно указываю firmware для Raspberry PI см. recipes-bsp/common/firmware.inc
        	  # bitbake -s | grep "bcm2835-bootfiles" | cut -d":" -f2
        	  VERSION_BCM2835 = "20180313-r3"
        	  FIRM_DIR = "firmware-af994023ab491420598bfd5648b9dcab956f7e11"
        	  GIT_DIR_BCM2835 = "bcm2835-bootfiles/${VERSION_BCM2835}/${FIRM_DIR}"
        	  WORK_DIR_BCM2835 = "${BASE_WORKDIR}/${MACHINE}-${DISTRO}-${TARGET_OS}"
        	  
        	  EXTRA_OECONF = " \
        	      --host=${HOST_SYS} \
        	      --build=${BUILD_SYS} \
        	      --prefix=${STAGING_DIR_TARGET}/usr/lib/kodi \
        	      --with-toolchain=${STAGING_DIR_TARGET} \
        	      --with-firmware=${WORK_DIR_BCM2835}/${GIT_DIR_BCM2835} \
        	      "
        	  
        	  # конфигурация для платы RPI
        	  EXTRA_OECONF_append_raspberrypi = " --with-platform=raspberry-pi"
        	  # конфигурация для плат RPI2 и RPI3
        	  EXTRA_OECONF_append_raspberrypi2 = " --with-platform=raspberry-pi2"
        	  
        	  
        	  KODI_GEN_TOOLCHAIN = "${WORKDIR}/git/tools/depends/target/Toolchain.cmake"
        	  
        	  # генерация Toolchain.cmake, сами зависимости не собираю,
        	  # для сборки kodi они беруться из yocto project см. kodi_git.bb => DEPENDS
        	  do_configure_prepend() {
        	      cd ${WORKDIR}/git/tools/depends
        	      sh bootstrap
        	      sh configure ${EXTRA_OECONF}
        	  
        	      # исправляю путь 
        	      # в cmake файле ${STAGING_DIR_TARGET}/usr/lib/kodi/KodiConfig.cmake
        	      # иначе при сборке addons не будет найден AddonHelpers
        	      sed -i "s| /usr/lib/kodi| ${STAGING_DIR_TARGET}/usr/lib/kodi|g" \
        	              ${WORKDIR}/recipe-sysroot/usr/lib/kodi/KodiConfig.cmake
        	                                
        	      sed -i "s| /usr/include/kodi| ${STAGING_DIR_TARGET}/usr/include/kodi|g" \
        	              ${WORKDIR}/recipe-sysroot/usr/lib/kodi/KodiConfig.cmake
        	  }
        	  
        	  
        	  # явно указываю корневой системный каталог, 
        	  # иначе cmake тесты компилятора не проходят
        	  CXXFLAGS += "--sysroot=${STAGING_DIR_TARGET}"
        	  CFLAGS += "--sysroot=${STAGING_DIR_TARGET}"
        	  # можно тоже самое сделать вот так
        	  # echo "SET( CMAKE_SYSROOT ${STAGING_DIR_TARGET})" >> ${KODI_GEN_TOOLCHAIN}
        	  
        	  
        	  do_configure() {
        	      echo "SET( OVERRIDE_PATHS 1)" >> ${KODI_GEN_TOOLCHAIN}
        	      
        	      cd ${B}
        	      cmake -DADDONS_TO_BUILD=${ADDONS_NAME} \
        	      -DCMAKE_BUILD_TYPE=Release \
        	      -DCMAKE_TOOLCHAIN_FILE=${KODI_GEN_TOOLCHAIN} \
        	      -DBUILD_DIR=${B} \
        	      -DCMAKE_INSTALL_PREFIX=${D} \
        	      -DPACKAGE_ZIP=1 \
        	      ${S}/project/cmake/addons
        	  }
        	  
        	  
        	  
        	  do_compile_append() {
        	      install -d ${D}/${KODI_ADDON_DIR}
        	      cp -vfR ${D}/pvr.iptvsimple ${D}/${KODI_ADDON_DIR}
        	      rm -fr ${D}/pvr.iptvsimple
        	  
        	      # автоматический запуск бинарного плагина pvr.iptvsimple при старте
        	      # содержимое базы можно посмотреть в "sqlitebrowser"
        	      install -d ${D}/${DB_DIR}
        	      install -m 0644 ${WORKDIR}/db/Addons27.db ${D}/${DB_DIR}
        	  }
        	  
        	  # отключаю метод, так как после сборки 
        	  # файлы уже располагаются в CMAKE_INSTALL_PREFIX=${D} 
        	  do_install[noexec] = "1"
        	  
        - рецепт сборки Kodi плагина pvr-iptvsimple
      • plugin-video-youtube_5.5.1.bb
        
        	  DESCRIPTION = "Plugin Video Youtube"
        	  SECTION = "configs"
        	  PR = "r1"
        	  
        	  LICENSE = "GPL-2.0"
        	  MD5_SUM = "md5=801f80980d171dd6425610833a22dbe6"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;${MD5_SUM}"
        	  
        	  FILESEXTRAPATHS_prepend := "${THISDIR}/addons:"
        	  
        	  KODI_HOME_DIR = "/home/root/.kodi"
        	  KODI_ADDON_NAME = "plugin.video.youtube"
        	  
        	  SRC_URI = "file://${KODI_ADDON_NAME}.tar.gz"
        	  
        	  S = "${WORKDIR}"
        	  PACKAGES = "${PN}"
        	  FILES_${PN} = "${KODI_HOME_DIR}"
        	  
        	  do_install_append() {
        	      install -d ${D}/${KODI_HOME_DIR}/addons/${KODI_ADDON_NAME}
        	      cp -vfR ${S}/${KODI_ADDON_NAME} ${D}/${KODI_HOME_DIR}/addons
        	  }
        	  
        - рецепт сборки Kodi плагина для просмотра "Youtube"
      • screensaver-kodi-universe_0.1.2.bb
        
        	  # Very simple Screensaver for Kodi mediacenter
        	  # autor Alexander Demachev (https://berserk.tv)
        	  
        	  DESCRIPTION = "Screensaver Kodi Universe"
        	  SECTION = "configs"
        	  PR = "r1"
        	  
        	  LICENSE = "GPL-2.0"
        	  MD5_SUM = "md5=801f80980d171dd6425610833a22dbe6"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;${MD5_SUM}"
        	  
        	  GIT_REPO_DIR = "github.com/berserktv"
        	  
        	  require ../kodi/kodi-dir.inc
        	  KODI_ADDON_NAME = "screensaver.kodi.universe"
        	  KODI_ADDON_PATH = "${KODI_ADDON_DIR}/${KODI_ADDON_NAME}"
        	  KODI_MEDIA_PATH = "\
        	      ${KODI_ADDON_PATH}/resources/skins/default/media\
        	      /kodi-universe.mkv"
        	      
        	  KODI_ADDON_VIDEO = "\
        	      https://${GIT_REPO_DIR}/bs-res/raw/master/kodi-plugins\
        	      /${KODI_ADDON_NAME}/isengard/kodi-universe.mkv"
        	  
        	  SRC_URI = "\
        	      ${KODI_ADDON_VIDEO};protocol=https;name=kodi-video \
        	      git://${GIT_REPO_DIR}/${KODI_ADDON_NAME}.git;\
        	      branch=master;name=kodi-addon \
        	      "
        	  
        	  S_SUM="45e6a93eee87b8506d351d13214ffbfe005526b6a146a2d0086e88050aa44785"           
        	  SRCREV_kodi-addon = "a15fd087f9d1bb67388815d18fde1c1a59919290"
        	  SRC_URI[kodi-video.md5sum] = "98f941a6ad29fe7ad4735e8a0eedd4dc"
        	  SRC_URI[kodi-video.sha256sum] = "${S_SUM}"
        	  
        	  
        	  S = "${WORKDIR}/git"
        	  PACKAGES = "${PN}"
        	  FILES_${PN} = "${KODI_HOME_DIR}"
        	  
        	  do_install_append() {
        	      install -d ${D}/${KODI_ADDON_PATH}
        	      rm -fr ${S}/.git
        	      cp -vfR ${S}/* ${D}/${KODI_ADDON_PATH}
        	      install -m 0644 ${WORKDIR}/kodi-universe.mkv ${D}/${KODI_MEDIA_PATH}
        	  }
        	  
        - рецепт сборки плагина screensaver-kodi-universe
      • script-berserk-network_0.2.5.bb
        
        	  # Plugin for Kodi mediacenter
        	  # "Network Manager" is a network management software 
        	  #          for Ethernet and Wifi network connections
        	  # Project "Berserk" - build Kodi for the Raspberry Pi platform
        	  # autor Alexander Demachev, site https://berserk.tv
        	  # license -  The MIT License (MIT)
        	  
        	  DESCRIPTION = "Network Manager is a network management \
        	                 software for Ethernet and Wifi network connections"
        	  SECTION = "configs"
        	  PR = "r1"
        	  LICENSE = "MIT"
        	  MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
        	  
        	  SRC_URI = "git://github.com/berserktv/script.berserk.network.git;branch=master"
        	  SRCREV = "77c1da8e02f7355d274cecd77a65bdff49008074"
        	  
        	  require ../kodi/kodi-dir.inc
        	  KODI_ADDON_NAME = "script.berserk.network"
        	  KODI_ADDON_PATH = "${KODI_ADDON_DIR}/${KODI_ADDON_NAME}"
        	  
        	  
        	  S = "${WORKDIR}/git"
        	  
        	  PACKAGES = "${PN}"
        	  FILES_${PN} = "${KODI_HOME_DIR}"
        	  
        	  RDEPENDS_${PN} += "python-subprocess python-fcntl"
        	  
        	  do_install_append() {
        	      install -d ${D}/${KODI_ADDON_PATH}
        	      install -m 0644 ${S}/addon.xml     ${D}/${KODI_ADDON_PATH}
        	      install -m 0644 ${S}/changelog.txt ${D}/${KODI_ADDON_PATH}
        	      install -m 0644 ${S}/default.py    ${D}/${KODI_ADDON_PATH}
        	      install -m 0644 ${S}/icon.png      ${D}/${KODI_ADDON_PATH}
        	      install -m 0644 ${S}/service.py    ${D}/${KODI_ADDON_PATH}
        	  
        	      cp -vfR ${S}/resources ${D}/${KODI_ADDON_PATH}
        	  }
        	  
        - рецепт сборки плагина настройки сети
      • script-module-requests_2.12.4.bb
        
        	  DESCRIPTION = "Dependenсe for Plugin Video Youtube"
        	  SECTION = "configs"
        	  PR = "r1"
        	  
        	  LICENSE = "GPL-2.0"
        	  MD5_SUM = "md5=801f80980d171dd6425610833a22dbe6"
        	  LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;${MD5_SUM}"
        	  
        	  FILESEXTRAPATHS_prepend := "${THISDIR}/addons:"
        	  
        	  KODI_HOME_DIR = "/home/root/.kodi"
        	  KODI_ADDON_NAME = "script.module.requests"
        	  
        	  SRC_URI = "file://${KODI_ADDON_NAME}.tar.gz"
        	  
        	  S = "${WORKDIR}"
        	  PACKAGES = "${PN}"
        	  FILES_${PN} = "${KODI_HOME_DIR}"
        	  
        	  do_install_append() {
        	      install -d ${D}/${KODI_HOME_DIR}/addons/${KODI_ADDON_NAME}
        	      cp -vfR ${S}/${KODI_ADDON_NAME} ${D}/${KODI_HOME_DIR}/addons
        	  }
        	  
        - рецепт сборки зависимости для плагина Youtube



    состав recipes-multimedia


    
    	└── ffmpeg
    	    ├── ffmpeg
    	    │   ├── 0001-ffmpeg-Call-get_format-to-fix-an-issue-with-MMAL-ren.patch
    	    │   ├── h264_parser.patch
    	    │   └── pfcd_hevc_optimisations.patch
    	    └── ffmpeg_3.1.11.bb
    	
    где:
    • 0001-ffmpeg-Call-get_format-to-fix-an-issue-with-MMAL-ren.patch - патч для ffmpeg
    • h264_parser.patch - патч для коррекции парсера h264
    • pfcd_hevc_optimisations.patch - основной патч с оптимизацией для Raspberry Pi
    • ffmpeg_3.1.11.bb
      
      	SUMMARY = "A complete, cross-platform solution to record, convert and stream audio and video."
      	DESCRIPTION = "FFmpeg is the leading multimedia framework, able to decode, encode, transcode, \
      	               mux, demux, stream, filter and play pretty much anything that humans and machines \
      	               have created. It supports the most obscure ancient formats up to the cutting edge."
      	HOMEPAGE = "https://www.ffmpeg.org/"
      	SECTION = "libs"
      	
      	LICENSE = "BSD & GPLv2+ & LGPLv2.1+ & MIT"
      	LICENSE_${PN} = "GPLv2+"
      	LICENSE_libavcodec = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_libavdevice = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_libavfilter = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_libavformat = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_libavresample = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_libavutil = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_libpostproc = "GPLv2+"
      	LICENSE_libswresample = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_libswscale = "${@bb.utils.contains('PACKAGECONFIG', 'gpl', 'GPLv2+', 'LGPLv2.1+', d)}"
      	LICENSE_FLAGS = "commercial"
      	
      	LIC_FILES_CHKSUM = "file://COPYING.GPLv2;md5=b234ee4d69f5fce4486a80fdaf4a4263 \
      	                    file://COPYING.GPLv3;md5=d32239bcb673463ab874e80d47fae504 \
      	                    file://COPYING.LGPLv2.1;md5=bd7a443320af8c812e4c18d1b79df004 \
      	                    file://COPYING.LGPLv3;md5=e6a600fd5e1d9cbde2d983680233ad02"
      	
      	SRC_URI = "https://www.ffmpeg.org/releases/${BP}.tar.xz \
      	           file://pfcd_hevc_optimisations.patch \
      	           file://h264_parser.patch \
      	           file://0001-ffmpeg-Call-get_format-to-fix-an-issue-with-MMAL-ren.patch \
      	          "
      	
      	SRC_URI[md5sum] = "b7a971e90f56a75f0d52d4085b3d7b4b"
      	SRC_URI[sha256sum] = "ca635a8c2e2f655069ea76c45fc0e60dff17b3b4fac803578d4f131513ee68f4"
      	
      	# Build fails when thumb is enabled: https://bugzilla.yoctoproject.org/show_bug.cgi?id=7717
      	ARM_INSTRUCTION_SET = "arm"
      	
      	# Should be API compatible with libav (which was a fork of ffmpeg)
      	# libpostproc was previously packaged from a separate recipe
      	PROVIDES = "libav libpostproc"
      	
      	DEPENDS = "alsa-lib zlib libogg yasm-native"
      	
      	inherit autotools pkgconfig
      	
      	PACKAGECONFIG ??= "avdevice avfilter avcodec avformat swresample swscale postproc \
      	                   bzlib gpl lzma theora x264 \
      	                   ${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'xv', '', d)}"
      	
      	# libraries to build in addition to avutil
      	PACKAGECONFIG[avdevice] = "--enable-avdevice,--disable-avdevice"
      	PACKAGECONFIG[avfilter] = "--enable-avfilter,--disable-avfilter"
      	PACKAGECONFIG[avcodec] = "--enable-avcodec,--disable-avcodec"
      	PACKAGECONFIG[avformat] = "--enable-avformat,--disable-avformat"
      	PACKAGECONFIG[swresample] = "--enable-swresample,--disable-swresample"
      	PACKAGECONFIG[swscale] = "--enable-swscale,--disable-swscale"
      	PACKAGECONFIG[postproc] = "--enable-postproc,--disable-postproc"
      	PACKAGECONFIG[avresample] = "--enable-avresample,--disable-avresample"
      	
      	# features to support
      	PACKAGECONFIG[bzlib] = "--enable-bzlib,--disable-bzlib,bzip2"
      	PACKAGECONFIG[gpl] = "--enable-gpl,--disable-gpl"
      	PACKAGECONFIG[gsm] = "--enable-libgsm,--disable-libgsm,libgsm"
      	PACKAGECONFIG[jack] = "--enable-indev=jack,--disable-indev=jack,jack"
      	PACKAGECONFIG[libvorbis] = "--enable-libvorbis,--disable-libvorbis,libvorbis"
      	PACKAGECONFIG[lzma] = "--enable-lzma,--disable-lzma,xz"
      	PACKAGECONFIG[mp3lame] = "--enable-libmp3lame,--disable-libmp3lame,lame"
      	PACKAGECONFIG[openssl] = "--enable-openssl,--disable-openssl,openssl"
      	PACKAGECONFIG[schroedinger] = "--enable-libschroedinger,--disable-libschroedinger,schroedinger"
      	PACKAGECONFIG[speex] = "--enable-libspeex,--disable-libspeex,speex"
      	PACKAGECONFIG[theora] = "--enable-libtheora,--disable-libtheora,libtheora"
      	PACKAGECONFIG[vaapi] = "--enable-vaapi,--disable-vaapi,libva"
      	PACKAGECONFIG[vdpau] = "--enable-vdpau,--disable-vdpau,libvdpau"
      	PACKAGECONFIG[vpx] = "--enable-libvpx,--disable-libvpx,libvpx"
      	PACKAGECONFIG[x264] = "--enable-libx264,--disable-libx264,x264"
      	PACKAGECONFIG[xv] = "--enable-outdev=xv,--disable-outdev=xv,libxv"
      	
      	# Check codecs that require --enable-nonfree
      	USE_NONFREE = "${@bb.utils.contains_any('PACKAGECONFIG', [ 'openssl' ], 'yes', '', d)}"
      	
      	def cpu(d):
      	    for arg in (d.getVar('TUNE_CCARGS') or '').split():
      	        if arg.startswith('-mcpu='):
      	            return arg[6:]
      	    return 'generic'
      	
      	EXTRA_OECONF = " \
      	    --disable-stripping \
      	    --enable-pic \
      	    --enable-shared \
      	    --enable-pthreads \
      	    --disable-libxcb \
      	    --disable-libxcb-shm \
      	    --disable-libxcb-xfixes \
      	    --disable-libxcb-shape \
      	    ${@bb.utils.contains('USE_NONFREE', 'yes', '--enable-nonfree', '', d)} \
      	    \
      	    --cross-prefix=${TARGET_PREFIX} \
      	    \
      	    --ld="${CCLD}" \
      	    --cc="${CC}" \
      	    --cxx="${CXX}" \
      	    --arch=${TARGET_ARCH} \
      	    --target-os="linux" \
      	    --enable-cross-compile \
      	    --extra-cflags="${TARGET_CFLAGS} ${HOST_CC_ARCH}${TOOLCHAIN_OPTIONS}" \
      	    --extra-ldflags="${TARGET_LDFLAGS}" \
      	    --sysroot="${STAGING_DIR_TARGET}" \
      	    --enable-hardcoded-tables \
      	    ${EXTRA_FFCONF} \
      	    --libdir=${libdir} \
      	    --shlibdir=${libdir} \
      	    --datadir=${datadir}/ffmpeg \
      	    ${@bb.utils.contains('AVAILTUNES', 'mips32r2', '', '--disable-mipsdsp --disable-mipsdspr2', d)} \
      	    --cpu=${@cpu(d)} \
      	    --pkg-config=pkg-config \
      	"
      	
      	EXTRA_OECONF_append_linux-gnux32 = " --disable-asm"
      	
      	do_configure() {
      	    ${S}/configure ${EXTRA_OECONF}
      	}
      	
      	PACKAGES =+ "libavcodec \
      	             libavdevice \
      	             libavfilter \
      	             libavformat \
      	             libavresample \
      	             libavutil \
      	             libpostproc \
      	             libswresample \
      	             libswscale"
      	
      	FILES_libavcodec = "${libdir}/libavcodec${SOLIBS}"
      	FILES_libavdevice = "${libdir}/libavdevice${SOLIBS}"
      	FILES_libavfilter = "${libdir}/libavfilter${SOLIBS}"
      	FILES_libavformat = "${libdir}/libavformat${SOLIBS}"
      	FILES_libavresample = "${libdir}/libavresample${SOLIBS}"
      	FILES_libavutil = "${libdir}/libavutil${SOLIBS}"
      	FILES_libpostproc = "${libdir}/libpostproc${SOLIBS}"
      	FILES_libswresample = "${libdir}/libswresample${SOLIBS}"
      	FILES_libswscale = "${libdir}/libswscale${SOLIBS}"
      	
      	# ffmpeg disables PIC on some platforms (e.g. x86-32)
      	INSANE_SKIP_${MLPREFIX}libavcodec = "textrel"
      	INSANE_SKIP_${MLPREFIX}libavdevice = "textrel"
      	INSANE_SKIP_${MLPREFIX}libavfilter = "textrel"
      	INSANE_SKIP_${MLPREFIX}libavformat = "textrel"
      	INSANE_SKIP_${MLPREFIX}libavutil = "textrel"
      	INSANE_SKIP_${MLPREFIX}libavresample = "textrel"
      	INSANE_SKIP_${MLPREFIX}libswscale = "textrel"
      	INSANE_SKIP_${MLPREFIX}libswresample = "textrel"
      	INSANE_SKIP_${MLPREFIX}libpostproc = "textrel"
      	
      - рецепт сборки библиотеки ffmpeg (аудио, видео кодеки)


    FFmpeg - OpenSource библиотека для кодирования / декодирования
    огромного количества видео и аудио форматов. FFmpeg поддерживает почти 400 кодеков (ffmpeg -codecs) и более 300 форматов (ffmpeg -formats).




    Дополнение рецепта для сборки "Kodi"


    В слое OpenEmbedded находиться штатный рецепт для сборки Kodi, но он достаточно общий, а мне хотелось бы получить немного более стабильную и проверенную версию для платформы Raspberry Pi.

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

    В мире OpenSource сообщества есть несколько хорошо известных проектов, использующих Kodi, лучшим из которых (на мой взляд) является LibreElec (OpenElec). У LibreElec есть хорошая сборка для платформы Raspberry Pi. Вот у них то и лучше всего взять патч обратного портирования для Kodi. Тем самым, можно избавиться от огромного количества проблем, даже не узнав об этом.

    Мультимедиа центр Kodi заточен на проигрывание "Медиа" контекста, и на мой взгляд самым критичным компонентом является связка Kodi и FFmpeg, т.е. взаимодействие определенных версий этих программ, остальные библиотеки можно оставить из слоев Yocto и OpenEmbedded.

    Для сборки я взял стабильную версия Kodi 17.6 и версию FFmpeg 3.1.11
    Примечание:

    
    	Версия дистрибутива, которую я собираю в рамках данной статьи, 
    	пока не включает систему запуска systemD. На данном этапе 
    	можно обойтись и без него (вопрос достаточно спорный (но пока так)).
    	
    	Для того, чтобы взять патчи из LibreElec вы можете
    	загрузить нужную версию примерно так:
    	
    	    #!/bin/bash
    	
    	    HASH_VER="934507d922fb011ce46c76566206f2f1f603360b"
    	    git clone https://github.com/LibreELEC/LibreELEC.tv.git libreelec
    	    cd libreelec
    	    git checkout ${HASH_VER}
    	
    	
    	патчи для Kodi, располагаются в каталоге:
    	projects/RPi2/patches/kodi
    	
    	(см. файл: kodi-001-backport.patch)
    	
    	патчи для библиотеки FFmpeg, можно посмотреть здесь:
    	packages/multimedia/ffmpeg/patches
    	

    Включаемый файл с описанием версии будет такой kodi-version.inc

    
    	FILESEXTRAPATHS_prepend := "${THISDIR}/kodi:"
    	
    	# ветка Krypton
    	SRCREV = "a9a7a20071bfd759e72e7053cee92e6f5cfb5e48"
    	PV = "17.6+gitr${SRCPV}"
    	


    Ветка Yocto и OpenEmbedded, которую я рассматриваю - rocko, содержит версию Kodi 17.3, и для того чтобы перейти к версии 17.6, достаточно добавить небольшое дополнение для рецепта - kodi_17.bbappend

    
    	require kodi-version.inc
    	
    	# убираю не работающий патч (был для версии 17.3)
    	SRC_URI_remove = "file://0013-FTPParse.cpp-use-std-string.patch"
    	
    	# отключаю патч, так как systemd не использую
    	SRC_URI_remove = "file://0004-handle-SIGTERM.patch"
    	
    	# добавляю патч обратного портирования для RPI взятого из libreelec
    	SRC_URI_append += "file://kodi-krypton-rpb-backports.patch"
    	
    	# исправление error adding symbols: DSO missing from command line
    	SRC_URI_append += "file://vchostif.patch"
    	
    	
    	MENU_ICON = "addons/skin.estuary/media/icons/settings"
    	# добавление нового пункта в меню настроек (значок шестеренки)
    	SRC_URI_append += "file://bs-menu.patch file://icon/bs-network.png"
    	do_configure_prepend() {
    	    install -m 0644 ${WORKDIR}/icon/bs-network.png ${S}/${MENU_ICON}
    	}
    	
    	# дополнительные зависимости для kodi plugins
    	RRECOMMENDS_${PN}_append = "\
    	                  python-xml python-misc python-db \
    	                  python-crypt python-threading python-math python-email \
    	                  python-io python-netserver python-urllib3 python-datetime"
    	
    	
    	# специфическии опции для плат Raspberry Pi
    	# реализация OPENGL обязательно должна быть --enable-gles
    	# для kodi зависимости сборки указаны в docs/README.linux => libxmu libxinerama 
    	#                                                            libxtst xdpyinfo
    	# для сборки этих библиотек в DISTRO_FEATURES необходима зависимость "x11"
    	# но сам kodi для RPI1 и RPI2,3 собирается с опцией --disable-x11
    	
    	BS_RPI = " --disable-gl --enable-openmax --enable-player=omxplayer \
    	           --with-platform=raspberry-pi --disable-x11"
    	
    	BS_RPI3 = " --disable-gl --enable-openmax --enable-player=omxplayer \
    	            --with-platform=raspberry-pi2 --disable-x11"
    	
    	EXTRA_OECONF_append = "${@bb.utils.contains('MACHINE', 'raspberrypi', \
    	                                                       '${BS_RPI}', '', d)}"
    	                       
    	EXTRA_OECONF_append = "${@bb.utils.contains('MACHINE', 'raspberrypi2', \
    	                                                       '${BS_RPI3}', '', d)}"
    	
    	EXTRA_OECONF_append = "${@bb.utils.contains('MACHINE', 'raspberrypi3', \
    	                                                       '${BS_RPI3}', '', d)}"
    	
    	# опция для появления всплывающего сообщения в Kodi о подключении 
    	# внешнего носителя, например USB или microSDHC диска (через картридер)
    	EXTRA_OECONF_append = " --enable-optical-drive"
    	

    Опция сборки "--enable-optical-drive" позволяет подключить удобный механизм оповещения, который используется в Kodi при подключении оптического диска. В этом случае модуль MediaManager(а) (xbmc/storage/MediaManager.cpp) отслеживает подключение/отключение новых дисковых разделов, и выводит на экран всплывающее сообщение об этом.

    пример udev правила подключения/отключения дисков:
    /etc/udev/rules.d/85-automount.rules.html

    
    	ACTION=="add" SUBSYSTEM=="block"  ENV{ID_FS_TYPE}=="vfat" KERNEL=="sd[a-z][0-9]" \
    	              RUN+="/bin/mkdir -p /media/%k", \
    	              RUN+="/bin/mount -o iocharset=utf8,noatime /dev/%k /media/%k"
    	
    	
    	ACTION=="add" SUBSYSTEM=="block"  ENV{ID_FS_TYPE}=="ntfs" KERNEL=="sd[a-z][0-9]" \
    	              RUN+="/bin/mkdir -p /media/%k", \
    	              RUN+="/usr/bin/ntfs-3g -o iocharset=utf8,noatime,windows_names /dev/%k /media/%k"
    	
    	
    	ACTION=="add" SUBSYSTEM=="block"  ENV{ID_FS_TYPE}=="ext2|ext3|ext4" KERNEL=="sd[a-z][0-9]" \
    	              RUN+="/bin/mkdir -p /media/%k", \
    	              RUN+="/bin/mount -o noatime /dev/%k /media/%k"
    	
    	
    	ACTION=="remove" SUBSYSTEM=="block" KERNEL=="sd[a-z][0-9]" \
    	                 RUN+="/bin/umount /media/%k", RUN+="/bin/rmdir /media/%k"
    	

    Примечание:
    команда rmdir умеет удалять только пустые каталоги, а вот не пустые уже нет (пример Linux подхода одна программа - одна функция) и в данном контексте ее применение безопасно.



    Добавление нового пункта в меню настроек Kodi

    В Kodi 17.6, за отображение пунктов меню отвечают конфигурационные xml файлы.
    Для добавления еще одного под пункта в меню "Settings", достаточно подкорректировать файл:
    kodi/addons/skin.estuary/xml/Settings.xml

    где skin.estuary - тема оформления меню по умолчанию

    описание пункта выглядит так:

    	<item>
    	    <label>$LOCALIZE[13279]</label>
    	    <onclick>RunAddon(script.berserk.network,butnetwork)</onclick>
    	    <icon>icons/settings/bs-network.png</icon>
    	</item>
    	

    где:
  • label - название пункта меню
  • onclick - обработка событие нажатия на кнопку меню
    (запуск плагина, с передачей первым аргументом строки "butnetwork")
  • icon - иконка пункта меню (путь к png изображению)


  • Указанная выше функциональность, а также подключение нескольких дополнительных Kodi плагинов интегрирована с помощью файла bs-menu.patch

    
    	diff -Naur a/addons/skin.estuary/xml/Settings.xml b/addons/skin.estuary/xml/Settings.xml
    	--- a/addons/skin.estuary/xml/Settings.xml	2018-02-01 18:17:45.000000000 +0300
    	+++ b/addons/skin.estuary/xml/Settings.xml	2018-03-08 12:06:50.000000000 +0300
    	@@ -134,6 +134,11 @@
    	 			<icon>icons/settings/interface.png</icon>
    	 		</item>
    	 		<item>
    	+			<label>$LOCALIZE[13279]</label>
    	+			<onclick>RunAddon(script.berserk.network,butnetwork)</onclick>
    	+			<icon>icons/settings/bs-network.png</icon>
    	+		</item>
    	+		<item>
    	 			<label>$LOCALIZE[20077]</label>
    	 			<onclick>ActivateWindow(SkinSettings)</onclick>
    	 			<icon>icons/settings/skin.png</icon>
    	diff -Naur a/system/addon-manifest.xml b/system/addon-manifest.xml
    	--- a/system/addon-manifest.xml	2018-03-07 15:58:24.000000000 +0300
    	+++ b/system/addon-manifest.xml	2018-05-14 14:06:58.000000000 +0300
    	@@ -27,6 +27,7 @@
    	   <addon>resource.uisounds.kodi</addon>
    	   <addon>screensaver.xbmc.builtin.black</addon>
    	   <addon>screensaver.xbmc.builtin.dim</addon>
    	+  <addon>screensaver.kodi.universe</addon>
    	   <addon>script.module.pil</addon>
    	   <addon>service.xbmc.versioncheck</addon>
    	   <addon>skin.estuary</addon>
    	@@ -43,4 +44,8 @@
    	   <addon>xbmc.python</addon>
    	   <addon>xbmc.webinterface</addon>
    	   <addon optional="true">peripheral.joystick</addon>
    	+  <addon>script.berserk.network</addon>
    	+  <addon>resource.language.ru_ru</addon>
    	+  <addon>script.module.requests</addon>
    	+  <addon>plugin.video.youtube</addon>
    	 </addons>
    	

    Максимальные настройки буферизации для видео


    В мультимедиа центре Kodi для увеличения производительности можно указать
    максимальные настройки буферизации:
    advancedsettings.xml

    
    	<advancedsettings>
    	  <cache>
    	    <buffermode>1</buffermode>
    	    <memorysize>139460608</memorysize>
    	    <readfactor>20</readfactor>
    	  </cache>
    	</advancedsettings>
    	

    buffermode=1
    - буферизировать запросы для всех файловых систем (включая локальную)

    readfactor
    - регулирует скорость загрузки на основе среднего битрейта видео. Так, например, если вы воспроизводите видео со средней скоростью передачи данных 5 Мбит/с и устанавливаете коэффициент чтения буфера на 2.0, это ограничит скорость загрузки (и, следовательно, скорость заполнения кеша) примерно до 10 Мбит/с, таким образом:

    readfactor=20
    снимает ограничение на скорость загрузки

    memorysize =139460608
    - размер буфера составляет 133 МБайт, при этом используется 133*3 оперативной памяти
    т.е. около 400 Мбайт оперативной памяти



    Просмотр телевидения по протоколу IPTV


    Медиацентр Kodi является очень мощным инструментом для просмотра цифрового контента.

    Основной функцией, для которой я собирал "Медиацентр" является функция просмотра цифрового телевидения по протоколу IPTV (Internet Protocol Television) т.е. телевидение по протоколу интернета.
    С помощью данной функции вы можете просматривать цифровое телевидение от вашего интернет провайдера.

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

    Для поддержки IPTV в Kodi существует несколько вариантов плагинов, из которых я остановился на плагине pvr.iptvsimple
    Для сборки плагина используется рецепт:

    	    └── kodi-plugins
    	        └── kodi-pvr-iptvsimple.bb
    	
    Плагин подключается/настраивается через:
    Основное меню Kodi => "Дополнения" => "Мои дополнения" => "Клиенты PVR" => "PVR IPTV Simple Client"

    Для проверки работы IPTV телевидения в составе Kodi, я взял несколько общедоступных новостных информационных каналов и добавил их в список в формате m3u8, а также включил автоматический запуск плагина "pvr.iptvsimple" при старте медиацентра.


    Просмотр Youtube с помощью Kodi плагина


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

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

    Самым интересным и распространенным plugin(ом) для Kodi по моему убеждению является плагин просмотра Youtube. Kodi же мультимедиа центр, а Youtube самое огромное хранилище этого самого мультимедиа контента, так что плагин Youtube для Kodi почти обязателен.

    Плагин написан на языке python, это штатный механизм плагинов, вам не нужно ничего компилировать, достаточно просто скопировать готовый плагин в корневой каталог с плагинами, и указать имя плагина в xml файле манифеста
    "system/addon-manifest.xml"

    Плагин взят из официального репозитория, и его исходный код включен в архив
    recipes-mediacentre/kodi-plugins/files/plugin.video.youtube.tar.gz

    Расположение рецепта сборки плагина см. выше в главе "состав recipes-mediacentre"

    Консольное shell расширение конфигурации сети


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

    	##############################################################
    	# пример возможного использования в /etc/network/interfaces:
    	##############################################################
    	auto eth0
    	     iface eth0 inet manual
    	     up /etc/network/eth-manual $IFACE up
    	     down /etc/network/eth-manual $IFACE down
    	
    	auto wlan0
    	     iface wlan0 inet manual
    	     up /etc/network/wlan $IFACE up
    	     down /etc/network/wlan $IFACE down
    	

    Для удобной настройки Ethernet/WLAN сетевых интерфейсов через GUI, у меня используется еще один небольшой Kodi плагин "script.berserk.network". Это единственный Kodi plugin, в котором я разобрался, но для этого мне пришлось его написать. Он предельно компактный и минималистичный и написан на языке "python".

    Оба этих компонента, собираются с помощью рецептов:

    • recipes-berserk/bs-net/bs-net_0.1.3.bb
    • recipes-mediacentre/kodi-plugins/script-berserk-network_0.2.5.bb


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


    Для автоматического подключения к WiFi точке доступа при старте системы
    используется udev правило: /etc/udev/rules.d/80-wifi-start.rules

    
    	SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", KERNEL=="wlan*", \
    	                  RUN+="/etc/network/wlan-runner $env{INTERFACE} up"
    	
    	SUBSYSTEM=="net", ACTION=="remove", DRIVERS=="?*", KERNEL=="wlan*", \
    	                  RUN+="/etc/network/wlan-runner $env{INTERFACE} down"
    	


    Описание хранителя экрана


    screensaver.kodi.universe вы можете посмотреть здесь



    Рецепт сборки дистрибутива


    В Yocto Project предусмотрен механизм повторного использования. Есть классы, от которых вы можете наследоваться (директива "inherit"), и есть базовые рецепты, которые вы можете подключить (директива "include")

    Покажу наследование на примере класса:
    poky/meta/clasess/core-image.bbclass

    Класс отвечает за описание групп пакетов, которые вы можете включить в тот или иной рецепт. Для этого достаточно указать в начале рецепта конструкцию:
    inherit core-image

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

    Особенности образа указываются так:

    	IMAGE_FEATURES += "ssh-server-dropbear splash"
    	

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

    Основной базовый рецепт, который я использую:
    poky/meta/recipes-core/images/core-image-minimal.bb

    Рецепт сборки дистрибутива

    
    	# Project: "Berserk" - build Kodi for the Raspberry Pi platform
    	#           autor: Alexander Demachev, site: https://berserk.tv
    	# license - The MIT License (MIT)
    	
    	DESCRIPTION = "Berserk - the image for the Raspberry PI"
    	LICENSE = "MIT"
    	MD5_SUM = "md5=0835ade698e0bcf8506ecda2f7b4f302"
    	LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;${MD5_SUM}"
    	
    	IMAGE_FEATURES += "ssh-server-dropbear splash"
    	
    	# немного увеличиваю размер rootfs в кило байтах (250000kB=~250Mb)
    	IMAGE_ROOTFS_EXTRA_SPACE_append += "+ 250000"
    	
    	
    	# BS - BerSerk, version 0.2.5 - "Torvin"
    	# Base this image on core-image-minimal
    	include recipes-core/images/core-image-minimal.bb
    	
    	# Set default password for 'root' user
    	inherit extrausers
    	ROOTUSERNAME = "root"
    	ROOTPASSWORD = "berserk"
    	EXTRA_USERS_PARAMS = "usermod -P ${ROOTPASSWORD} ${ROOTUSERNAME};"
    	
    	
    	# стартовая заставка, которая выводиться во время загрузки
    	SPLASH = "psplash-berserk"
    	
    	BS_DEBUG_TOOLS = "ldd strace ltrace"
    	
    	BS_GLIBC = "glibc-thread-db \
    	            glibc-gconv-utf-16 \
    	            glibc-gconv-utf-32 \
    	            glibc-binary-localedata-en-us \
    	            glibc-binary-localedata-ru-ru \
    	            glibc-charmap-utf-8 \
    	            "
    	
    	BS_BASE = "kernel-modules \
    	           lsb \
    	           pciutils \
    	           parted \
    	           tzdata \
    	           dosfstools \
    	           ntp \
    	           ntpdate \
    	           e2fsprogs-resize2fs \
    	           ntfs-3g \
    	           ntfsprogs \
    	           "
    	
    	BS_WLAN = "kernel-module-rt2800usb \
    	           kernel-module-rt2800lib \
    	           kernel-module-rt2x00lib \
    	           kernel-module-rt2x00usb \
    	           kernel-module-cfg80211 \
    	           kernel-module-nls-utf8 \
    	           kernel-module-ath9k-common \
    	           kernel-module-ath9k-hw \
    	           kernel-module-ath9k-htc \
    	           kernel-module-ctr \
    	           kernel-module-ccm \
    	           kernel-module-arc4 \
    	           "
    	
    	BS_WIFI_SUPPORT = " \
    	        iw \
    	        dhcp-client \
    	        wireless-tools \
    	        wpa-supplicant \
    	        linux-firmware \
    	        "
    	
    	BS_SOFT = "mc \
    	           kodi \
    	           kodi-runner \
    	           kodi-settings \
    	           kodi-language-ru \
    	           kodi-pvr-iptvsimple \
    	           bs-net \
    	           tv-config \
    	           first-run \
    	           script-berserk-network \
    	           screensaver-kodi-universe \
    	           plugin-video-youtube \
    	           script-module-requests \
    	           "
    	
    	
    	
    	# Include modules in rootfs
    	IMAGE_INSTALL += " \
    	    ${BS_BASE} \
    	    ${BS_WLAN} \
    	    ${BS_WIFI_SUPPORT} \
    	    ${BS_GLIBC} \
    	    ${BS_SOFT} \
    	    ${BS_DEBUG_TOOLS} \
    	    "
    	

    Хотел бы уточнить, что например пакет "kernel-modules", установит все модули ядра указанные в файле defconfig в образ дистрибутива.


    Но если вы что то сильно кастомизируете, то конечно все модули ядра вам могут и не понадобиться, в таком случае удобно добавлять каждый модуль по имени, как указано в переменной BS_WLAN, это как шпаргалка, указываем только то, что нужно и после проверки работы пакет "kernel-modules" убираем, проверяем и т.д.



    Краткая инструкция по созданию образа дистрибутива


    1) Установите зависимости Yocto Project в Ubuntu:
    	sudo apt-get install -y --no-install-suggests --no-install-recommends \
    	     gawk wget git-core diffstat unzip texinfo gcc-multilib build-essential \
    	     chrpath socat cpio python python3 python3-pip python3-pexpect \
    	     xz-utils debianutils iputils-ping python3-git python3-jinja2 \
    	     libegl1-mesa libsdl1.2-dev xterm
    	

    2) Скачайте и установите Repo:
    	mkdir ~/bin
    	curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
    	chmod a+x ~/bin/repo
    	

    3) Загрузите проект с github:
    	mkdir torvin
    	cd torvin
    	repo init -u https://github.com/berserktv/bs-manifest -m raspberry/rocko/torvin-0.2.5.xml
    	repo sync	
    	

    4) Соберите проект:
    	./shell.sh
    	bitbake berserk-image
    	

    5) Запишите образ дистрибутива на карту памяти
    	Собранный образ после сборки будет располагаться по пути
    	torvin/build/tmp/deploy/images/raspberrypi3 
    	
    	На последний успешно собранный образ
    	всегда будет указывать символическая ссылка:
    	berserk-image-raspberrypi3.rpi-sdimg
    	
    	cам файл будет содержать достаточно длинное имя 
    	c датой создания и временем в UTC
    	
    	Пример записи образа дистрибутива с помощью команды dd
    	
    	ПРЕДУПРЕЖДЕНИЕ: 
    	все предыдущие данные на карте памяти "microSDHC"
    	после выполнения операции записи будут удалены.
    	
    	$ sudo bash
    	$ cd torvin/build/tmp/deploy/images/raspberrypi3
    	$ dd if=berserk-image-raspberrypi3.rpi-sdimg of=/dev/sdX bs=1M
    	$ sync
    	
    	
    	где /dev/sdX:
    	X может быть a,b,c и т.д. 
    	в зависимости от предыдущих подключенных дисковых разделов
    	
    	уже собранный образ можно загрузить с моего домашнего сайта
    	Для записи образа под Windows, вы можете воспользоваться 
    	программой Win32 Disk Imager находиться здесь
    	более подробную инструкцию можно посмотреть здесь
    	


    Примечание:
    	Время сборки образа дистрибутива достаточно длительное
    	и может занимать от трех до N часов в зависимости от производительности
    	компьютера, также в процессе сборки из "Интернета" должны быть
    	загружены исходные коды всех программ входящих в дистрибутив,
    	часто это полные git базы
    	
    	(т.е. время сборки также зависит от скорости подключения сети "Интернет")
    	
    	например на машине: Процессор       - Intel(R) Core(TM) i5-3570 CPU @ 3.40GHz
    	                    ОЗУ             - 8 Гбайт
    	                    Жесткий диск    - внешний USB-3.0  1Tбайт
    	
    	                    Время сборки    - 4 часа 05 минут
    	                    Размер образа   - 1 Гбайт 
    	                    
    	                    размер в архиве - 274.8 Mбайт 
    	
    	Размер каталога torvin/build после завершения сборки
    	(cache сборки, исходный код программ, промежуточные файлы сборки, объектные файлы,
    	дополнительные мета данные, файлы пакетов и т.п.)
    	                                    - Занимает примерно 42 ГБайт
    	
    	Размер каталога torvin/downloads    - Занимают 9.1 Гбайт
    	(git базы приложений и tar.gz архивы)
    	
    	Размер rootfs раздела образа        - 550 Мбайт
    	      из них каталог /lib/firmware  - 212 Мбайт
    	                     /lib/modules   - 53  Мбайт
    	
    	примечание: вы можете ставить не все модули и firmware (а только нужные вам)
    	            тем самым можно значительно уменьшить размер дистрибутива,
    	            минимум на 200 Мб
    	
    	




    Постскриптум


    Возможности OpenSource за последние годы только увеличиваются.

    А возможности эти не малые, за примерами далеко ходить не надо. Вряд ли та же "Microsoft" ожидала, что OpenSource технологии выбросят ее с рынка мобильных операционных систем. Я имею ввиду ОС от Google - "Android", которая в одночасье выбросила "Пионера" мобильных систем на обочину. И не понятно, сможет ли Microsoft, снова на него вернуться.

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

    Лучшие OpenSource проекты со временем становятся произведением искусства (например Kodi, Openelec/libre и т.д.)

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

    Побольше вам сборок хороших и разных, и помните "мир интернета вещей наступает".