Пример “Hello World”

Для добавления обычного примера команды выводящей сообщение “hello world” необходимо создать файл “hello.c” с исходным кодом на языке Си.

#include <stdio.h>

int main(int argc, char **argv) {
    printf("Hello World!\n");
    return 0;
}

И затем добавить описание модуля.

Добавление модуля

Все модули и интерфейсы системы описываются в my-файлах: файлах с расширением .my или имеющих имя Mybuild (без расширения). Структурно каждый my-файл содержит объявление пакета, которому принадлежат все определяемые в файле сущности, (опционально) список импортируемых имен из других пакетов, а также определения самих модулей и интерфейсов. К примеру, для добавления новой команды для встроенного в ядро командного интерпретатора создадим новый файл Hello.my со следующим содержимым:

package embox.cmd.tutorial

@AutoCmd
@Cmd(name="hello", help="Prints ‘Hello World’ string")
module hello {
    source "hello.c"
}

В этом примере описывается простой модуль имеющий всего один атрибут (source) - файл с исходным кодом “hello.c”, которых будет скомпилирован и связан с ядром в случае добавления модуля в сборку. Аннотация @Cmd регистрирует модуль в системе как команду встроенного интерпретатора, позволяя, таким образом, запускать ее по имени “hello”. Необязательный параметр help содержит строку, которая будет выведана при запуске команды “help hello” (если модуль help также включен в сборку). Аннотация @AutoCmd позволяет использовать привычную функцию main() в качестве точки входа в программу.

Атрибуты модуля

Модуль hello достаточно примитивен и не определяет никаких внешних зависимостей или опций. Единственный его атрибут - source - определяет набор исходных файлов для компиляции. Опции Теперь модифицируем пример таким образом, чтобы строка приветствия задавалась в виде опции. Для этого используется атрибут option. Добавим модулю hello (файл Hello.my) строковую опцию greeting:

// ...
module hello {
    // ...
    option string greeting = "World"
}

И модифицируем файл исходного кода hello.c таким образом, чтобы команда после слова “Hello” выводила строку, содержащуюся в значении опции greeting:

#define GREETING OPTION_STRING_GET(greeting)

// ...
    printf("Hello %s!\n", GREETING);
// ...

Включение в сборку

Для того, чтобы новый модуль оказался в результирующем образе ядра, его необходимо добавить в конфигурацию сборки, которая описывается в файле conf/mods.config:

package genconfig

configuration conf {
    // ...
    include embox.cmd.tutorial.hello
}

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

// ...
    include embox.cmd.tutorial.hello(greeting="Everyone")
// ...

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

Как правило, на ранних стадиях (runlevel=0) загружаются драйверы устройств, необходимых для корректного функционирования системы (например, контроллер прерываний), основные компоненты системы, а также исполняются низкоуровневые тесты и процедуры самодиагностики. Следует отметить, что runlevel определяет лишь максимальную стадию, на которой должен быть запущен данный модуль. Таким образом, если какой-либо модуль, загружаемый на нулевой стадии, зависит от модуля, загружаемого позже, последний все-равно будет загружен раньше, т.е. на нулевой стадии.