Разработка автоматизированной среды сборки кросс-платформенного по для ОС семейства Linux

нужна установка, не использует сторонних библиотек. Но требует Perl или Python.

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

Здесь все зависит только от вас самих. Можно тестами покрыть 100% кода, но это большая трата ресурсов. Золотая середина, по моему мнению -нетривиальные публичные функции.

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

Отдельно я бы хотел рассмотреть boost test framework

Каждый файл, использующий boost test framework, должен подключать соответствующий заголовочный файл:

#include <boost/test/unit test.hpp>

Как известно, любая программа должна иметь точку входа (функцию, с которой начинается выполнение программы). В зависимости от того, как организован проект, вы можете либо написать эту функцию сами, либо доверить всю работу Boost. Функция main будет добавлена автоматически, если перед подключением unit test.hpp объявлены константы BOOST_TEST_MAIN и BOOST_TEST_DYN_LINK. Вызовы всех тестов проекта будут автоматически помещены в сгенерированную функцию.

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

Для описания тестовых случаев применяется макрос BOOST_AUTO_TEST_CASE, содержащий имя и код теста. Код теста содержит специальные макросы, проверяющие соответствие фактических результатов работы функции ожидаемым. Макросы отличаются уровнем предупреждения (CHECK - ошибка, REQUIRE - критическая ошибка, WARN - предупреждение). Среди макросов есть следующие:

BOOST CHECK (условие) - сообщает об ошибке, если условие ложно;

BOOST_REQUIRE_EQUAL(apryMeHT_1, аргумент_2) - сообщает о критической ошибке, если аргумент 1 не равен аргумент 2;

BOOST_WABN_MESSAGE(y^OBMe, сообщение) - выводит предупреждение с текстом сообщения, если условие ложно;

BOOST_CHECK_NO_THROW(выpажeниe) - сообщает об ошибке, если при вычислении выражения вырабатывается исключение;

BOOST_CHECK_THROW(выpажeниe, исключение) -сообщает об ошибке, если при вычислении выражения не вырабатывается исключение требуемого типа;

BOOST_CHECK_CLOSE_FRACTION( аргумент_1, аргумент 2, погрешность) - проваливает тест если аргумент 1 не равен аргумент 2 с заданной погрешностью.

Более полный список доступных макросов можно найти в официальной документации.

Пример unit-тестирования с boost test framework

Рассмотрим простой класс, который способен делить и умножать некоторые числа и сохраненять результат:

class Calculator {

public:

explicit Calculator

{ }

void Divide

{

if (value == 0) {

throw std::invalid argument ("Деление на ноль!");

}

Value /= value;

}

void Multiply

{

Value *= value;

}

int Result() const

{

return Value ;

}

private:

int Value ;

};

Тестировать будем следующим образом - сначала вызовем метод Divide с несколькими значениями и сравним результат возвращаемый Result с эталонными значениями, потом проделаем это с методом Multiply.

#include "calculator.h"

#include <boost/test/unit test.hpp>

#define BOOST_TEST_MODULE testCalculator

BOOST_AUTO_TEST_CASE(testCalculator) {

Calculator calculator(12);

BOOST_CHECK_EQUAL(calculator.Result(),

12);

calculator.Divide(3);

BOOST_CHECK_EQUAL(calculator.Result(),

4);

calculator.Divide(2);

BOOST_CHECK_EQUAL(calculator.Result(),

2);

calculator.Multiply(2);

BOOST_CHECK_EQUAL(calculator.Result(),

4);

calculator.Multiply(3);

BOOST_CHECK_EQUAL(calculator.Result(),

12); }

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

УДК 004.4'233 Трусов Е.В.

ФГБОУ ВО «Пензенский государственный университет», Пенза, Россия

РАЗРАБОТКА АВТОМАТИЗИРОВАННОЙ СРЕДЫ СБОРКИ КРОСС-ПЛАТФОРМЕННОГО ПО ДЛЯ ОС СЕМЕЙСТВА LINUX

Введение

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

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

Для сборки нам потребуется следующее:

Программа, собираемая под различные платформы Сборочные среды chroot

Скрипты сборки

