| | |
|
QNX: QNX NEUTRINO RTOS V 6.2
Содержание
3 Техническая оценка
Для разъяснения содержания следующих разделов, читателю предлагается обратиться к документу “Report definition and test plan”, который может быть загружен c сайта (http://www.dedicated-systems.com/). Этот документ определяет (помимо многого другого) различные модели защиты памяти, объекты и особенности, упомянутые в разделе Богатство API. Также документ содержит детальное разъяснение проведенных тестов.
3.1 Инсталляция и конфигурация
Инсталляция простая и быстрая. Создание и конфигурирование конкретного образа QNX осуществляется посредством IDE или с использованием текстовых build-файлов.
3.1.1 Инсталляция
Операционную систему реального времени QNX NEUTRINO v6.2 легко и быстро инсталлировать. Самый простой путь инсталляции QNX NEUTRINO v6.2 - это использование CD-диска, который вы можете заказать у фирмы-производителя, “QNX Software Systems”. Инсталляция базовых модулей занимает всего несколько минут, это значит, что по завершении этого процесса будут проинсталлированы ядро и пользовательский интерфейс (встраиваемая графическая оболочка Photon microGUI). Дополнительные модули, например, компиляторы, и т.д. могут быть проинсталлированы с использованием менеджера устройств (DEV).
3.1.2 Конфигурация
Конфигурация QNX NEUTRINO RTOS v6.2 достаточно проста. При полной инсталляции системы, такие проблемные компоненты, как жесткие диски или сетевые карты, определяются автоматически. Если требуется дальнейшее конфигурирование, его можно осуществить при использовании графического пользовательского интерфейса.
Построение конкретного QNX образа происходит при использовании build-файлов. Для изменения, добавления и конфигурирования модулей необходимо редактирование соответствующих текстовых build-файлов. В документации к системе содержится большое количество примеров описания build-фалов.
Дополнительно IDE содержит инструмент построения системы, делающий доступным управление QNX-образами. Данный инструмент изменяет build-файлы при помощи графического интерфейса для создания образа (как загрузочного образа, так и флэш – образа) и позволяет импортировать существующие build-файлы. Помимо этого, данный инструмент конфигурирования системы предоставляет анализ зависимостей (например, указывает потерянные библиотеки), подобно тому как “диетолог” создает уменьшенные версии используемых вами разделяемых библиотек, содержащие только используемые вами функции.
Несмотря на то, что запуск Momentics IDE занимает достаточно большое количество времени (несколько минут), инструмент построения системы работает достаточно быстро и довольно-таки прост в использовании. Сначала Вы должны немного поэкспериментировать, для того чтобы понять, где располагаются различные модули (например, обнаруженные устройства, включенные в DLL). Вы можете улучшить результат, добавив колонку комментария в процессе выбора. При включении модуля в построитель системы, данный комментарий отображается в IDE и объясняет использование и опции библиотеки. Построитель системы также автоматически добавляет разделяемые библиотеки, которые необходимы добавленным модулям в вашей целевой конфигурации системы.
Наилучшим образом построитель системы инициализируется существующим (простым) build-файлом, который устанавливает основную конфигурацию.
Функция "диеты" работает очень хорошо и является одной из тех вещей, которых мы не обнаружили ни в одном другом графическом построителе платформы. Конечно, "диетизация" разделенных библиотек - это медленный процесс (проверяющий все зависимости), но это требуется сделать только в конце цикла построения.
Графический инструмент построения системы, с его проверками зависимостей и функцией «диеты», является главным усовершенствованием по сравнению с QNX v6.1.
3.2 Архитектура RTOS
Истинно клиент-серверная архитектура, предоставляющая полную защиту виртуальной памяти. QNX NEUTRINO RTOS v6.2 является операционной системой на базе обмена сообщениями и может быть с легкостью распределена между большим количеством сетевых узлов. RTOS поддерживает SMP и предоставляет множество дополнительных HA (High Availability) возможностей.
3.2.1 Архитектура системы
QNX NEUTRINO RTOS v6.2 имеет клиент - серверную архитектуру, состоящую из микроядра и сгруппированных вокруг него взаимодействующих процессов. Микроядро включает в себя только сервисы ядра, такие как нити, сигналы, передача сообщений, синхронизация, планирование заданий и таймер. Микроядро само по себе не подвергается планировке. Его код выполняется только в результате вызова ядра или возникновения аппаратного прерывания.
Дополнительные функциональные возможности осуществляются взаимодействующими процессами, которые действуют как серверные процессы и отвечают на запросы процессов клиента (например, прикладного процесса). Примеры таких серверных процессов - менеджер файловой системы, менеджер процесса, менеджер устройства, менеджер сети, и т.д. В то время как ядро запускается на 0 уровне привилегий процессора Intel, менеджеры и драйверы устройств запускаются на уровнях 1 и 2 (для исполнения действий ввода/вывода). Прикладные процессы запускаются на 3 уровне привилегий и поэтому могут выполнять только общие команды процессора.
QNX NEUTRINO RTOS v6.2 - операционная система, основанная на передаче сообщений. Обработка передачи сообщений является фундаментальным средством межпроцессорного взаимодействия (IPC) в данной RTOS. Обработка передачи сообщения основана на клиент-серверной модели: клиент (например, прикладной процесс) посылает сообщение серверу (например, менеджеру устройства), который возвращает результат. Многие запросы QNX NEUTRINO RTOS API используют данный механизм передачи сообщений. Например, когда прикладной процесс хочет открыть файл, запрос к системе переводится в сообщение, которое посылается менеджеру файловой системы. Менеджер файловой системы (после доступа к диску через его драйверы устройств) отвечает обработчиком файла. Этот механизм передачи сообщений является прозрачным относительно сети, то есть, система может быть распределена между более чем несколькими сетевыми узлами, без необходимости каких-либо изменений в коде приложения.
При передаче сообщений между клиентом и сервером, QNX NEUTRINO RTOS v6.2 использует так называемый механизм приоритет, управляемый клиентом (“client-driven priority”). Это означает, что серверный процесс наследует уровень приоритета клиентского процесса, требующего обслуживания. Когда обслуживания запроса клиента завершено, серверный процесс может восстановить свой первоначальный уровень приоритета. Если обслуживания требуют несколько клиентов одновременно, серверный процесс принимает уровень приоритета клиентского процесса с наиболее высоким приоритетом. Это помогает избежать инверсии приоритетов.
Архитектура клиент-сервер имеет много преимуществ, одно из которых – устойчивость к ошибкам. Каждый менеджер (за исключением менеджера процессов) и драйвер устройства запускается в его собственном адресном пространстве виртуальной памяти, что приводит к надежности и устойчивости системы. Цена, которую приходится платить, - это производительность: выполнение системных вызовов приводит к небольшому количеству переключений контекстов (с дополнительными расходами на защиту памяти), что приводит к некоторому понижению производительности.
3.2.2 Основные системные ресурсы
3.2.2.1 Методика обработки заданий
QNX NEUTRINO RTOS v6.2 использует процессы и нити. Процесс определяет адресное пространство, в котором будут запущены нити и всегда содержит, по крайней мере, одну нить.
Существует 63 уникальных уровня приоритетов нитей, доступных приложениям. Этого количества достаточно, но иногда желательно иметь 128 уровней приоритетов. Это особенно важно для больших приложений реального времени, разработанных с использованием таких технологий как RMA (Rate Monotonic Analysis), в которых каждая нить должна иметь свой собственный уникальный уровень приоритета.
Планировщик заданий управляет нитями, используя очередь с приоритетами (FIFO), алгоритм round-robin или "sporadic scheduling" – нововведение, реализованное в QNX 6.2. Спорадическое (случайное) распределение является адаптивным: т. е. приоритет нити понижается, если она требует слишком много квантов времени центрального процессора. После некоторого времени существования с низким приоритетом (период пополнения), нить снова приобретает свой прежний уровень приоритета. Все эти параметры (включая границы приоритетов) могут изменяться для каждой нити.
QNX 6.2 | Модель | Процессы и нити | Количество уровней приоритетов | 64 | Максимальное количество заданий | 4095 процессов Каждый процесс может иметь до 32767 нитей | Планировщик заданий | Очередь с приоритетами Алгоритм Round-robin Адаптивный алгоритм[1] Случайный алгоритм[2] | Количество документированных состояний | 14 |
|
3.2.2.2 Методика управления памятью
В QNX NEUTRINO RTOS v6.2 каждому процессу отводится свое собственное пространство виртуальной памяти. Виртуальная память поддерживает страничный механизм распределения. Виртуальная память защищает как пользовательские, так и системные процессы друг от друга, что приводит в высокой устойчивости системы к ошибкам.
Поддерживается подкачка на диск (свопинг), но для этого требуется ее явно задействовать при помощи семейства "отпирающих" вызовов. В QNX Software не рекомендуется использовать эти вызовы, так как они не предназначены для общих целей, а только для совместимости с GNU-компиляторами и связующими трансляторами. Обычно свопинг является нежелательным для встроенных систем, но последнее время становится все более и более необходимым для централизованных систем. Вот почему QNX планирует поддержку явного свопинга в следующих версиях.
Подкачка по обращению - это способность операционной системы загружать исполняемые части в память, когда это необходимо. В QNX NEUTRINO RTOS v6.2 сегмент кода бинарных данных целиком загружается в память при выполнении. Подкачка по обращению пагубно отражается на предсказуемости в режиме реального времени и, таким образом, не включена в QNX RTOS.
QNX 6.2 | Поддержка MMU | Есть | Физический размер страницы | 4K | Свопинг/Подкачка страниц по обращению | Есть/Нет | Виртуальная память | Есть | Модели защиты памяти | Полная защита виртуальной памяти |
|
3.2.2.3 Методика обработки прерываний
Обработчик прерываний в микроядре осуществляет управление прерываниями на их начальной стадии. Нить, имеющая соответствующие привилегии, может динамически устанавливать и удалять обработчики прерываний путем передачи микроядру адреса функции-обработчика (ISR). При возникновении прерывания, обработка передается сначала в микроядро, которое содержит код для его переадресации. Перед вызовом ISR микроядро сохраняет контекст исполняемой нити и переустанавливает регистры процессора таким образом, что ISR имеет доступ к адресному пространству нити, в которой он содержится. Это позволяет ISR выполнить обработку, пользуясь данными и буферами нити, в которой она содержится, или буферизовать принятые данные для последующей обработки этой нитью. Это также дает возможность ISR осуществлять доступ ко всем устройствам, находящимся в домене ответственности (области префиксов) данной нити, и непосредственно выполнять операции ввода-вывода. QNX NEUTRINO RTOS v6.2 поддерживает распределение прерываний. При возникновении прерывания, каждая программа обработки соответствующего прерывания, связанного с аппаратным прерыванием, обрабатывается по очереди. Пользователь не должен брать на себя ответственность за порядок вызова программ обработки прерываний.
Прерывания не блокируются во время выполнения управляющей прерываниями программы, таким образом, прерывания могут быть вложенными. Немаскируемые прерывания могут быть обслужены во время выполнения уже запущенной программы обработки прерывания.
Так как QNX NEUTRINO RTOS v6.2 является клиент-серверной операционной системой, основанной на передаче сообщений, взаимодействие ISR и нити основано на сигналах и пульсах. ISR может посылать пульсы и сигналы нитям и процессам и делать готовой ждущую прерывания нить путем вызова "InterruptWait". ISR также могут передавать данные через определенные приложениями структуры соответствующим процессам. Использование семафоров было преднамеренно блокировано, так как это недостаточно хорошее решение для системы реального времени, с архитектурой основанной на передаче сообщений.
QNX 6.2 | Управление | Вложенное, с приоритетами | Контекст | ISR запускается в контексте соответствующей нити | Стек | ISR имеет свой собственный стек | Взаимодействие заданий и прерываний | Сигналы и пульсы |
|
3.3 Богатство API
QNX NEUTRINO RTOS v6.2 предоставляет как POSIX-совместимость, так и собственные API. API приспособлены для работы с системами, основанными на сообщениях, как и архитектура самой операционной системы.
Таблицы, представленные ниже, описывают основные объекты реального времени и особенности POSIX и QNX интерфейсов. Во время интерпретации данных результатов, читателю необходимо помнить, что представленные таблицы затрагивают только строго определенное множество системных вызовов. QNX NEUTRINO RTOS v6.2 предоставляет другие интерфейсы, которые в данных таблицах не рассматриваются.
3.3.1 Управление заданиями
Управление нитями | Есть | Получить размер стека | + | Установить размер стека | + | Получить адрес стека | + | Установить адрес стека | + | Получить состояние нити | + | Установить состояние нити | + | Получить TCB | + | Установить TCB | - | Получить уровень приоритета | + | Установить уровень приоритета | + | Получить ID нити | + | Управление изменением состояния нити | - | Получить текущее состояние указателя стека | + | Установить использование нитью центрального процессора | + | Установить механизм планировки заданий | + | Запереть нить в памяти | + | Отключить планировщик заданий | - | Итого | 14 | В процентах | 82% |
|
3.3.2 Часы и таймер
Часы | Есть | Получить время | + | Установить время | + | Получить точность | + | Установить точность | + | Выровнять время | + | Прочитать регистр счетчика | + | Автоматическое выравнивание времени | + | Итого | 7 | В процентах | 100% |
|
Интервальный таймер | Есть | Истечение таймера по абсолютной дате | + | Истечение таймера по относительной дате | + | Циклическое истечение таймера | + | Получить оставшееся время | + | Получить число переходов за границу времени | + | Подключить работу пользователя по графику | + | Итого | 6 | В процентах | 100% |
|
3.3.3 Управление памятью
Разбиение с фиксированным размером блоков | Нет | Получить размер разбиения | - | Установить размер разбиения | - | Получить размер блока памяти | - | Установить размер блока памяти | - | Определить размещение разбиения | - | Получить блок памяти – с блокировкой | - | Получить блок памяти – без блокировки | - | Получить блок памяти – с таймаутом | - | Освободить блок памяти | - | Расширить разбиение | - | Получить число свободных блоков памяти | - | Запереть/открыть разбиение в памяти | - | Итого | 0 | В процентах | 0% |
|
Пул с нефиксированным размером блоков | Есть | Получить размер пула | + | Установить размер пула | + | Получить размер блока памяти | - | Создать новый пул | - | Получить блок памяти – с блокировкой | + | Получить блок памяти – без блокировки | - | Получить блок памяти – с таймаутом | - | Освободить блок памяти | + | Расширить пул | - | Расширить блок | + | Получить число свободных байтов | - | Запереть/открыть пул в памяти | + | Запереть/открыть блок в памяти | + | Итого | 7 | В процентах | 54% |
|
3.3.4 Обработка прерываний
Управление прерываниями | Есть | Установить обработчик прерывания | + | Удалить обработчик прерывания | + | Ожидание прерывания – с блокировкой | + | Ожидание прерывания – с таймаутом | + | Вызов прерывания | - | Запустить/остановить аппаратное прерывание | + | Маскировать/демаскировать аппаратное прерывание | + | Разделение прерываний | + | Итого | 7 | В процентах | 88% |
|
3.3.5 Объекты синхронизации и исключения
Помимо указанных ниже механизмов, QNX NEUTRINO RTOS v6.2 предоставляет дополнительные возможности выполнения синхронизации, некоторые из которых являются очень мощными (соединенные нити, блокировка читатель/писатель, sleepons, spinlocks, барьеры и так далее). Также QNX NEUTRINO RTOS v6.2 предоставляет actomic_xxx функции, которые могут быть использованы для осуществления высокоскоростных операций, не требуя при этом традиционных исключающих элементов.
Семафоры – счетчики | Есть | Получить максимальное значение счетчика | - | Установить максимальное значение счетчика | - | Установить начальное значение | + | Разделиться между процессами | + | Ожидать – с блокировкой | + | Ожидать – без блокировки | + | Ожидать – с таймаутом | + | Отметить | + | Отметить – с передачей | - | Получить статус (значение) | + | Итого | 7 | В процентах | 60% |
|
Бинарные семафоры | Нет | Установить начальное значение | - | Разделиться между процессами | - | Ожидать – с блокировкой | - | Ожидать – без блокировки | - | Ожидать – с таймаутом | - | Отметить | - | Получить статус | - | Итого | 0 | В процентах | 0% |
|
Мьютексы | Есть | Установить начальное значение | + | Разделиться между процессами | + | Механизм отмены инверсии приоритетов | + | Рекурсивное получение | + | Безопасность удаления нитей | - | Ожидать – с блокировкой | + | Ожидать – без блокировки | + | Ожидать – с таймаутом | + | Очистить | + | Получить статус | - | Получить ID нити – владельца | - | Получить блок нити – владельца | - | Итого | 8 | В процентах | 67% |
|
Условные переменные | Есть | Ожидать без блокировки | + | Ожидать с таймаутом | + | Ожидать в порядке очереди / с приоритетами | - | Передать | + | Инверсия приоритетов | - | Итого | 3 | В процентах | 60% |
|
Флаги событий | Нет[3] | Установить один единовременно | - | Установить несколько | - | Ожидать для одного | - | Ожидать для нескольких | - | Ожидать с OR условиями | - | Ожидать с AND условиями | - | Ожидать с AND и OR условиями | - | Ожидать с таймаутом | - | Итого | 0 | В процентах | 0% |
|
POSIX сигналы | Есть[4] | Создать обработчик сигнала | + | Удалить обработчик сигнала | + | Маскировать/демаскировать сигнал | + | Определить отправителя | + | Установить ID получателя | + | Установить ID сигнала | + | Получить ID сигнала | + | Нить сигнала | + | Очередь сигналов | + | Итого | 9 | В процентах | 100% |
|
3.3.6 Объекты связи и передачи сообщений
Очереди | Есть | Установить максимальный размер сообщения | + | Получить максимальный размер сообщения | + | Установить размер очереди | + | Получить размер очереди | + | Получить число сообщений в очереди | + | Разделение между процессами | + | Принять – с блокировкой | + | Принять – без блокировки | + | Принять – с таймаутом | + | Отправить – с ACK | + | Отправить – с приоритетом | + | Отправить – с OOB (out of band) | - | Отправить – с таймаутом | + | Отправить – broadcast | - | Timestamp | - | Подтверждение | + | Итого | 13 | В процентах | 81% |
|
Почтовый ящик | Нет | Установить максимальное число сообщений | - | Получить максимальное число сообщений | - | Разделение между процессами | - | Отправить – с ACK | - | Отправить – с таймаутом | - | Отправить – broadcast | - | Принять– с блокировкой | - | Принять – без блокировки | - | Принять – с таймаутом | - | Получить статус | - | Итого | 0 | В процентах | 0% |
|
3.4 Поддержка Интернет
Комплект разработки QNX Momentics содержит следующие продукты и инструменты: - Встроенный веб-сервер. Встроенный веб-сервер поддерживает CGI 1.1, HTTP 1.1, динамический HTML (включая команды Server Side Include). Вы также можете управлять SSI, используя сервер данных. Сервер данных позволяет множеству нитей разделять данные: для этого существует специальный процесс, обновляющий сервер данных в соответствии с состоянием драйверов аппаратных устройств, в то время как встроенный веб-сервер имеет доступ к текущему состоянию данных.
- Небольшой веб-браузер для просмотра информации. Он полностью поддерживает HTML 3.2, фреймовую структуру, технологии javascript, cookies и т.д. Возможна даже реализация аудио/видео потока. Браузеры Mozilla и Opera не так давно также были приспособлены для использование под QNX NEUTRINO RTOS v6.2.
- Источник доступный для построения интернет – приложений для встроенных систем.
- Широкая поддержка сети и протоколов. Для получения более детальной информации читатель может обратиться к сайту DS.
3.5 Инструменты
Существует большое количество доступных в QNX NEUTRINO RTOS v6.2 инструментов. Нововведением для QNX NEUTRINO RTOS v6.2 является QNX Momentics IDE, базирующееся на расширяемом среде Eclipse.
Дополнительно могут быть использованы Metrowerks Codewarrior IDE и пакет разработчика GCC. Данные пакеты разработчиков содержат наиболее часто используемые инструменты.
Новый IDE был сильно расширен по сравнению с предшествующей версией QNX. IDE снабжен хорошими обучающими видео (на CD), позволяющими быстро начать работать с системой. Предоставляемый пользовательский интерфейс интуитивно понятен.
Самым большим недостатком данного IDE является большая ресурсоемкость (потребляемая память и время центрального процессора), таким образом, для старых платформ и оборудования его использование сильно затруднено. Несомненно, что время подключения IDE в таком случае (у нас для Pentium 200 MHz MMX с 128MB RAM это заняло около пяти минут) совершенно неприемлемо. Уже запущенный IDE работает медленно, но все же работает: только позаботьтесь о том, чтобы не закрыть случайно IDE окно... В новых продуктах мы все чаще и чаще замечаем следующую особенность: кажется, будто программисты больше не работают в ограниченной среде разработки и начинают крайне непроизводительно кодировать!
Также мы заметили некоторые проблемы работы компилятора: возникающие при компиляции ошибки не всегда правильно ставятся в соответствие строкам кода в редакторе, на которых они возникли. Однако, переустановка IDE решает данную проблему.
Помимо инструментов, которые будут подробно рассмотрены ниже, доступны также дополнительные возможности: - Пакет разработчика Photon для разработки пользовательских Photon интерфейсов.
- Пакет разработчика TCP/IP для разработки программ соединения вида точка-точка по протоколу TCP/IP.
| Наличие Есть/Нет | Интегрировано в IDE | Отдельный инструмент | Командный инструмент | GUI | Редактор | | | | | | Подцветка | Есть | + | + | | | Встроенная помощь | Есть | + | + | | | Автоматическое форматирование кода | Есть | + | + | | | Компилятор | | | | | | C | Есть | + | + | + | + | C++ | Есть | + | + | + | + | Java | Есть | + | + | + | + | Ada | Нет | - | - | - | - | Assembler | Есть | + | + | + | + | Линкер | | | | | | Инкрементальный | Есть | + | + | + | + | Генерация таблицы символов | Есть | + | + | + | + | Инструменты для разработки | | | | | | Профайлер | Есть | + | + | + | + | Управление проектами | Есть | + | - | - | + | Контроль исходного кода | Есть | + | + | + | + | Проверка изменений | Есть | + | + | + | + | Отладчик | | | | | | Символьный отладчик | Есть | + | + | + | + | Нитезависимая отладка | Есть | + | + | + | + | Смешанные источники и разбор | Есть | + | - | - | + | Инспектирование переменных | Есть | + | + | + | + | Инспектирование структур | Есть | + | + | + | + | Инспектирование памяти | Есть | + | + | + | + | Инспектирование регистров | Есть | + | + | + | + | Инструмент системного анализа | | | | | | Трассировка | Есть | + | + | + | + | Информация о нитях | Есть | + | + | + | + | Информация о прерываниях | Есть | + | + | + | + | Загрузчики | | | | | | TFTP загрузчик | Есть | + | + | + | + | Серийный загрузчик | Есть | + | + | + | + | Загрузка отдельных модулей | Нет | - | - | - | - |
|
3.6 Документация и поддержка
Мы были весьма обрадованы прекрасной технической поддержкой данной версии продукта. Документация в значительной степени улучшена по сравнению с предшествующей версией QNX (6.1).
Безусловно, разработчики QNX Software читали отзыв по QNX 6.1 RTOS. И мы рады были тому факту, что главная критика не осталась незамеченной: недостаточное документирование параметров API. Теперь все параметры подробно описываются в документации. Дальнейшее улучшение может дать добавление ссылок на описание используемых для этих параметров структур.
Как и раньше, документация выполняет важную работу по предоставлению основной информации о системе и ее архитектуре.
QNX Software предоставляет платную расширенную поддержку своим пользователям (Стандартная и Приоритетная поддержка).
3.7 Методология разработки
Предшествующие версии QNX RTOS использовали только подход, при котором и главная и целевая машины совпадали. В QNX Neutrino RTOS v6.2 разработчики могут использовать как self-hosted так и кросс модель разработки.
Как уже описано в разделе 3.2, QNX Neutrino RTOS v6.2 может иметь как конфигурацию, состоящую из одного микроядра, так и включать многочисленные модули, превращаясь тем самым в полноценную многопользовательскую операционную систему обслуживаемую как среда разработки.
Преимуществом self-hosted подхода является возможность пользователя работать на одной машине: приложение может тестироваться на одной машине, на которой и было разработано, отладка может проходить локально, и так далее.
Проблем при взаимодействии главной и целевой машин не возникает. Разработчики, предпочитающие стандартный рабочий стол MS-Windows или Solaris рабочему столу QNX, могут использовать инструменты cross-разработки. В дополнение к QNX Momentics IDE, для MS-Windows может быть использован Metrowerks IDE для компиляции и отладки с Windows host-машины.
Вопрос, какой вид разработки лучше - кросс или self-hosted - является часто обсуждаемым. На самом деле, это зависит от качества инструментов. Если уровень инструментов cross-разработки низкий, следует отдать предпочтение self-hosted разработке. К сожалению, оценка качества инструментов разработки выходит за границы данного отчета. Но, несомненно, то, что операционная система поддерживает оба эти метода, является большим преимуществом.
Далее >>>
|
|
|