ОСНОВНЫЕ ПРИНЦИПЫ ПРОЕКТИРОВАНИЯ ПЕРЕНОСИМЫХ
ПРОГРАММНЫХ СИСТЕМ
А. А. Галкин
Санкт-Петербургский
Государственных Электротехнический Университет
Abstract - The report describes last
changes in IT market that show need for cross-platform system in modern corporative
program systems. Here it gives definition to the platform statement,
cross-platform software and cross-platform systems. The generic classification
of cross-platform software is included along with main problems and the ways of
solving them for each category.
Определения. Для начала определим
значение термина "платформо-независимость" и его отношение в
применении к программному обеспечению. Для этого придется рассмотреть несколько
сопутствующих понятий и произвести классификацию переносимого программного
обеспечения.
Платформа – некий набор аппаратных и программных средств, позволяющий использовать программный продукт для решения поставленной перед ним задачи. В роли аппаратных средств выступает физическая вычислительная машина (ее электронная и механическая части), в роли программных средств - установленное на ней программное обеспечение (BIOS, операционная система, драйвера).
Классификация платформо-независимых систем. Выделим две группы свойств, причем каждый физический продукт должен принадлежать обеим группам. В первой группе разделим системы на категории, во второй на классы.
Категории платформо-независимых систем:
Системы, независимые от версии операционной системы на одной архитектурной платформе.
Системы, независимые от архитектурной платформы в рамках одной версии операционной системы.
Системы, независимые от версии операционной системы на разных архитектурных платформах.
Системы, независимые от операционной системы в рамках одной аппаратной архитектуры.
Системы, независимые от операционной системы на любой аппаратной платформе.
Классы
платформо-независимых систем:
Безусловно независимые.
Условно независимые с заменой одного из подмодулей без повторной трансляции всей системы.
Условно независимые с заменой одного из подмодулей с повторной трансляцией всей системы.
Рассмотрим подробнее наиболее сложные и важные случаи.
Системы,
независимые от операционной системы в рамках одной аппаратной архитектуры, и
системы, независимые от операционной системы на любой аппаратной платформе. Вопросы, связанные с различными
аппаратными платформами, аналогичны рассмотренным в [1]. Основные различия в
архитектуре маскируются операционной системой, что не всегда выполнено удачно и
даже не всегда возможно. Также остаются другие проблемы, вроде различной длины
машинного слова, которые необходимо учитывать и обходить при переносе
программного обеспечения.
В части, относящейся
непосредственно к взаимодействию с OС, проблем неизмеримо больше. Задача
переноса программного обеспечения с одной системы на другую, как правило,
сводится к подбору похожих точек взаимодействия с системой, адаптации общих
существующих данных и получению недостающих в новой реализации. Кроме того,
часто для взаимодействия требуется обеспечить соответствующую среду выполнения.
К счастью, существует стандарт, облегчающий эту работу. Большинство операционных систем и систем программирования для них имеют реализацию и поддержку ANSI-вызовов. По стандарту эти вызовы должны идентично работать во всех своих реализациях. Допускаются, однако, их переименования, например: __mkdir(). Такие различия легко обходятся средствами компилятора и языка программирования. Обычно ANSI-вызовы перетранслируются средой выполнения (CRT) в вызовы операционной системы путем добавления необходимой обвязки и преобразования данных к формату, понимаемому API операционной системы.
Но, к сожалению, эти вызовы явно не были достаточно оттестированы и в них периодически проявляются досадные ошибки. Из за этого разработчики ПО зачастую вместо них пользуются непосредственно системным API. К примеру, в Microsoft Windows NT4 + Microsoft Visual Studio 6 не всегда корректно отрабатывают такие функции, как __spawn и __mkdir __chdir. В связи с этим рекомендуется использовать системно зависимые CreateProcess, CreateDirectory и прочие, делая для них свою обвязку. Но это уменьшает эффективность программирования и служит дополнительным источником ошибок [4].
Полностью
независимые.
Идеальный случай – программа может работать на любой платформе в рамках той
категории, к которой она относится. К
сожалению, как и все идеальное, это достижимо только с известными
ограничениями.
1. Программа относится к категории «Системы, независимые от операционной системы в рамках одной аппаратной архитектуры». Это также реальный вариант, но только в том случае, если в конструкцию операционной системы заложена поддержка приложений неродных программных платформ – иными словами, в системе присутствует эмулятор или возможен запуск виртуальной машины. Реализация эмулятора допускает самые различные варианты:
· эмуляция – на уровне ядра, операционной системы или приложения (VPC);
· конвертация – преобразование исполняемого кода в формат другой операционной системы (Odin).
2. Все остальные программы, относящиеся к категориям, включающим в себя независимость от аппаратных платформ, не могут быть реализованы в данном классе. Причина в том, что любой транслятор создает код на уровне процессора и этот фактор не может замаскировать ни одна операционная система. Но имеются два исключения:
· эмуляторы процессоров. Приложение операционной системы, имитирующее определенный аппаратный процессор или целиком архитектуру. Но это, тем не менее, не позволяет использовать данный способ для работы с серьезными программными продуктами. Обычно этим пользуются на стадиях создания и отладки программ для платформ, отличных от той, где происходит разработка. К примеру, создание приложений для платформы Palm или подобных мобильных устройств;
· так называемые интернет-приложения. Под этим термином подразумевается приложение, которое может быть загружено на терминал пользователя, прозрачно для него через сеть и выполняется на ресурсах его машины. Очевидно, что такие приложения должны поддерживать самые различные платформы. Это новый класс приложений, который сейчас бурно развивается. Согласно теории, приложения, написанные для сети, должны быть работоспособны на любой платформе и попадают под категорию «Системы, независимые от операционной системы на любой аппаратной платформе». И к этому есть все предпосылки, но, к сожалению, только в теоретически. Наиболее распространенный тип интернет-приложений – различные виды апплетов (например, java-applet, midlet и пр.) и скриптов (java-script, wml-script и пр.). Они могут работать в паре с серверной частью для распределения ресурсоемких вычислений. Обычно средой выполнения для них является браузер. И он же является проблемой. Каждая фирма-разработчик браузера создает свои стандарты и модифицирует существующие. Поэтому скрипты и апплеты сильно зависят от браузера и от той runtime исполняемого кода, которую он поддерживает.
Условно
независимые с заменой подмодулей без повторной трансляции всей системы. Этот класс практически
аналогичен полностью независимым системам, за исключением того момента, что для
запуска продукта на различных платформах требуется провести замену каких-то
заранее подготовленных частей программы. Обычно такая операция прозрачна для
пользователя и выполняется во время инсталляции или первого запуска продукта.
Следовательно, для конечного пользователя этот класс можно считать полностью
независимым.
Этот класс интересен тем, что обеспечивает работу в рамках разных аппаратных платформ. Для этого основная логика реализуется на платформо-независимом языке, например Java, а все системо-зависимые модули выносятся во внешние сменные модули (для Java это native dll и технология JNI).
Похожий принцип работы также предоставляет и технология COM (и ее новая реинкарнация .NET) от Microsoft, позволяющая создавать модули на наиболее подходящем для текущей платформы языке, но она имеет свою специфику и не всегда применима.
Данный способ имеет и свои недостатки:
1. Увеличение объема дистрибутива продукта пропорционально числу поддерживаемых платформ.
2. Некоторое уменьшение скорости работы продукта. Поскольку в данном случае в сменном модуле окажутся функции нижнего уровня (взаимодействие с OS), то к ним будет проходить наибольшее число обращений
3. Контроль версий. Основной модуль должен знать, какие функции имеются в его распоряжении и способ общения с ними. Даже если система работы с плагинами (или подобными технологиями) поддерживается средствами языка (например, JNI, COM), несоответствие версий может привести к появлению трудно обнаруживаемых ошибок.
Условно независимые с заменой подмодулей с повторной трансляцией всей системы. Данный класс наиболее интересен с точки зрения переносимости на различные платформы. Это единственный класс, позволяющий работать на различных аппаратных платформах, поскольку происходит трансляция всей (необходимой части) системы под конкретную архитектуру. Рассмотрим особенности различных категорий в этом классе:
1. Программа относится к категории «Системы, независимые от архитектурной платформы в рамках одной версии операционной системы». Поскольку в задачу операционной системы входит маскировка аппаратного уровня от приложений, то теоретически для нормальной работы достаточно оттранслировать приложение под новую архитектуру. Но, к сожалению, часто это не так. Обычно в процессе переноса выявляется множество мелких отличий в работе систем на разных аппаратных платформах, от размера машинного слова (как ни странно, но и одна операционная система не маскирует это полностью) до отличий в обращениях к файловой системе. Но, поскольку имеется возможность транслировать продукт уже на целевой платформе, можно все эти отличия выявить при трансляции. В этом большое преимущество перед технологией plugin, в которой код всех вариантов должен присутствовать в программе одновременно, даже если он не используется.
2. Программа относится к категории «Системы, независимые от операционной системы в рамках одной аппаратной архитектуры, и системы, независимые от операционной системы на любой аппаратной платформе». Сразу надо отметить, что далеко не все программное обеспечение можно и целесообразно делать переносимым. К примеру, очень мало поддаются переносу драйверы, которые, конечно, можно перенести, но сделать их так, чтобы для запуска в другой системе было достаточно простой трансляции, практически невозможно. Легче всего переносятся вычислительные задачи, поскольку они, в основном, используют стандартные ANSI-функции, которые обычно реализованы в большинстве систем, хотя и (как уже отмечалось) требуют известной коррекции. Рассмотрим коротко некоторые из них:
· графический пользовательский интерфейс (взаимодействие с оконной системой). Проблемы возникают именно при наличии оконной системы, поскольку необходимо обеспечить корректное взаимодействие с разными диспетчерами для получения необходимых сигналов и вывода данных[2];
· работа с файловой системой. Сложности возникают из-за отличий в организации файловой подсистемы и в работе с файлами. В основном это касается форматов и способов работы с текстовыми и бинарными файлами, признаками конца строки и файла, прав доступа к файлам. Также необходимо отметить, что во многих системах работа с внешними устройствами последовательного доступа организована через виртуальные файлы, а поскольку логика работы устройств может быть несколько отличной в разных системах, то необходимо это учитывать[3];
· работа с системными объектами. В эту область входят такие объекты, как semaphore, mutex, thread, process, pipe и подобные, а именно: их создание, удаление, дублирование, установка и снятие (для флаговых объектов). Основная проблема состоит в том, что поскольку все эти объекты привязаны к ядру системы, то в каждой операционной системе имеется свой набор системных объектов и обычно они различны.
Самый разумный способ сделать переносимое
приложение данного класса и вида – создать две системно зависимые промежуточные
библиотеки нижнего уровня. Первая из них
будет находиться между системными API-функциями и приложением, обеспечивая
системно независимый интерфейс с OС. Вторая библиотека предназначена для
взаимодействия с графической оболочкой (если это требуется). Она должна
реализовывать интерфейс для включения в оконную систему, получения нужных
данных извне, их нормализации и передачи далее в приложение, а также обратный
процесс. Таким образом, можно делать основную программу совершенно независимой
от системы используя собственный API. В то же время, две оставшиеся библиотеки
имеют жесткую специализацию и могут быть переделаны под необходимую
операционную систему за небольшой срок, во много раз меньший того, что потребовался бы для переноса всей системы
целиком.
Литература
1.
Галкин А. А. Основные принципы проектирования переносимых программных
систем //Тез. докл. конф. «Компьютерные технологии, коммуникации, численные
методы и математическое моделирование». СПб., 17 дек. 2002. СПб.:Изд-во СПбГТУ,
2002. С.63-64.
2.
Dalheimer M. K. Programming
with Qt. Koln: O’RellyVerlang GmbH & Co. KG, 1999.
3. Мюррей У., Паппас К. Создание переносимых приложений для Windows. пер. С англ. – СПб.: BHV – Санкт-Петербург, 1997.