Программа, собираемая под различные платформы В качестве программы возьмем классическую программу Hello World на языке c++. Текст программы можно найти в приложении, в пунке "Программа".

Назовем файл project.cpp и попробуем его скомпилировать. Для этого используем компилятор g++. Если программа использует новые методы и функции, то лучше его обновить, в данном случае это не обязательно.

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

Makefile - это набор инструкций для программы make, которая помогает собирать программный проект.

Если запустить make

то программа попытается найти файл с именем по умолчанию Makefile в текущем каталоге и выполнить инструкции из него. Если в текущем каталоге есть несколько мейкфайлов, то можно указать на нужный вот таким образом: make -f MyMakefile Процесс сборки следующий:

Компилятор берет файлы с исходным кодом и получает из них объектные файлы. Затем линковщик берет объектные файлы и получает из них исполняемый файл. Сборка = компиляция + линковка. Компиляция программы

Возможный способ собрать программу: g++ (файлы.cpp) -o (название) Самый простой Makefile В нем должны быть такие части: цель: зависимости [tab] команда

Для нашего примера makefile будет выглядеть так:

CC=g++ // Это показывает, что переменная СС указывает на компилятор, используемый для сборки.

all:

$(CC) project.cpp -o project

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

Теперь если мы запустим make, находясь в директории с созданным makefile, он скомпилирует project.cpp и в результате будет создан исполняемый файл project. При его запуске будет выводиться "Hello World!" В командную строку.

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

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

Для начала создадим chroot для Debian 7.6 i386. С помощью пакета debootstrap:

debootstrap - arch i386 wheeze

Эта команда скачает пакеты debian с сайта в нужную директорию.

Далее нужно будет примонтировать некоторые папки к директории для обеспечения функционала: mount --bind /dev (путь к директории)/dev

mount --bind /sys (путь к директории)/sys mount -proc none (путь к директории)/proc mount -devpts none (путь к директо-рии)/dev/pts

И теперь уже можно зайти chroot: chroot

Для нашей программы нужны пакеты make и g++. Если таковых нет, то доставляем их с помощью менеджера пакетов apt. apt-get install make apt-get install gcc-c++

Теперь если поместить исходные файлы в chroot и выполнить make, то получится программа, исполняющаяся в Debian 7.6 i386. Выйдем из chroot:

exit

umount (путь к директо-

рии)/{dev/pts,proc,sys,dev}

Заархивируем папку с системой, чтобы она занимала меньше места:

tar -cf

Так же создадим chroot для Ubuntu 14.04 i386. По такому же принципу.

Написание скрипта сборки

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

1) Первым запускается build.sh, он активирует сборку под все требуемые платформы.

2) За ним build for platform.sh, он разархи-вирует chroot(bi), монтирует их, копирует в появившуюся систему программу и makefile и вызывает скрипт inchroot.

3) Он в свою очередь собирает программу по алгоритму makefile и возвращает управление build for platform.sh

4) Скрипт положит в выбранную папку собранную программу, размонтирует и удалит распакованный chroot и передаст управление build.sh

5) Если есть еще платформа он вновь запустит build for platform.sh, в противном случае завершается работу.

Build.sh - главный сборочный скрипт, написанный на языке bash. Он запускает сборку под все требуемые платформы, делает требуемые экспорты переменных, для использования в скрипте build_for_platform.sh

Одной из основных сущностей этого скрипта является функция

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

Параметры в функцию передаются следующим образом:

При вызове build_for_platform Ubuntu 14.04 i38 6 $CHROOT_ARCHIVE_DIR/Ubuntu-14.04-i386.tar build_for_platform = $0 Ubuntu = $1 14.04 = $2 i38 6 = $3

$CHROOT_ARCHIVE_DIR/Ubuntu-14.04-i386.tar =

$4

Во время приёма параметров функция экспортирует соответствующие переменные, определяющую целевую платформу, чтобы подготовить окружение для скрипта build_package_for_platform.sh: export DISTR_NAME=$1 export DISTR_VERSION=$2 export DISTR_ARCH=$3 export CHROOT_ARCHIVE=$4

