netlib.narod.ru | < Назад | Оглавление | Далее > |
Ядро Linux перенесено на множество платформ, и проблемы переносимости решались по мере их возникновения. Большинство кода для поддержки различных платформ завершается множеством препроцессорных заморочек, наподобие показанных ниже:
#if defined(SOLARIS) /* делать что-либо способом, принятым в Solaris ... */ #elif defined(HPUX) /* делать что-либо способом, принятым в HP-UX ... */ #elif defined (LINUX) /* делать что-либо общепринятым и правильным способом ... */ #else #error Неподдерживаемая платформа. #endif
Несмотря на то что пример связан с обеспечением переносимости кода в различных ОС, а задача Linux заключается в обеспечении переносимости кода в различных процессорах, принципы реализации совершенно аналогичны. Задействование препроцессора для такой задачи — ошибочное решение. Весь этот хаос лишь усложняет чтение и понимание кода. Что еще хуже, добавление поддержки новой платформы заставляет возвращаться к каждому блоку этого хлама (попробуйте еще отыскать их все!) и добавлению кусочков кода там и сям.
С другой стороны, Linux обычно абстрагируется от платформ через простые вызовы функций (или макросов). Переносимость ядра достигается за счет реализации функций (или макросов) в соответствии с требованиями той или иной платформы. Подобный подход не только существенно упрощает чтение кода, но также позволяет не забывать учитывать все необходимое при переносе на новую платформу — в противном случае будет генерироваться ошибка, связанная с неразрешимой ссылкой на функцию. В некоторых случаях для поддержки различных архитектур все еще используется препроцессор, однако это скорее исключение из правил.
Нельзя не заметить четко прослеживающуюся аналогию между рассматриваемым решением и методологией использования объектов (или структур, заполненных указателями на функции, в С), которая применяется вместо множества операторов switch, реализующих различные варианты обработки. На определенном уровне проблемы и их решения весьма схожи.
Проблемы переносимости не ограничиваются платформами и центральными процессорами — в действие вступают также и компиляторы. Это еще одно место, позволяющее понять, почему предполагается, что Linux должен компилироваться в gcc. Нет необходимости предусматривать в коде блоки #if (либо #ifdef), обеспечивающие выбор того или иного компилятора, поскольку Linux предполагает существование только одного компилятора в мире. Основное использование #ifdef в коде ядра связано с поддержкой конструкций, которые могут не компилироваться. К таким конструкциям относится, например, код, тестирующий, определен ли макрос SMP, указывающий на необходимость поддержки многопроцессорных SMP-машин.
netlib.narod.ru | < Назад | Оглавление | Далее > |