Также в ней есть проверка на наличие архива со сборочной средой chroot и результата вызова скрипта сборки для конкретной платформы: if ! [ -f $CHROOT_ARCHIVE ]; then ...<сообщение об ошибке > fi

Сборочный скрипт ./build for platform.sh производит сборку программы под требуемую плафторму.

В процессе его работы выполняется создание каталогов для сборки и извлечения архива со средой сборки chroot, монтирования каталогов /dev, /proc, /sys из основной ОС в файловую систему chroot, копирование исходных кодов программы и скрипта сборки в файловую систему chroot, запуск команды сборки через утилиту chroot и копирования результатов сборки в выбранное место.

Основные используемые переменные и константы, используемые в скрипте: BUILD_DIR=build/ CHROOT_ARCHIVE=$4 CHROOT_DIR=myproject/chroot FULL_CHROOT_DIR=/home/etrusov/qt/prac-tic/$CHROOT_DIR

Здесь BUIILD DIR - каталог, куда будут складываться версии программы под разнее платформы; CHROOT_ARCHIVE - имя файла архива со сборочной средой chroot; CHROOT_DIR - относительный путь каталога извлечения chroot-архива;

FULL_CHROOT_DIR - абсолютный путь каталога извлечения chroot-архива.

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

mkdir -p $BUILD_DIR/ mkdir -p $CHROOT_DIR/

Ход работы скрипта можно отследить по комментариям, например, таким:

echo "Preparing CHROOT directory" При помощи команды tar -xf архив со сборочной средой chroot распаковывается в выбранную директорию.

Копирование файлов для сборки в chroot-среде производится через команду cp. Помимо makefile и файла с исходным кодом производится копирование скрипта, который выполняется непосредственно в chroot-среде.

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

Команда входа в chroot-среду и сборки программы выглядит так:

chroot $FULL_CHROOT_DIR/$1-$2-$3

./inchroot.sh

Скрипт inchroot.sh выполняет команду make, которая активирует компиляцию. На выходе его работы образуется исполняемый файл программы для соответствующего Linux-дистрибутива.

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

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

"Project for <Имя ОС>-<Версия ОС>-<Архитек-тура ОС> has been built successfully"

В результате выполнения build.sh в каталоге /build создаются файлы:

project-Debian-7.6-i38 6

project-Ubuntu-14.04-i38 6

Приложение

Программа:

#include <iostream>

using namespace std;

int main() {

cout << "Hello World!" << endl;

return 0; }

Makefile:

CC=g++

all:

$(CC) project.cpp -o project Скрипт build.sh: #!/bin/bash

export CHROOT_AR-

CHIVE DIR=/home/etrusov/qt/practic/myprogect

build for platform() { " "

export DISTR_NAME=$1 export DISTR_VERSION=$2 export DISTR_ARCH=$3 export CHROOT_ARCHIVE=$4 if ! [ -f $CHROOT_ARCHIVE ]; then echo "chroot arhive fot $DISTR_NAME-$DISTR_VERSION-$DISTR_ARCH not found:

$CHROOT_ARCHIVE" exit fi

./build_for_platform.sh $DISTR_NAME

$DISTR_VERSION $DISTR_ARCH $CHROOT_ARCHIVE ret=$?

if [ $ret -eq 0 ]; then

echo "Project for $DISTR_NAME-$DISTR_VERSION-$DISTR_ARCH has been built successfully" else

echo "Failed to build project for $DISTR_NAME-$DISTR_VERSION-$DISTR_ARCH"

fi }

build_for_platform Ubuntu 14.04 i386 $CHROOT_ARCHIVE_DIR/Ubuntu-14.04-i386.tar

build for platform Debian 7.6 i386

$CHROOT_ARCHIVE_DIR/Debian-7.6-i386.tar Скрипт build_for_platform.sh: #!/bin/bash " " BUILD_DIR=build/ CHROOT_ARCHIVE=$4 CHROOT_DIR=myproject/chroot FULL_CHROOT_DIR=/home/etrusov/qt/prac-tic/$CHROOT_DIR

mkdir -p $BUILD_DIR/

mkdir -p $CHROOT_DIR/

echo "Preparing CHROOT directory"

tar -xf $CHROOT_ARCHIVE -C $CHROOT_DIR

if [ $? -gt 0 ]; then

echo "Failed to extract CHROOT archive" rm -rf "$CHROOT_DIR" exit fi

echo "CHROOT directory has been prepared"

cp Makefile $CHROOT_DIR/$1-$2-$3 cp progect.cpp $CHROOT_DIR/$1-$2-$3 cp inchroot.sh $CHROOT_DIR/$1-$2-$3 mount —bind /dev $FULL_CHROOT_DIR/$1-$2-$3/dev

mount —bind /sys $FULL_CHROOT_DIR/$1-$2-$3/sys

mount -t proc none $FULL_CHROOT_DIR/$1-$2-$3/proc

mount -t devpts none $FULL_CHROOT_DIR/$1-$2-$3/dev/pts

unset module

chroot $FULL_CHROOT_DIR/$1-$2-$3

./inchroot.sh

mv $CHROOT_DIR/$1-$2-$3/project

$CHROOT_DIR/$1-$2-$3/project-$1-$2-$3

cp $CHROOT_DIR/$1-$2-$3/project-$1-$2-$3

$BUILD_DIR

umount $FULL_CHROOT_DIR/$1-$2-

$3/{dev/pts,proc,sys,dev} rm -rf $CHROOT_DIR Скрипт inchroot: #!/bin/bash make exit

Труды Международного симпозиума «Надежность и качество», 2016, том 1 Скриншоты:

Левая панель Файл Команда Настройки Правая панель

Размер

Г - ВВЕРХ- июл6 13:17||

Debian-7.6-i386.tar UbuntJ-14.S4-i386.tar 83432 86347 июн 1 16:20 ишн 5 15:11

Рисунок 1 - Каталог проекта

Файл Правка Вид Поиск Терминал Справка

Команда Настройки

Правая панель

-Л ч>1

И Имя Размер Время правки

-ВВЕРХ- июл 9 14 1

/build 4096 июл 6 12 49

/mypreject 4096 июл 6 13 18

Makef Hg 177 июл 7 13 17

*build.sh 835 июл 6 12 55

*build pKgs for platform.sh 951 июл 7 13 17

*inchroot. sh 23 июл 6 11 24

inf.odt 514202 июл 6 13 ш

project,cpp 109 июл 2 14 18

Рисунок 2 - Архивы chroot

Файл Правка Вид Поиск Терминал Справка

Левая панель Файл Команда Настройки Правая панель

Имя

/Debian-7.6-i386

/Ubuntu-14.04-i386

Рисунок 3 - Разархивированные chroot архивы

Файл Правка Виц Поиск Терминал Справка

Левая панель Файл Команда Настройки Правая панель

/bin

/boot

/dev

/etc

/home

/lib

/media

/mrit

/opt /proc

/root

/run

/sbin

/selinux

/srv

/sys /tmp

/jsr

/var

Makefile

*inchroot.sh

*progect-Debian-7.6-i386

progect.cpp

а и 23

юн 1

ай 28

юн 1

юн 1

юн 1

ай 28

нв 5

ай 28

нв 5

Рисунок 4 - Chroot Debian

Рисунок 5 - Chroot Ubuntu

[root@localhost practic]# ./build.sh

Preparing CHROOT directory

CHROOT directory has been prepared

/bin/bash: BASH_FUMC_scl{}: line 0: syntax error near unexpected token ")' /bin/bash: BASH FUHC scl{}: line 0: 'BASHFUHCscl{) (> { local CMD=$1; 1 /bin/bash: error importing function definition for "BASHFUWCscl1 g++ project.cpp -o project

package for Ubuntu-14.04-i336 has been built successfully

Preparing CHROOT directory

CHROOT directory has been prepared

g+4- project.cpp -o project

package for Debian-7.6-i3S6 has been built successfully [ root@localhost practic]#[

Рисунок 6 - Выполнение скрипта build.sh

Файл Правка Вид Поиск Терминал Справка

Левая панель

Настройки Правая панель

*project-Debia[i-7.6-i386 *project-Ubuiitu-14.04-i386

Рисунок 7 - Полученные сборки