KasperskyOS Community Edition 1.2

Содержание

Сборка решения на базе KasperskyOS

Этот раздел содержит следующие сведения:

  • описание процесса сборки решения на базе KasperskyOS;
  • описания скриптов, библиотек и шаблонов сборки, поставляемых в KasperskyOS Community Edition;
  • сведения о том, как использовать динамические библиотеки в решении на базе KasperskyOS.

В этом разделе

Сборка образа решения

Общая схема сборки

Использование CMake из состава KasperskyOS Community Edition

Библиотеки CMake в составе KasperskyOS Community Edition

Сборка без использования CMake

Использование динамических библиотек

В начало
[Topic cmake_build_solution]

Сборка образа решения

Решение на базе KasperskyOS – системное ПО (включая ядро KasperskyOS и модуль безопасности Kaspersky Security Module) и прикладное ПО, интегрированные для работы в составе программно-аппаратного комплекса.

Подробнее см. "Структура и запуск решения на базе KasperskyOS".

Системные и прикладные программы

Программы по назначению делятся на два типа:

  • Системные программы создают инфраструктуру для прикладных программ (например, обеспечивают работу с аппаратурой, поддерживают механизм IPC, реализуют файловые системы и сетевые протоколы). Системные программы поставляются в составе KasperskyOS Community Edition. При необходимости вы можете разрабатывать собственные системные программы.
  • Прикладные программы предназначены для взаимодействия с пользователем решения и выполнения пользовательских задач. Прикладные программы отсутствуют в составе KasperskyOS Community Edition.

Сборка программ в процессе сборки решения

При сборке решения программы делятся на два типа:

  • Системные программы, поставляемые в составе KasperskyOS Community Edition в виде исполняемых файлов;
  • Системные или прикладные программы, требующие компоновки в исполняемый файл.

При этом программы, требующие компоновки, делятся на следующие типы:

  • Системные программы, реализующие IPC-интерфейс, для которого в составе KasperskyOS Community Edition поставляются готовые транспортные библиотеки.
  • Прикладные программы, реализующие собственный IPC-интерфейс. Для их сборки необходимо генерировать транспортные методы и типы с помощью компилятора NK.
  • Клиентские программы, не предоставляющие служб.

Сборка образа решения

В составе KasperskyOS Community Edition поставляются образ ядра KasperskyOS, а также исполняемые файлы некоторых системных программ и программ-драйверов, готовые к использованию в решении.

Специальная программа Einit, предназначенная для запуска всех остальных программ, а также модуль безопасности Kaspersky Security Module собираются под каждое конкретное решение и не поставляются в составе KasperskyOS Community Edition. Вместо этого в тулчейн KasperskyOS Community Edition включены утилиты для их сборки.

Общая пошаговая схема сборки описана в статье "Общая схема сборки". Сборку образа решения можно осуществлять:

В начало
[Topic cmake_solution_image]

Общая схема сборки

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

  1. Подготовить EDL-, CDL- и IDL-описания прикладных программ, а также файл init-описания (по умолчанию init.yaml) и файлы с описанием политики безопасности решения (по умолчанию security.psl).

    При сборке с CMake EDL-описание можно генерировать используя команду generate_edl_file().

  2. Для всех программ, кроме системных программ, поставляемых в составе KasperskyOS Community Edition, сгенерировать файлы *.edl.h.
  3. Для программ, реализующих собственный IPC-интерфейс, сгенерировать код транспортных методов и типов, используемых для формирования, отправки, приема и обработки IPC-сообщений.
  4. Собрать все программы, входящие в решение, при необходимости скомпоновав их с транспортными библиотеками системных или прикладных программ. Для сборки прикладных программ, реализующих собственный IPC-интерфейс, потребуются сгенерированный на шаге 3 код, содержащий транспортные методы и типы.
    • При сборке с CMake для этого используются стандартные команды сборки. Необходимые настройки кросс-компиляции производятся автоматически.
    • При сборке без CMake для этого необходимо вручную использовать кросс-компиляторы, входящие в состав KasperskyOS Community Edition.
  5. Собрать инициализирующую программу Einit.
    • При сборке с CMake программа Einit собирается в процессе сборки образа решения командами build_kos_qemu_image() и build_kos_hw_image().
    • При сборке без CMake для генерации кода программы Einit необходимо использовать утилиту einit. Программу Einit затем необходимо собрать с помощью кросс-компилятора, поставляемого в KasperskyOS Community Edition.
  6. Собрать модуль Kaspersky Security Module.
  7. Создать образ решения.

Пример 1

Для простейшего примера hello, входящего в состав KasperskyOS Community Edition, в котором содержится одна прикладная программа, не предоставляющая служб, схема сборки выглядит следующим образом:

Пример 2

Пример echo, входящий в состав KasperskyOS Community Edition, описывает простейший случай взаимодействия двух программ с помощью механизма IPC. Чтобы организовать такое взаимодействие, потребуется реализовать на сервере интерфейс с методом Ping и "поместить" службу Ping в новый компонент (например, Responder), а экземпляр этого компонента – в EDL-описание программы Server.

В случае наличия в решении программ, использующих механизм IPC, схема сборки выглядит следующим образом:

В начало
[Topic cmake_common_build_scheme]

Использование CMake из состава KasperskyOS Community Edition

Для автоматизации процесса подготовки образа решения нужно настроить систему сборки CMake. За основу можно взять параметры системы сборки, используемые в примерах из состава KasperskyOS Community Edition.

В файлах CMakeLists.txt используется стандартный синтаксис CMake, а также команды и макросы из библиотек, поставляемых в KasperskyOS Community Edition.

Рекомендованная структура директорий проекта

При создании решения на базе KasperskyOS рекомендуется использовать следующую структуру директорий в проекте:

  • В корне проекта создать корневой файл CMakeLists.txt, содержащий общие инструкции сборки для всего решения.
  • Исходный код каждой из разрабатываемых программ следует разместить в отдельной директории, в поддиректории src.
  • Создать файлы CMakeLists.txt для сборки каждой прикладной программы в соответствующих директориях.
  • Для генерации исходного кода программы Einit следует создать отдельную директорию einit, содержащую поддиректорию src, в которую следует поместить шаблоны init.yaml.in и security.psl.in.

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

  • Создать файл CMakeLists.txt для сборки программы Einit в директории einit.
  • Файлы EDL-, CDL- и IDL-описаний следует разместить в директории resources в корне проекта.

Пример структуры директорий проекта

example$ tree . ├── CMakeLists.txt ├── hello │ ├── CMakeLists.txt │ ├── src │ │ ├── hello.c ├── einit │ ├── CMakeLists.txt │ ├── src │ │ ├── init.yaml.in │ │ ├── security.psl.in ├── resources │ ├── Hello.idl │ ├── Hello.cdl │ ├── Hello.edl

Сборка образа решения

Чтобы выполнить сборку образа решения, нужно использовать утилиту cmake (исполняемый файл toolchain/bin/cmake из состава KasperskyOS Community Edition).

Пример скрипта сборки:

build.sh

#!/bin/bash # Скрипт для запуска в корне проекта. # Сведения о параметрах запуска утилиты cmake можно # получить shell-командой cmake --help, а также из # официальной документации по CMake. TARGET="aarch64-kos" SDK_PREFIX="/opt/KasperskyOS-SDK" # Инициализация системы сборки cmake \ -G "Unix Makefiles" \ -D CMAKE_BUILD_TYPE:STRING=Release \ -D CMAKE_TOOLCHAIN_FILE=$SDK_PREFIX/toolchain/share/toolchain-$TARGET.cmake \ -S . \ -B build # Сборка # Чтобы собрать образ решения для QEMU, нужно указать цель, заданную в # параметре NAME CMake-команды build_kos_qemu_image() в файле CMakeLists.txt # для сборки программы Einit. # Чтобы собрать образ решения для аппаратной платформы, нужно указать цель, # заданную в параметре NAME CMake-команды build_kos_hw_image() в файле # CMakeLists.txt для сборки программы Einit. # Чтобы собрать образ решения для QEMU и запустить QEMU с этим образом, нужно # указать цель sim. cmake --build build --target sim

В этом разделе

Корневой файл CMakeLists.txt

Файлы CMakeLists.txt для сборки прикладных программ

Файл CMakeLists.txt для сборки программы Einit

Шаблон init.yaml.in

Шаблон security.psl.in

В начало
[Topic cmake_using_sdk_cmake]

Корневой файл CMakeLists.txt

Корневой файл CMakeLists.txt содержит общие инструкции сборки для всего решения.

Корневой файл CMakeLists.txt должен содержать следующие команды:

  • cmake_minimum_required (VERSION 3.25) – указание минимальной поддерживаемой версии CMake.

    Для сборки решения на базе KasperskyOS требуется CMake версии не ниже 3.25.

    Требуемая версия CMake поставляется в составе KasperskyOS Community Edition и используется по умолчанию.

  • include (platform) – подключение CMake-библиотеки platform.
  • initialize_platform() – инициализация библиотеки platform.
  • project_header_default("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO") – установка флагов компилятора и компоновщика.
  • [Опционально] Подключение и настройка пакетов для поставляемых системных программ и драйверов, которые необходимо включить в решение:
    • Подключение пакета выполняется с помощью команды find_package().
    • После подключения пакета необходимо добавить директории, связанные с этим пакетом, в список директорий поиска с помощью команды include_directories().
    • Для некоторых пакетов также требуется установить значения свойств с помощью команды set_target_properties().

    CMake-описания системных программ и драйверов, поставляемых в составе KasperskyOS Community Edition, а также их экспортируемых переменных и свойств находятся в соответствующих файлах /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/lib/cmake/<имя программы>/<имя программы>-config.cmake

  • Сборка инициализирующей программы Einit должна быть выполнена с помощью команды add_subdirectory(einit).
  • Все прикладные программы, сборку которых необходимо выполнить, должны быть добавлены с помощью команды add_subdirectory(<имя директории программы>).

Пример корневого файла CMakeLists.txt

CMakeLists.txt

cmake_minimum_required(VERSION 3.12) project (example) # Инициализация библиотеки CMake для KasperskyOS SDK. include (platform) initialize_platform () project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO") # Подключение пакета, импортирующего компоненты для работы с виртуальной файловой системой. # Компоненты импортируются из папки: /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/lib/cmake/vfs/vfs-config.cmake find_package (vfs REQUIRED COMPONENTS ENTITY CLIENT_LIB) include_directories (${vfs_INCLUDE}) # Подключение пакета, импортирующего компоненты для сборки программы аудита и # подключения к ней. find_package (klog REQUIRED) include_directories (${klog_INCLUDE}) # Сборка инициализирующей программы Einit add_subdirectory (einit) # Сборка прикладной программы hello add_subdirectory (hello)
В начало
[Topic cmake_lists_root]

Файлы CMakeLists.txt для сборки прикладных программ

Файл CMakeLists.txt для сборки прикладной программы должен содержать следующие команды:

  • include (platform/nk) – подключение библиотеки CMake для работы с компилятором NK.
  • project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO") – установка флагов компилятора и компоновщика.
  • EDL-описание класса процессов для программы можно сгенерировать, используя команду generate_edl_file().
  • Если программа предоставляет службы, используя механизм IPC, необходимо сгенерировать транспортный код:
    1. idl.h-файлы генерируются командой nk_build_idl_files()
    2. cdl.h-файлы генерируются командой nk_build_cdl_files()
    3. edl.h-файлы генерируются командой nk_build_edl_files()
  • add_executable (<имя программы> "<путь к файлу исходного кода программы>") – добавление цели для сборки программы.
  • add_dependencies (<имя программы> <имя цели сборки edl.h файла>) – добавление зависимости сборки программы от генерации edl.h-файла.
  • target_link_libraries (<имя программы> <список библиотек>) – определяет библиотеки, с которыми необходимо скомпоновать программу при сборке.

    Например, если программа использует файловый или сетевой ввод/вывод, то она должна быть скомпонована с транспортной библиотекой ${vfs_CLIENT_LIB}.

    CMake-описания системных программ и драйверов, поставляемых в составе KasperskyOS Community Edition, а также их экспортированных переменных и свойств находятся в соответствующих файлах /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/lib/cmake/<имя программы>/<имя программы>-config.cmake

  • Для автоматического добавления описаний IPC-каналов в файл init.yaml при сборке решения необходимо определить свойство EXTRA_CONNECTIONS и присвоить ему значение с описаниями нужных IPC-каналов.

    Обратите внимание на отступы в начале строк в свойстве EXTRA_CONNECTIONS. Эти отступы необходимы для корректной подстановки значений в файл init.yaml и должны соответствовать требованиям к его синтаксису.

    Пример создания IPC-канала между процессами Client и Server:

    set_target_properties (Client PROPERTIES EXTRA_CONNECTIONS " - target: Server id: server_connection")

    В результате, при сборке решения, описание этого IPC-канала будет автоматически добавлено в файл init.yaml на этапе обработки макросов шаблона init.yaml.in.

  • Для автоматического добавления списка аргументов функции main() и словаря переменных окружения в файл init.yaml при сборке решения, необходимо определить свойства EXTRA_ARGS и EXTRA_ENV и присвоить им соответствующие значения.

    Обратите внимание на отступы в начале строк в свойствах EXTRA_ARGS и EXTRA_ENV. Эти отступы необходимы для корректной подстановки значений в файл init.yaml и должны соответствовать требованиям к его синтаксису.

    Пример передачи программе Client аргумента "-v" функции main() и переменной окружения VAR1 со значением VALUE1:

    set_target_properties (Client PROPERTIES EXTRA_ARGS " - \"-v\"" EXTRA_ENV " VAR1: VALUE1")

    В результате, при сборке решения, описание аргумента функции main()и значение переменной окружения будут автоматически добавлены в файл init.yaml на этапе обработки макросов шаблона init.yaml.in.

Пример файла CMakeLists.txt для сборки простой прикладной программы

CMakeLists.txt

project (hello) # Инструментарий для работы с компилятором NK. include (platform/nk) # Установка флагов компиляции. project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO") # Задаем имя проекта, в который входит программа. set (LOCAL_MODULE_NAME "example") # Задаем имя программы. set (ENTITY_NAME "Hello") # Обратите внимание на содержание шаблонов init.yaml.in и security.psl.in # В них имена программ задаются как ${LOCAL_MODULE_NAME}.${ENTITY_NAME} # Задаем цели, которые будут использованы для создания генерируемых файлов программы. set (ENTITY_IDL_TARGET ${ENTITY_NAME}_idl) set (ENTITY_CDL_TARGET ${ENTITY_NAME}_cdl) set (ENTITY_EDL_TARGET ${ENTITY_NAME}_edl) # Задаем имя цели, которая будет использована для построения программы. set (APP_TARGET ${ENTITY_NAME}_app) # Добавляем цель сборки idl.h-файла. nk_build_idl_files (${ENTITY_IDL_TARGET} NK_MODULE ${LOCAL_MODULE_NAME} IDL "resources/Hello.idl" ) # Добавляем цель сборки cdl.h-файла. nk_build_cdl_files (${ENTITY_CDL_TARGET} IDL_TARGET ${ENTITY_IDL_TARGET} NK_MODULE ${LOCAL_MODULE_NAME} CDL "resources/Hello.cdl") # Добавляем цель сборки EDL-файла. Переменная EDL_FILE экспортируется # и содержит путь до сгенерированного EDL-файла. generate_edl_file ( ${ENTITY_NAME} PREFIX ${LOCAL_MODULE_NAME} ) # Добавляем цель сборки edl.h-файла. nk_build_edl_files (${ENTITY_EDL_TARGET} NK_MODULE ${LOCAL_MODULE_NAME} EDL ${EDL_FILE} ) # Определяем цель для сборки программы. add_executable (${APP_TARGET} "src/hello.c") # Имя программы в init.yaml и security.psl и имя исполняемого файла должны совпадать set_target_properties (${APP_TARGET} PROPERTIES OUTPUT_NAME ${ENTITY_NAME}) # Библиотеки, с которыми программа компонуется при сборке target_link_libraries ( ${APP_TARGET} PUBLIC ${vfs_CLIENT_LIB} # Программа использует файловый ввод/вывод # и должна быть подключена как клиент к VFS )
В начало
[Topic cmake_lists_applied]

Файл CMakeLists.txt для сборки программы Einit

Файл CMakeLists.txt для сборки инициализирующей программы Einit должен содержать следующие команды:

  • include (platform/image) – подключение библиотеки CMake, содержащей скрипты сборки образа решения.
  • project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO") – установка флагов компилятора и компоновщика.
  • Настройка пакетов системных программ и драйверов, которые необходимо включить в решение.
    • Подключение пакета выполняется с помощью команды find_package ().
    • Для некоторых пакетов также требуется установить значения свойств с помощью команды set_target_properties ().

    CMake-описания системных программ и драйверов, поставляемых в составе KasperskyOS Community Edition, а также их экспортированных переменных и свойств находятся в соответствующих файлах /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/lib/cmake/<имя программы>/<имя программы>-config.cmake

  • Для автоматического добавления описаний IPC-каналов между процессами системных программ в файл init.yaml при сборке решения необходимо добавить эти каналы в свойство EXTRA_CONNECTIONS для соответствующих программ.

    Обратите внимание на отступы в начале строк в свойстве EXTRA_CONNECTIONS. Эти отступы необходимы для корректной подстановки значений в файл init.yaml и должны соответствовать требованиям к его синтаксису.

    Например, программа VFS по умолчанию не имеет канала для соединения с программой Env. Чтобы описание такого канала автоматически добавилось в файл init.yaml при сборке решения, необходимо добавить следующий вызов в файл CMakeLists.txt для сборки программы Einit:

    set_target_properties (${vfs_ENTITY} PROPERTIES EXTRA_CONNECTIONS " - target: env.Env id: {var: ENV_SERVICE_NAME, include: env/env.h}"

    В результате, при сборке решения, описание этого IPC-канала будет автоматически добавлено в файл init.yaml на этапе обработки макросов шаблона init.yaml.in.

  • Для автоматического добавления списка аргументов функции main() и словаря переменных окружения в файл init.yaml при сборке решения, необходимо определить свойства EXTRA_ARGS и EXTRA_ENV и присвоить им соответствующие значения.

    Обратите внимание на отступы в начале строк в свойствах EXTRA_ARGS и EXTRA_ENV. Эти отступы необходимы для корректной подстановки значений в файл init.yaml и должны соответствовать требованиям к его синтаксису.

Пример передачи программе VfsEntity аргумента "-f fstab" функции main() и переменной окружения ROOTFS со значением ramdisk0,0 / ext2 0:

set_target_properties (${vfs_ENTITY} PROPERTIES EXTRA_ARGS " - \"-f\" - \"fstab\"" EXTRA_ENV " ROOTFS: ramdisk0,0 / ext2 0")

В результате, при сборке решения, описание аргумента функции main() и значение переменной окружения будут автоматически добавлены в файл init.yaml на этапе обработки макросов шаблона init.yaml.in.

  • set(ENTITIES <полный список программ, входящих в решение>) – определение переменной ENTITIES со списком исполняемых файлов всех программ, входящих в решение.
  • Одна или обе команды для сборки образа решения:
    • build_kos_hw_image() – создает цель сборки образа решения для аппаратной платформы.
    • build_kos_qemu_image() – создает цель сборки образа решения для QEMU.

Пример файла CMakeLists.txt для сборки программы Einit

CMakeLitsts.txt

project (einit) # Подключение библиотеки, содержащей скрипты сборки образа решения. include (platform/image) # Установка флагов компиляции. project_header_default ("STANDARD_GNU_11:YES" "STRICT_WARNINGS:NO") # Настройка программы VFS. # По умолчанию программе VFS не сопоставляется программа, реализующая блочное устройство. # Если необходимо использовать блочное устройство, например ata из компонента ata, # необходимо задать это устройство в переменной ${blkdev_ENTITY}_REPLACEMENT # Больше информации об экспортированных переменных и свойств программы VFS # см. в /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/lib/cmake/vfs/vfs-config.cmake # find_package(ata) # set_target_properties (${vfs_ENTITY} PROPERTIES ${blkdev_ENTITY}_REPLACEMENT ${ata_ENTITY}) # В простейшем случае не нужно взаимодействовать с диском, # поэтому мы устанавливаем значение переменной ${blkdev_ENTITY}_REPLACEMENT равным пустой строке set_target_properties (${vfs_ENTITY} PROPERTIES ${blkdev_ENTITY}_REPLACEMENT "") # Определение переменной ENTITIES со списком исполняемых файлов программ # Важно включить все программы, входящие в проект, кроме программы Einit. # Обратите внимание на то, что имя исполняемого файла программы должно # совпадать с названием цели, указанной в add_executable() в CMakeLists.txt для сборки этой программы. set(ENTITIES ${vfs_ENTITY} Hello_app ) # Создание цели сборки с именем kos-image, которая является образом решения для аппаратной платформы. build_kos_hw_image (kos-image EINIT_ENTITY EinitHw CONNECTIONS_CFG "src/init.yaml.in" # шаблон файла init.yaml SECURITY_PSL "src/security.psl.in" # шаблон файла security.psl IMAGE_FILES ${ENTITIES} ) # Создание цели сборки с именем kos-qemu-image, которая является образом решения для QEMU. build_kos_qemu_image (kos-qemu-image EINIT_ENTITY EinitQemu CONNECTIONS_CFG "src/init.yaml.in" SECURITY_PSL "src/security.psl.in" IMAGE_FILES ${ENTITIES} )
В начало
[Topic cmake_lists_einit]

Шаблон init.yaml.in

Шаблон init.yaml.in используется для автоматической генерации части файла init.yaml перед сборкой программы Einit средствами CMake.

Использование шаблона init.yaml.in позволяет не добавлять описания системных программ и IPC-каналов для соединения с ними в файл init.yaml вручную.

Шаблон init.yaml.in должен содержать следующие данные:

  • Корневой ключ entities.
  • Список всех прикладных программ, входящих в решение.
  • Для прикладных программ, использующих механизм IPC, необходимо указать список IPC-каналов, соединяющих эту программу с другими программами.

    IPC-каналы, соединяющие эту программу с другими прикладными программами указываются вручную или в файле CMakeLists.txt этой программы с помощью свойства EXTRA_CONNECTIONS.

    Для указания списка IPC-каналов, соединяющих эту программу с системными программами, входящими в состав KasperskyOS Community Edition, используются следующие макросы:

    • @INIT_<имя программы>_ENTITY_CONNECTIONS@ – при сборке заменяется на список IPC-каналов со всеми системными программами, с которыми скомпонована прикладная программа. Поля target и id заполняются в соответствии с файлами connect.yaml из состава KasperskyOS Community Edition, расположенными в /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/include/<имя системной программы>).

      Этот макрос нужно использовать, если прикладная программа не имеет соединений с другими прикладными программами и соединяется только с системными программами. Этот макрос добавляет корневой ключ connections.

    • @INIT_<имя программы>_ENTITY_CONNECTIONS+@ – при сборке добавляет список IPC-каналов со всеми системными программами, с которыми скомпонована прикладная программа, к списку IPC-каналов, заданному вручную. Этот макрос не добавляет корневой ключ connections.

      Этот макрос нужно использовать, если прикладная программа имеет соединения с другими прикладными программами, которые были указаны в шаблоне init.yaml.in вручную.

  • Макросы @INIT_<имя программы>_ENTITY_CONNECTIONS@ и @INIT_<имя программы>_ENTITY_CONNECTIONS+@ также добавляют список соединений для каждой программы, заданный в свойстве EXTRA_CONNECTIONS при сборке этой программы.
  • Если необходимо передать программе аргументы функции main(), заданные в свойстве EXTRA_ARGS при сборке этой программы, то необходимо использовать следующие макросы:
    • @INIT_<имя программы>_ENTITY_ARGS@ – при сборке заменяется на список аргументов функции main(), заданный в свойстве EXTRA_ARGS. Этот макрос добавляет корневой ключ args.
    • @INIT_<имя программы>_ENTITY_ARGS+@ – при сборке добавляет список аргументов функции main(), заданный в свойстве EXTRA_ARGS, к списку аргументов заданному вручную. Этот макрос не добавляет корневой ключ args.
  • Если необходимо передать программе значения переменных окружения, заданные в свойстве EXTRA_ENV при сборке этой программы, то необходимо использовать следующие макросы:
    • @INIT_<имя программы>_ENTITY_ENV@ – при сборке заменяется на словарь переменных окружения и их значений, заданный в свойстве EXTRA_ENV. Этот макрос добавляет корневой ключ env.
    • @INIT_<имя программы>_ENTITY_ENV+@ – при сборке добавляет словарь переменных окружения и их значений, заданный в свойстве EXTRA_ENV, к переменным заданным вручную. Этот макрос не добавляет корневой ключ env.
  • Макрос @INIT_EXTERNAL_ENTITIES@, который при сборке заменяется на список системных программ, с которыми скомпонована прикладная программа, и их IPC-каналов, аргументов функции main() и значений переменных окружения.

Пример шаблона init.yaml.in

init.yaml.in

entities: - name: ping.Client connections: # Программа "Client" может обращаться к "Server". - target: ping.Server id: server_connection @INIT_Client_ENTITY_CONNECTIONS+@ @INIT_Client_ENTITY_ARGS@ @INIT_Client_ENTITY_ENV@ - name: ping.Server @INIT_Server_ENTITY_CONNECTIONS@ @INIT_EXTERNAL_ENTITIES@

При сборке программы Einit из этого шаблона будет сгенерирован следующий файл init.yaml:

init.yaml

entities: - name: ping.Client connections: # Программа "Client" может обращаться к "Server" - target: ping.Server id: server_connection - target: kl.VfsEntity id: {var: _VFS_CONNECTION_ID, include: vfs/defs.h} args: - "-v" env: VAR1: VALUE1 - name: ping.Server connections: - target: kl.VfsEntity id: {var: _VFS_CONNECTION_ID, include: vfs/defs.h} - name: kl.VfsEntity path: VFS args: - "-f" - "fstab" env: ROOTFS: ramdisk0,0 / ext2
В начало
[Topic cmake_yaml_templates]

Шаблон security.psl.in

Шаблон security.psl.in используется для автоматической генерации части файла security.psl перед сборкой программы Einit средствами CMake.

Файл security.psl содержит часть описания политики безопасности решения.

Использование шаблона security.psl.in позволяет не добавлять EDL-описания системных программ в файл security.psl вручную.

Шаблон security.psl.in должен содержать описание политики безопасности решения, созданное вручную, включая следующие декларации:

  • установка глобальных параметров политики безопасности решения;
  • включение PSL-файлов в описание политики безопасности решения;
  • включение EDL-файлов прикладных программ в описание политики безопасности решения;
  • создание объектов моделей безопасности;
  • привязка методов моделей безопасности к событиям безопасности;
  • создание профилей аудита безопасности.

Для автоматического включения системных программ, необходимо использовать макрос @INIT_EXTERNAL_ENTITIES@.

Пример шаблона security.psl.in

security.psl.in

execute: kl.core.Execute use nk.base._ use EDL Einit use EDL kl.core.Core use EDL Client use EDL Server @INIT_EXTERNAL_ENTITIES@ /* Запуск программ разрешен */ execute { grant () } /* Отправка и получение запросов, ответов и ошибок разрешены. */ request { grant () } response { grant () } error { grant () } /* Обращения по интерфейсу безопасности игнорируются. */ security { grant () }
В начало
[Topic cmake_psl_templates]

Библиотеки CMake в составе KasperskyOS Community Edition

Этот раздел содержит описание библиотек, поставляемых в KasperskyOS Community Edition и предназначенных для автоматизации сборки решения на базе KasperskyOS.

В этом разделе

Библиотека platform

Библиотека nk

Библиотека image

В начало
[Topic cmake_libs]

Библиотека platform

Библиотека platform содержит следующие команды:

  • initialize_platform() – команда для инициализации библиотеки platform.

    Команда initialize_platform() может вызываться с параметром FORCE_STATIC, который включает принудительную статическую компоновку исполняемых файлов:

    • По умолчанию, если тулчейн в составе KasperskyOS SDK поддерживает динамическую компоновку, то команда initialize_platform() делает так, что для сборки всех исполняемых файлов, заданных через CMake-команды add_executable(), флаг -rdynamic используется автоматически.
    • При вызове initialize_platform (FORCE_STATIC) в корневом файле CMakeLists.txt тулчейн, поддерживающий динамическую компоновку, выполняет статическую компоновку исполняемых файлов.

    Команда initialize_platform() может вызываться с параметром NO_NEW_VERSION_CHECK, который отключает проверку наличия обновлений SDK и передачу версии SDK на сервер "Лаборатории Касперского".

    Чтобы отключить проверку наличия обновлений SDK и передачу данных версии SDK на сервер Kaspersky при сборке решения используйте следующий вызов: initialize_platform(NO_NEW_VERSION_CHECK). Подробнее о политике предоставления данных см. "Предоставление данных".

  • project_static_executable_header_default() – команда для включения принудительной статической компоновки исполняемых файлов, заданных через последующие CMake-команды add_executable() в одном файле CMakeLists.txt. Тулчейн, поддерживающий динамическую компоновку, выполняет статическую компоновку этих исполняемых файлов.
  • platform_target_force_static() – команда для включения принудительной статической компоновки исполняемого файла, заданного через CMake-команду add_executable(). Тулчейн, поддерживающий динамическую компоновку, выполняет статическую компоновку этого исполняемого файла. Например, если вызываются CMake-команды add_executable(client "src/client.c") и platform_target_force_static(client), то для программы client выполняется статическая компоновка.
  • project_header_default() – команда для указания флагов компиляции.

    Параметры команды задаются в виде пар, состоящих из флага компиляции и его значения: "FLAG_1:VALUE_1" "FLAG_2:VALUE_2" ... "FLAG_N:VALUE_N". CMake-библиотека platform преобразует эти пары в параметры компилятора. Часто используемые флаги компиляции для компиляторов С и С++ из набора GCC, а также значения этих флагов приведены в таблице ниже.

    Флаг компиляции

    Значение YES

    Значение NO

    Значение по умолчанию

    STANDARD_ANSI

    Используются стандарты ISO C90 и 1998 ISO C++.

    Для компиляторов C и C++ значение преобразуется в параметр: -ansi.

    Стандарты ISO C90 и 1998 ISO C++ не используются.

    STANDARD_ANSI:NO

    STANDARD_C99

    Используется стандарт ISO C99.

    Для компилятора C значение преобразуется в параметр: -std=c99.

    Стандарт ISO C99 не используется.

    STANDARD_C99:NO

    STANDARD_GNU_C99

    Используется стандарт ISO C99 с расширениями GNU.

    Для компилятора C значение преобразуется в параметр: -std=gnu99.

    Стандарт ISO C99 с расширениями GNU не используется.

    STANDARD_GNU_C99:NO

    STANDARD_11

    Используются стандарты ISO C11 и 2011 ISO C++.

    Для C-компилятора значение преобразуется в параметр -std=c11 или -std=c1x в зависимости от версии компилятора.

    Для компилятора C++ значение преобразуется в параметр -std=c++11 или -std=c++0x в зависимости от версии компилятора.

    Стандарты ISO C11 и 2011 ISO C++ не используются.

    STANDARD_11:NO

    STANDARD_GNU_11

    Используются стандарты ISO C11 и 2011 ISO C++ с расширениями GNU.

    Для C-компилятора значение преобразуется в параметр -std=gnu1x или -std=gnu11 в зависимости от версии компилятора.

    Для компилятора C++ значение преобразуется в параметр -std=gnu++0x или -std=gnu++11 в зависимости от версии компилятора.

    Стандарты ISO C11 и 2011 ISO C++ с расширениями GNU не используются.

    STANDARD_GNU_11:NO

    STANDARD_14

    Используется стандарт 2014 ISO C++.

    Для компилятора C++ значение преобразуется в параметр -std=c++14.

    Стандарт 2014 ISO C++ не используется.

    STANDARD_14:NO

    STANDARD_GNU_14

    Используется стандарт 2014 ISO C++ с расширениями GNU.

    Для компилятора C++ значение преобразуется в параметр -std=gnu++14.

    Стандарт 2014 ISO C++ с расширениями GNU не используется.

    STANDARD_GNU_14:NO

    STANDARD_17

    Используются стандарты ISO C17 и 2017 ISO C++.

    Для C-компилятора значение преобразуется в параметр -std=c17.

    Для компилятора C++ значение преобразуется в параметр -std=c++17.

    Стандарты ISO C17 и 2017 ISO C++ не используются.

    STANDARD_17:NO

    STANDARD_GNU_17

    Используются стандарты ISO C17 и 2017 ISO C++ с расширениями GNU.

    Для C-компилятора значение преобразуется в параметр -std=gnu17.

    Для компилятора C++ значение преобразуется в параметр -std=gnu++17.

    Стандарты ISO C17 и 2017 ISO C++ с расширениями GNU не используются.

    STANDARD_GNU_17:NO

    STRICT_WARNINGS

    Включены предупреждения для обнаружения потенциальных проблем и ошибок в коде на языках C и C++.

    Для компиляторов C и C++ значение преобразуется в следующие параметры: -Wcast-qual, -Wcast-align, -Wundef.

    Для компилятора C дополнительно используется параметр -Wmissing-prototypes.

    Предупреждения отключены.

    STRICT_WARNINGS:YES

    Если через параметры команды не заданы флаги компиляции вида STANDART_*, то по умолчанию используется параметр STANDARD_GNU_17:YES.

При использовании команд initialize_platform(FORCE_STATIC), project_static_executable_header_default() и platform_target_force_static() могут возникать ошибки компоновки, если статический вариант требуемых библиотек отсутствует (например, не собран или не поставлен в составе KasperskyOS SDK). Но даже при наличии статического варианта требуемых библиотек эти ошибки могут возникать из-за того, что при использовании команд initialize_platform(FORCE_STATIC), project_static_executable_header_default() и platform_target_force_static() система сборки по умолчанию может выполнять поиск динамического варианта требуемых библиотек, а не статического, как ожидается. Чтобы избежать ошибок, нужно, во-первых, обеспечить наличие статического варианта требуемых библиотек, во-вторых, настроить систему сборки на поиск статических библиотек (для некоторых библиотек этой возможности может не быть) либо явно задавать компоновку со статическими библиотеками.

Примеры настройки системы сборки на поиск статических библиотек:

set (fmt_USE_STATIC ON) find_package (fmt REQUIRED) set (fdn_USE_STATIC ON) find_package (fdn REQUIRED) set (sqlite_wrapper_USE_STATIC ON) find_package (sqlite_wrapper REQUIRED)

Пример, в котором явно задана компоновка со статической библиотекой:

target_link_libraries(${PROJECT_NAME} PUBLIC logger::logger-static)

Подробнее об использовании динамических библиотек см. "Использование динамических библиотек".

Эти команды используются в файлах CmakeLists.txt для программы Einit и прикладных программ.

В начало
[Topic cmake_platform_lib]

Библиотека nk

Этот раздел содержит описание команд и макросов библиотеки CMake-библиотеки для работы с компилятором NK.

В этом разделе

generate_edl_file()

nk_build_idl_files()

nk_build_cdl_files()

nk_build_edl_files()

Генерация транспортного кода для разработки на языке C++

В начало
[Topic cmake_nk_lib]

generate_edl_file()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>toolchain/share/cmake/Modules/platform/nk2.cmake.

generate_edl_file(NAME ...)

Команда генерирует EDL-файл с описанием класса процессов.

Параметры:

  • NAME – имя создаваемого EDL-файла. Обязательный параметр.
  • PREFIX – в этом параметре необходимо указать имя класса процессов, исключив из него имя EDL-файла. Например, если имя класса процессов, для которого создается EDL-файл, определено как kl.core.NameServer, то в параметре PREFIX необходимо передать значение kl.core.
  • EDL_COMPONENTS – имя компонента и его экземпляра, которые будут включены в EDL-файл. Например: EDL_COMPONENTS "env: kl.Env". Для включения нескольких компонентов нужно использовать несколько параметров EDL_COMPONENTS.
  • SECURITY – квалифицированное имя метода интерфейса безопасности, который будет включен в EDL-файл.
  • OUTPUT_DIR – директория, где будет создан EDL-файл. По умолчанию ${CMAKE_CURRENT_BINARY_DIR}.

В результате работы команды переменная EDL_FILE экспортируется и содержит путь до сгенерированного EDL-файла.

Пример вызова:

generate_edl_file(${ENTITY_NAME} EDL_COMPONENTS "env: kl.Env")

Пример использования команды см. в статье "Файлы CMakeLists.txt для сборки прикладных программ".

В начало
[Topic cmake_generate_edl]

nk_build_idl_files()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>toolchain/share/cmake/Modules/platform/nk2.cmake.

nk_build_idl_files(NAME ...)

Команда создает CMake-цель для генерации .idl.h-файлов для одного или нескольких заданных IDL-файлов при помощи компилятора NK.

Параметры:

  • NAME – имя CMake-цели для сборки .idl.h-файлов. Если цель еще не создана, то она будет создана с помощью add_library() с указанным именем. Обязательный параметр.
  • NOINSTALL – если указана эта опция, то файлы будут только сгенерированы в рабочей директории, но не будут установлены в глобальные директории: ${CMAKE_BINARY_DIR}/_headers_ ${CMAKE_BINARY_DIR}/_headers_/${PROJECT_NAME}.
  • NK_MODULE – в этом параметре необходимо указать имя пакета, исключив из него имя IDL-файла. Например, если в IDL-описании имя пакета задано как kl.core.NameServer, то в параметре NK_MODULE необходимо передать значение kl.core.
  • WORKING_DIRECTORY – рабочая директория для вызова компилятора NK, по умолчанию: ${CMAKE_CURRENT_BINARY_DIR}.
  • DEPENDS – дополнительные цели сборки, от которых зависит IDL-файл.

    Для добавления нескольких целей нужно использовать несколько параметров DEPENDS.

  • IDL – путь к IDL-файлу, для которого генерируется idl.h-файл. Обязательный параметр.

    Для добавления нескольких IDL-файлов нужно использовать несколько параметров IDL.

    Если один IDL-файл импортирует другой IDL-файл, то генерацию idl.h-файлов нужно производить в порядке, необходимом для соблюдения зависимостей (сначала самые вложенные).

  • NK_FLAGS – дополнительные флаги для NK компилятора.

Пример вызова:

nk_build_idl_files (echo_idl_files NK_MODULE "echo" IDL "resources/Ping.idl")

Пример использования команды см. в статье "Файлы CMakeLists.txt для сборки прикладных программ".

В начало
[Topic cmake_build_idl]

nk_build_cdl_files()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>toolchain/share/cmake/Modules/platform/nk2.cmake.

nk_build_cdl_files(NAME ...)

Команда создает CMake-цель для генерации .cdl.h-файлов для одного или нескольких заданных CDL-файлов при помощи компилятора NK.

Параметры:

  • NAME – имя CMake-цели для сборки .cdl.h-файлов. Если цель еще не создана, то она будет создана с помощью add_library() с указанным именем. Обязательный параметр.
  • NOINSTALL – если указана эта опция, то файлы будут только сгенерированы в рабочей директории, но не установлены в глобальные директории: ${CMAKE_BINARY_DIR}/_headers_ ${CMAKE_BINARY_DIR}/_headers_/${PROJECT_NAME}.
  • IDL_TARGET – цель сборки .idl.h-файлов для IDL-файлов, содержащих описания служб, предоставляемых компонентами, описанными в CDL-файлах.
  • NK_MODULE – в этом параметре необходимо указать имя компонента, исключив из него имя CDL-файла. Например, если в CDL-описании имя компонента задано как kl.core.NameServer, то в параметре NK_MODULE необходимо передать значение kl.core.
  • WORKING_DIRECTORY – рабочая директория для вызова компилятора NK, по умолчанию: ${CMAKE_CURRENT_BINARY_DIR}.
  • DEPENDS – дополнительные цели сборки, от которых зависит CDL-файл.

    Для добавления нескольких целей нужно использовать несколько параметров DEPENDS.

  • CDL – путь к CDL-файлу, для которого генерируется .cdl.h-файл. Обязательный параметр.

    Для добавления нескольких CDL-файлов нужно использовать несколько параметров CDL.

  • NK_FLAGS – дополнительные флаги для NK компилятора.

Пример вызова:

nk_build_cdl_files (echo_cdl_files IDL_TARGET echo_idl_files NK_MODULE "echo" CDL "resources/Ping.cdl")

Пример использования команды см. в статье "Файлы CMakeLists.txt для сборки прикладных программ".

В начало
[Topic cmake_build_cdl]

nk_build_edl_files()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>toolchain/share/cmake/Modules/platform/nk2.cmake.

nk_build_edl_files(NAME ...)

Команда создает CMake-цель для генерации .edl.h-файла для одного заданного EDL-файла при помощи компилятора NK.

Параметры:

  • NAME – имя CMake-цели сборки .edl.h-файла. Если цель еще не создана, то она будет создана с помощью add_library() с указанным именем. Обязательный параметр.
  • NOINSTALL – если указана эта опция, то файлы будут только сгенерированы в рабочей директории, но не установлены в глобальные директории: ${CMAKE_BINARY_DIR}/_headers_ ${CMAKE_BINARY_DIR}/_headers_/${PROJECT_NAME}.
  • CDL_TARGET – цель сборки .cdl.h-файлов для CDL-файлов, содержащих описания компонентов EDL-файла, для которого выполняется сборка.
  • IDL_TARGET – цель сборки .idl.h-файлов для IDL-файлов, содержащих описания интерфейсов EDL-файла, для которого выполняется сборка.
  • NK_MODULE – в этом параметре необходимо указать имя класса процессов, исключив из него имя EDL-файла. Например, если в EDL-описании имя класса процессов задано как kl.core.NameServer, то в параметре NK_MODULE необходимо передать значение kl.core.
  • WORKING_DIRECTORY – рабочая директория для вызова компилятора NK, по умолчанию: ${CMAKE_CURRENT_BINARY_DIR}.
  • DEPENDS – дополнительные цели сборки, от которых зависит EDL-файл.

    Для добавления нескольких целей нужно использовать несколько параметров DEPENDS.

  • EDL – путь к EDL файлу, для которого генерируется edl.h-файл. Обязательный параметр.
  • NK_FLAGS – дополнительные флаги для NK компилятора.

Примеры вызова:

nk_build_edl_files (echo_server_edl_files CDL_TARGET echo_cdl_files NK_MODULE "echo" EDL "resources/Server.edl") nk_build_edl_files (echo_client_edl_files NK_MODULE "echo" EDL "resources/Client.edl")

Пример использования команды см. в статье "Файлы CMakeLists.txt для сборки прикладных программ".

В начало
[Topic cmake_build_edl]

Генерация транспортного кода для разработки на языке C++

Для генерации транспортных прокси-объектов и стабов с помощью генератора nkppmeta при сборке решения используются CMake-команды add_nk_idl(), add_nk_cdl() и add_nk_edl().

В этом разделе

add_nk_idl()

add_nk_cdl()

add_nk_edl()

В начало
[Topic cmake_cpp]

add_nk_idl()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

add_nk_idl(NAME IDL_FILE ...)

Команда создает CMake-цель для генерации заголовочного файла *.idl.cpp.h для заданного IDL-файла при помощи компилятора nkppmeta. Также команда создает библиотеку, содержащую транспортный код для заданного интерфейса. Для компоновки с этой библиотекой необходимо использовать команду bind_nk_targets().

Генерируемые заголовочные файлы содержат представление на языке C++ для интерфейса и типов данных, описанных в IDL-файле, а также методы, необходимые для использования прокси-объектов и стабов.

Параметры:

  • NAME – имя CMake-цели. Обязательный параметр.
  • IDL_FILE – путь к IDL-файлу. Обязательный параметр.
  • NK_MODULE – в этом параметре необходимо указать имя пакета, исключив из него имя IDL-файла. Например, если в IDL-описании имя пакета задано как kl.core.NameServer, то в параметре NK_MODULE необходимо передать значение kl.core.
  • LANG – в этом параметре необходимо указать значение CXX.

Пример вызова:

add_nk_idl (ANIMAL_IDL "${CMAKE_SOURCE_DIR}/resources/Animal.idl" NK_MODULE "example" LANG "CXX")
В начало
[Topic add_nk_idl]

add_nk_cdl()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

add_nk_cdl(NAME CDL_FILE ...)

Команда создает CMake-цель для генерации файла *.cdl.cpp.h для заданного CDL-файла при помощи компилятора nkppmeta. Команда также создает библиотеку, содержащую транспортный код для заданного компонента. Для компоновки с этой библиотекой необходимо использовать команду bind_nk_targets().

Файл *.cdl.cpp.h содержит дерево вложенных компонентов и служб, предоставляемых компонентом, описанным в CDL-файле.

Параметры:

  • NAME – имя CMake-цели. Обязательный параметр.
  • CDL_FILE – путь к CDL-файлу. Обязательный параметр.
  • NK_MODULE – в этом параметре необходимо указать имя компонента, исключив из него имя CDL-файла. Например, если в CDL-описании имя компонента задано как kl.core.NameServer, то в параметре NK_MODULE необходимо передать значение kl.core.
  • LANG – в этом параметре необходимо указать значение CXX.

Пример вызова:

add_nk_cdl (CAT_CDL "${CMAKE_SOURCE_DIR}/resources/Cat.cdl" NK_MODULE "example" LANG "CXX")
В начало
[Topic add_nk_cdl]

add_nk_edl()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>/toolchain/share/cmake/Modules/platform/nk2.cmake.

add_nk_edl(NAME EDL_FILE ...)

Команда создает CMake-цель для генерации файла *.edl.cpp.h для заданного EDL-файла при помощи компилятора nkppmeta. Также команда создает библиотеку, содержащую транспортный код для серверной или клиентской программы. Для компоновки с этой библиотекой необходимо использовать команду bind_nk_targets().

Файл *.edl.cpp.h содержит дерево вложенных компонентов и служб, предоставляемых классом процессов, описанным в EDL-файле.

Параметры:

  • NAME – имя CMake-цели. Обязательный параметр.
  • EDL_FILE – путь к EDL-файлу. Обязательный параметр.
  • NK_MODULE – в этом параметре необходимо указать имя класса процессов, исключив из него имя EDL-файла. Например, если в EDL-описании имя класса процессов задано как kl.core.NameServer, то в параметре NK_MODULE необходимо передать значение kl.core.
  • LANG – в этом параметре необходимо указать значение CXX.

Пример вызова:

add_nk_edl (SERVER_EDL "${CMAKE_SOURCE_DIR}/resources/Server.edl" NK_MODULE "example" LANG "CXX")
В начало
[Topic add_nk_edl]

Библиотека image

Этот раздел содержит описание команд и макросов CMake-библиотеки image , входящей в состав KasperskyOS Community Edition и содержащей скрипты сборки образа решения.

В этом разделе

build_kos_qemu_image()

build_kos_hw_image()

В начало
[Topic cmake_image_lib]

build_kos_qemu_image()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>toolchain/share/cmake/Modules/platform/image.cmake.

build_kos_qemu_image(NAME ...)

Команда создает CMake-цель сборки образа решения для QEMU.

Параметры:

  • NAME – имя CMake-цели для сборки образа решения. Обязательный параметр.
  • PERFCNT_KERNEL – использовать ядро со счетчиками производительности, если оно доступно в составе KasperskyOS Community Edition.
  • EINIT_ENTITY – имя исполняемого файла, из которого будет запускаться программа Einit.
  • EXTRA_XDL_DIR – дополнительные директории для включения при сборке программы Einit.
  • CONNECTIONS_CFG – путь до файла init.yaml или шаблона init.yaml.in.
  • SECURITY_PSL – путь до файла security.psl или шаблона security.psl.in.
  • KLOG_ENTITY – цель сборки системной программы Klog, отвечающей за аудит безопасности. Если цель не указана – аудит не выполняется.
  • QEMU_FLAGS – дополнительные флаги для запуска QEMU.
  • IMAGE_BINARY_DIR_BIN – директория для финального образа и других артефактов, по умолчанию совпадает с CMAKE_CURRENT_BINARY_DIR.
  • NO_AUTO_BLOB_CONTAINER – не включать в образ решения программу BlobContainer, необходимую для работы с динамическими библиотеками в разделяемой памяти. Подробнее см. "Включение системной программы BlobContainer в решение на базе KasperskyOS".
  • PACK_DEPS, PACK_DEPS_COPY_ONLY, PACK_DEPS_LIBS_PATH, PACK_DEPS_COPY_TARGET – параметры, задающие способ добавления динамических библиотек в образ решения.
  • IMAGE_FILES – исполняемые файлы прикладных и системных программ (кроме программы Einit) и любые другие файлы для добавления в образ ROMFS.

    Для добавления нескольких программ или файлов можно использовать несколько параметров IMAGE_FILES.

  • <пути до файлов> – свободные параметры, тоже что IMAGE_FILES.

Пример вызова:

build_kos_qemu_image ( kos-qemu-image EINIT_ENTITY EinitQemu CONNECTIONS_CFG "src/init.yaml.in" SECURITY_CFG "src/security.cfg.in" IMAGE_FILES ${ENTITIES})

Пример использования команды см. в статье "Файлы CMakeLists.txt для сборки программы Einit".

В начало
[Topic cmake_build_qemu]

build_kos_hw_image()

Команда объявлена в файле /opt/KasperskyOS-Community-Edition-<version>toolchain/share/cmake/Modules/platform/image.cmake.

build_kos_hw_image(NAME ...)

Команда создает CMake-цель сборки образа решения для аппаратной платформы.

Параметры:

  • NAME – имя CMake-цели для сборки образа решения. Обязательный параметр.
  • PERFCNT_KERNEL – использовать ядро со счетчиками производительности, если оно доступно в составе KasperskyOS Community Edition.
  • EINIT_ENTITY – имя исполняемого файла, из которого будет запускаться программа Einit.
  • EXTRA_XDL_DIR – дополнительные директории для включения при сборке программы Einit.
  • CONNECTIONS_CFG – путь до файла init.yaml или шаблона init.yaml.in.
  • SECURITY_PSL – путь до файла security.psl или шаблона security.psl.in.
  • KLOG_ENTITY – цель сборки системной программы Klog, отвечающей за аудит безопасности. Если цель не указана – аудит не выполняется.
  • IMAGE_BINARY_DIR_BIN – директория для финального образа и других артефактов, по умолчанию CMAKE_CURRENT_BINARY_DIR.
  • NO_AUTO_BLOB_CONTAINER – не включать в образ решения программу BlobContainer, необходимую для работы с динамическими библиотеками в разделяемой памяти. Подробнее см. "Включение системной программы BlobContainer в решение на базе KasperskyOS".
  • PACK_DEPS, PACK_DEPS_COPY_ONLY, PACK_DEPS_LIBS_PATH, PACK_DEPS_COPY_TARGET – параметры, задающие способ добавления динамических библиотек в образ решения.
  • IMAGE_FILES – исполняемые файлы прикладных и системных программ (кроме программы Einit) и любые другие файлы для добавления в образ ROMFS.

    Для добавления нескольких программ или файлов можно использовать несколько параметров IMAGE_FILES.

  • <пути до файлов> – свободные параметры, тоже что IMAGE_FILES.

Пример вызова:

build_kos_hw_image ( kos-image EINIT_ENTITY EinitHw CONNECTIONS_CFG "src/init.yaml.in" SECURITY_CFG "src/security.cfg.in" IMAGE_FILES ${ENTITIES})

Пример использования команды см. в статье "Файлы CMakeLists.txt для сборки программы Einit".

В начало
[Topic cmake_build_hw]

Сборка без использования CMake

Этот раздел содержит описание скриптов, утилит, компиляторов и шаблонов сборки, поставляемых в KasperskyOS Community Edition.

Эти инструменты можно использовать:

  • в других системах сборки;
  • для выполнения отдельных шагов сборки;
  • для изучения особенностей сборки и написания собственной системы сборки.

Общая схема сборки образа решения приведена в статье "Общая схема сборки".

В этом разделе

Инструменты для сборки решения

Пример сборки без использования CMake

В начало
[Topic cmake_no_cmake_build]

Инструменты для сборки решения

Этот раздел содержит описание скриптов, утилит, компиляторов и шаблонов сборки, поставляемых в KasperskyOS Community Edition.

В этом разделе

Утилиты и скрипты сборки

Кросс-компиляторы

В начало
[Topic solution_build_tools]

Утилиты и скрипты сборки

В состав KasperskyOS Community Edition входят следующие утилиты и скрипты сборки:

  • nk-gen-c

    Компилятор NK (nk-gen-c) генерирует транспортный код на основе IDL-, CDL- и EDL-описаний. Транспортный код нужен для формирования, отправки, приема и обработки IPC-сообщений.

  • nk-psl-gen-c

    Компилятор nk-psl-gen-c генерирует исходный код модуля безопасности Kaspersky Security Module на языке C на основе описания политики безопасности решения и IDL-, CDL-, EDL-описаний. Также компилятор nk-psl-gen-c позволяет генерировать исходный код тестов политики безопасности решения на языке C на основе тестов политики безопасности решения на языке PAL.

  • einit

    Утилита einit позволяет автоматизировать создание кода инициализирующей программы Einit. Эта программа первой запускается при загрузке KasperskyOS и запускает остальные программы, а также создает IPC-каналы между ними.

  • makekss

    Скрипт makekss создает модуль безопасности Kaspersky Security Module.

  • makeimg

    Скрипт makeimg создает финальный загружаемый образ решения на базе KasperskyOS со всеми запускаемыми программами и модулем Kaspersky Security Module.

В начало
[Topic build_utilities_and_scripts]

nk-gen-c

Компилятор NK (nk-gen-c) генерирует транспортный код на основе IDL-, CDL-, EDL-описаний.

Компилятор nk-gen-c принимает IDL-, CDL- или EDL-файл и создает следующие файлы:

  • Файл *.*dl.h, содержащий транспортный код.
  • Файл *.*dl.nk.d, в котором перечислены зависимости созданного файла *.*dl.h от IDL- и CDL-файлов. Файл *.*dl.nk.d создается для системы сборки.

Синтаксис shell-команды для запуска компилятора nk-gen-c:

nk-gen-c [-I <PATH>]... [-o <PATH>] [--types] [--interface] [--endpoints] [--client] [--server] [--extended-errors] [--trace-client-ipc {headers|dump}] [--trace-server-ipc {headers|dump}] [--ipc-trace-method-filter <METHOD>[,METHOD]...] [-h|--help] [--version] <FILE>

Базовые параметры:

  • FILE

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

  • -I <PATH>

    Через эти параметры задаются пути к директориям, которые содержат вспомогательные файлы, необходимые для генерации транспортного кода. (Вспомогательные файлы располагаются в директории sysroot-*-kos/include из состава KasperskyOS SDK.) Также через эти параметры можно задать пути к директориям, содержащим IDL-, CDL-файлы, на которые ссылается файл, заданный через параметр FILE.

  • -o <PATH>

    Путь к существующей директории, в которую будут помещены созданные файлы. Если этот параметр не указан, созданные файлы будут помещены в текущую директорию.

  • -h|--help

    Выводит текст справки.

  • --version

    Выводит версию компилятора nk-gen-c.

  • --extended-errors

    Это параметр обеспечивает возможность использовать интерфейсные методы с одним или несколькими error-параметрами произвольных IDL-типов. (Клиент работает с error-параметрами как с выходными параметрами.)

    Если не указывать параметр --extended-errors, можно использовать интерфейсные методы только с одним error-параметром status IDL-типа UInt16, значение которого передается клиенту через код возврата интерфейсного метода. Такой способ является устаревшим и перестанет поддерживаться в будущем, поэтому рекомендуется всегда указывать параметр --extended-errors.

Выборочная генерация транспортного кода

Чтобы уменьшить объем генерируемого транспортного кода, можно использовать флаги выборочной генерации транспортного кода. Например, для программ, реализующих службы, можно использовать флаг --server, а для программ, использующих службы, можно использовать флаг --client.

Если ни один из флагов выборочной генерации транспортного кода не указан, компилятор nk-gen-c генерирует для заданного IDL-, CDL- или EDL-файла транспортный код со всеми возможными методами и типами.

Флаги выборочной генерации транспортного кода для IDL-файла:

  • --types

    Транспортный код включает типы, соответствующие IDL-типам из заданного IDL-файла, а также импортируемым в этот файл IDL-типам, которые используются в IDL-типах заданного IDL-файла. При этом типы, соответствующие импортируемым IDL-константам и псевдонимам импортируемых IDL-типов, не включаются в файл *.idl.h. Чтобы использовать типы, соответствующие импортируемым IDL-константам и псевдонимам импортируемых IDL-типов, нужно отдельно сгенерировать транспортный код для IDL-файлов, из которых осуществляется импорт.

  • --interface

    Транспортный код соответствует флагу --types, а также включает типы структур фиксированной части IPC-запросов и IPC-ответов для интерфейсных методов, сигнатуры которых указаны в заданном IDL-файле. Кроме того, транспортный код содержит константы с размерами арен IPC-сообщений.

  • --client

    Транспортный код соответствует флагу --interface, а также включает тип прокси-объекта, метод инициализации прокси-объекта и интерфейсные методы, указанные в заданном IDL-файле.

  • --server

    Транспортный код соответствует флагу --interface, а также включает типы и диспетчер (dispatch-метод), используемые для обработки IPC-запросов, соответствующих интерфейсным методам, указанным в заданном IDL-файле.

Флаги выборочной генерации транспортного кода для CDL- или EDL-файла:

  • --types

    Транспортный код включает типы, соответствующие IDL-типам, которые используются в параметрах методов служб, предоставляемых компонентом (для заданного CDL-файла) или классом процессов (для заданного EDL-файла).

  • --endpoints

    Транспортный код соответствует флагу --types, а также включает типы структур фиксированной части IPC-запросов и IPC-ответов для методов служб, предоставляемых компонентом (для заданного CDL-файла) или классом процессов (для заданного EDL-файла). Кроме того, транспортный код содержит константы с размерами арен IPC-сообщений.

  • --client

    Транспортный код соответствует флагу --types, а также включает типы структур фиксированной части IPC-запросов и IPC-ответов для методов служб, предоставляемых компонентом (для заданного CDL-файла) или классом процессов (для заданного EDL-файла). Кроме того, транспортный код содержит константы с размерами арен IPC-сообщений, а также типы прокси-объектов, методы инициализации прокси-объектов и методы служб, предоставляемых компонентом (для заданного CDL-файла) или классом процессов (для заданного EDL-файла).

  • --server

    Транспортный код соответствует флагу --types, а также включает типы и диспетчеры (dispatch-методы), используемые для обработки IPC-запросов, соответствующих службам, предоставляемым компонентом (для заданного CDL-файла) или классом процессов (для заданного EDL-файла). Кроме того, транспортный код содержит константы с размерами арен IPC-сообщений, а также типы стабов, методы инициализации стабов и типы структур фиксированной части IPC-запросов и IPC-ответов для методов служб, предоставляемых компонентом (для заданного CDL-файла) или классом процессов (для заданного EDL-файла).

Вывод диагностических данных об отправке и приеме IPC-сообщений

Транспортный код может формировать диагностические данные об отправке и приеме IPC-сообщений и выводить эти данные через стандартный вывод ошибок. Чтобы генерировать транспортный код с такими возможностями, нужно использовать следующие параметры:

  • --trace-client-ipc {headers|dump}

    Код вывода диагностических данных исполняется непосредственно перед выполнением системного вызова Call() и сразу после его выполнения. Если указано значение headers, диагностические данные включают идентификатор метода службы (MID), идентификатор службы (RIID), размер фиксированной части IPC-сообщения в байтах, содержимое дескриптора арены IPC-сообщения, размер арены IPC-сообщения в байтах и размер использованной части арены IPC-сообщения в байтах. Если указано значение dump, диагностические данные дополнительно включают содержимое фиксированной части и арены IPC-сообщения в шестнадцатеричном представлении.

    При использовании этого параметра нужно указать флаг выборочной генерации транспортного кода --client либо не указывать флаги выборочной генерации транспортного кода.

  • --trace-server-ipc {headers|dump}

    Код вывода диагностических данных исполняется непосредственно перед вызовом функции, реализующей интерфейсный метод, и сразу после выполнения этой функции, то есть при вызове диспетчера (dispatch-метода) в промежутке между выполнением системных вызовов Recv() и Reply(). Если указано значение headers, диагностические данные включают идентификатор метода службы (MID), идентификатор службы (RIID), размер фиксированной части IPC-сообщения в байтах, содержимое дескриптора арены IPC-сообщения, размер арены IPC-сообщения в байтах и размер использованной части арены IPC-сообщения в байтах. Если указано значение dump, диагностические данные дополнительно включают содержимое фиксированной части и арены IPC-сообщения в шестнадцатеричном представлении.

    При использовании этого параметра нужно указать флаг выборочной генерации транспортного кода --server либо не указывать флаги выборочной генерации транспортного кода.

  • --ipc-trace-method-filter <METHOD>[,METHOD]...

    Вывод диагностических данных выполняется, если только вызваны заданные интерфейсные методы. В качестве значения METHOD можно использовать имя интерфейсного метода либо конструкцию <имя пакета>:<имя интерфейсного метода>. Имя пакета и имя интерфейсного метода указаны в IDL-файле.

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

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

В начало
[Topic nkgenc]

nk-psl-gen-c

Компилятор nk-psl-gen-c генерирует исходный код модуля безопасности Kaspersky Security Module на языке C на основе описания политики безопасности решения и IDL-, CDL-, EDL-описаний. Этот код используется скриптом makekss.

Компилятор nk-psl-gen-c также позволяет генерировать исходный код тестов политики безопасности решения на языке C на основе тестов политики безопасности решения на языке PAL.

Синтаксис shell-команды для запуска компилятора nk-psl-gen-c:

nk-psl-gen-c [{-I|--include-dir} <DIR>]... [{-o|--output} <FILE>] [--out-tests <FILE>] [{-t|--tests} <ARG>] [{-a|--audit} <FILE>] [-h|--help] [--version] <INPUT>

Параметры:

  • INPUT

    Путь к верхнеуровневому файлу описания политики безопасности решения. Как правило, это файл security.psl.

  • {-I|--include-dir} <DIR>

    Через эти параметры задаются пути к директориям с IDL-, CDL-, EDL-файлам, относящимися к решению, и пути к директориям, которые содержат вспомогательные файлы из состава KasperskyOS SDK (common, sysroot-*-kos/include, toolchain/include).

  • {-o|--output} <FILE>

    Путь к файлу, в который будет сохранен исходный код модуля безопасности Kaspersky Security Module и опционально исходный код тестов политики безопасности решения. Путь должен включать существующие директории.

  • --out-tests <FILE>

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

  • {-t|--tests} <ARG>

    Задает, нужно ли генерировать исходный код тестов политики безопасности решения. ARG может принимать следующие значения:

    • skip – исходный код тестов не генерируется. Это значение используется по умолчанию, если параметр -t, --tests <ARG> не указан.
    • generate – исходный код тестов генерируется. Если исходный код тестов генерируется, то рекомендуется использовать параметр --out-tests <FILE>, иначе исходный код тестов будет сохранен в одном файле с исходным кодом модуля безопасности Kaspersky Security Module, что может привести к ошибкам при сборке.
  • {-a|--audit} <FILE>

    Путь к файлу, в который будет сохранен исходный код декодера аудита на языке C.

  • -h|--help

    Выводит текст справки.

  • --version

    Выводит версию компилятора nk-psl-gen-c.

В начало
[Topic nkpslgenc]

einit

Утилита einit позволяет автоматизировать создание кода инициализирующей программы Einit.

Утилита einit принимает описание инициализации решения (по умолчанию файл init.yaml), а также EDL-, CDL- и IDL-описания, и создает файл с исходным кодом инициализирующей программы Einit. Программу Einit затем необходимо собрать с помощью кросс-компилятора языка C, поставляемого в KasperskyOS Community Edition.

Синтаксис использования утилиты einit:

einit -I PATH -o PATH [--help] FILE

Параметры:

  • FILE

    Путь к файлу init.yaml.

  • -I PATH

    Путь к директории, содержащей вспомогательные файлы (включая EDL-, CDL- и IDL-описания), необходимые для генерации инициализирующей программы. По умолчанию эти файлы располагаются в директории /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/include.

  • -o, --out-file PATH

    Путь к создаваемому .c файлу с кодом инициализирующей программы.

  • -h, --help

    Отображает текст справки.

В начало
[Topic einit_tool]

makekss

Скрипт makekss создает модуль безопасности Kaspersky Security Module.

Скрипт вызывает компилятор nk-psl-gen-c для генерации исходного кода модуля безопасности и затем компилирует полученный код, вызывая компилятор C, поставляемый в KasperskyOS Community Edition.

Скрипт создает модуль безопасности из описания политики безопасности решения.

Синтаксис использования скрипта makekss:

makekss --target=ARCH --module=PATH --with-nk="PATH" --with-nktype="TYPE" --with-nkflags="FLAGS" [--output="PATH"][--help][--with-cc="PATH"][--with-cflags="FLAGS"] FILE

Параметры:

  • FILE

    Путь к верхнеуровневому файлу описания политики безопасности решения.

  • --target=ARCH

    Архитектура процессора, для которой производится сборка.

  • --module=-lPATH

    Путь к библиотеке ksm_kss. Этот ключ передается компилятору C для компоновки с этой библиотекой.

  • --with-nk=PATH

    Путь к компилятору nk-psl-gen-c, который будет использоваться для генерации исходного кода модуля безопасности. По умолчанию компилятор расположен в /opt/KasperskyOS-Community-Edition-<version>/toolchain/bin/nk-psl-gen-c.

  • --with-nktype="TYPE"

    Указывает на тип компилятора NK, который будет использоваться. Для использования компилятора nk-psl-gen-c, необходимо указать тип psl.

  • --with-nkflags="FLAGS"

    Параметры, с которыми вызывается компилятор nk-psl-gen-c.

    Компилятору nk-psl-gen-c потребуется доступ ко всем EDL- CDL- и IDL-описаниям. Для того, чтобы компилятор nk-psl-gen-c мог найти эти описания, нужно передать пути к расположению этих описаний в параметре --with-nkflags, используя параметр -I компилятора nk-psl-gen-c.

  • --output=PATH

    Путь к создаваемому файлу модуля безопасности.

  • --with-cc=PATH

    Путь к компилятору C, который будет использоваться для сборки модуля безопасности. По умолчанию используется компилятор, поставляемый в KasperskyOS Community Edition.

  • --with-cflags=FLAGS

    Параметры, с которыми вызывается компилятор C.

  • -h, --help

    Отображает текст справки.

В начало
[Topic makekss]

makeimg

Скрипт makeimg создает финальный загружаемый образ решения на базе KasperskyOS со всеми исполняемыми файлами программ и модулем Kaspersky Security Module.

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

  • образ решения;
  • образ решения без таблиц символов (.stripped);
  • образ решения с отладочными таблицами символов (.dbg.syms).

Синтаксис использования скрипта makeimg:

makeimg --target=ARCH --sys-root=PATH --with-toolchain=PATH --ldscript=PATH --img-src=PATH --img-dst=PATH --with-init=PATH [--with-extra-asflags=FLAGS][--with-extra-ldflags=FLAGS][--help] FILES

Параметры:

  • FILES

    Список путей к файлам, включая исполняемые файлы всех программ, которые нужно добавить в ROMFS.

    Модуль безопасности (ksm.module) нужно указывать явно, иначе он не будет включен в образ решения. Программу Einit указывать не нужно, так как она будет включена в образ решения автоматически.

  • --target=ARCH

    Архитектура, для которой производится сборка.

  • --sys-root=PATH

    Путь к корневой директории sysroot. По умолчанию эта директория расположена в /opt/KasperskyOS-Community-Edition-<version>/sysroot-aarch64-kos/.

  • --with-toolchain=PATH

    Путь к набору вспомогательных утилит, необходимых для сборки решения. По умолчанию эти утилиты расположены в /opt/KasperskyOS-Community-Edition-<version>/toolchain/.

  • --ldscript=PATH

    Путь к скрипту компоновщика, необходимому для сборки решения. По умолчанию этот скрипт расположен в /opt/KasperskyOS-Community-Edition-<version>/libexec/aarch64-kos/.

  • --img-src=PATH

    Путь к заранее скомпилированному ядру KasperskyOS. По умолчанию ядро расположено в /opt/KasperskyOS-Community-Edition-<version>/libexec/aarch64-kos/.

  • --img-dst=PATH

    Путь к создаваемому файлу образа.

  • --with-init=PATH

    Путь к исполняемому файлу инициализирующей программы Einit.

  • --with-extra-asflags=FLAGS

    Дополнительные флаги для ассемблера AS.

  • --with-extra-ldflags=FLAGS

    Дополнительные флаги для компоновщика LD.

  • -h, --help

    Отображает текст справки.

В начало
[Topic makeimg]

Кросс-компиляторы

В тулчейн из состава KasperskyOS SDK входит один или несколько компиляторов GCC. В директории toolchain/bin находятся следующие файлы:

  • исполняемые файлы компиляторов (например, x86_64-pc-kos-gcc, arm-kos-g++);
  • исполняемые файлы компоновщиков (например, x86_64-pc-kos-ld, arm-kos-ld);
  • исполняемые файлы ассемблеров (например, x86_64-pc-kos-as, arm-kos-as);

В GCC, кроме стандартных макросов, определен дополнительный макрос __KOS__=1. Использование этого макроса упрощает портирование программного кода на KasperskyOS, а также разработку платформонезависимых программ.

Чтобы просмотреть список стандартных макросов GCC, выполните следующую команду:

echo '' | aarch64-kos-gcc -dM -E -

Особенности работы компоновщика

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

  1. libc – стандартная библиотека языка C.
  2. libm – библиотека, реализующая математические функции стандартной библиотеки языка C.
  3. libvfs_stubs – библиотека, содержащая заглушки функций ввода/вывода (например, open, socket, read, write).
  4. libkos – библиотека для доступа к службам ядра KasperskyOS.
  5. libenv – библиотека подсистемы настройки окружения программ (переменных окружения, аргументов функции main и пользовательских конфигураций).
  6. libsrvtransport-u – библиотека поддержки IPC между процессами и ядром.
В начало
[Topic crosscompliers]

Пример сборки без использования CMake

Ниже приведен пример скрипта для сборки простейшего примера. Этот пример содержит единственную прикладную программу Hello, которая не предоставляет службы.

Приведенный скрипт предназначен только для демонстрации используемых команд сборки.

build.sh

#!/bin/sh # В переменной SDK нужно указать путь к директории установки KasperskyOS Community Edition. SDK=/opt/KasperskyOS-Community-Edition-<version> TOOLCHAIN=$SDK/toolchain SYSROOT=$SDK/sysroot-aarch64-kos PATH=$TOOLCHAIN/bin:$PATH # Создание файла Hello.edl.h из Hello.edl # (Программа Hello не реализует служб, поэтому cdl- и idl-файлы отсутствуют.) nk-gen-c -I $SYSROOT/include Hello.edl # Компиляция и сборка программы Hello aarch64-kos-gcc -o hello hello.c # Создание модуля безопасности Kaspersky Security Module (ksm.module) makekss --target=aarch64-kos \ --module=-lksm_kss \ --with-nkflags="-I $SDK/examples/common -I $SYSROOT/include" \ security.psl # Создание кода инициализирующей программы Einit einit -I $SYSROOT/include -I . init.yaml -o einit.c # Компиляция и сборка программы Einit aarch64-kos-gcc -I . -o einit einit.c # Создание загружаемого образа решения (kos-qemu-image) makeimg --target=aarch64-kos \ --sys-root=$SYSROOT \ --with-toolchain=$TOOLCHAIN \ --ldscript=$SDK/libexec/aarch64-kos/kos-qemu.ld \ --img-src=$SDK/libexec/aarch64-kos/kos-qemu \ --img-dst=kos-qemu-image \ Hello ksm.module # Запуск решения под QEMU qemu-system-aarch64 -m 1024 -serial stdio -kernel kos-qemu-image
В начало
[Topic cmake_no_cmake_build_example]

Использование динамических библиотек

В решении на базе KasperskyOS можно использовать динамические библиотеки (файлы *.so). По сравнению со статическими библиотеками (файлами *.a) динамические библиотеки дают следующие преимущества:

  • Экономия оперативной памяти.

    Несколько процессов могут использовать один экземпляр динамической библиотеки. Также программа и динамические библиотеки в одном процессе могут использовать один экземпляр динамической библиотеки.

    Динамические библиотеки могут загружаться в память и выгружаться из нее по инициативе программ, которые их используют.

  • Удобство обновления ПО.

    Обновление динамической библиотеки распространяется на все зависимые от нее программы и динамические библиотеки без их повторной сборки.

  • Возможность реализовать механизм плагинов.

    Плагины для компонентов решения представляют собой динамические библиотеки.

  • Совместное использование кода и данных.

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

Динамические библиотеки поставляются в составе KasperskyOS SDK, а также могут быть созданы разработчиком решения на базе KasperskyOS. Работоспособность сторонних динамических библиотек не гарантируется.

В настоящее время из-за технических ограничений в решении на базе KasperskyOS нельзя использовать libc.so и libpthread.so.

В этом разделе

Условия, необходимые для использования динамических библиотек

Жизненный цикл динамической библиотеки

Включение системной программы BlobContainer в решение на базе KasperskyOS

Сборка динамических библиотек

Добавление динамических библиотек в образ решения на базе KasperskyOS

В начало
[Topic shared_libraries]

Условия, необходимые для использования динамических библиотек

Чтобы использовать динамические библиотеки в решении на базе KasperskyOS, нужно выполнить следующие условия:

  1. Процессы, использующие динамические библиотеки, должны иметь доступ к файловым системам, в которых хранятся файлы динамических библиотек. Доступ к файловым системам обеспечивается VFS, которая может исполняться в контексте процессов, использующих динамические библиотеки, а также может быть отдельным процессом. VFS и другое ПО, с помощью которого VFS работает с накопителем (например драйвер накопителя), не должны использовать динамические библиотеки.
  2. Тулчейн должен поддерживать динамическую компоновку.

    В составе KasperskyOS SDK поставляется отдельный тулчейн для каждой поддерживаемой архитектуры процессора. Требуемый тулчейн может не поддерживать динамическую компоновку. Чтобы проверить, что динамическая компоновка поддерживается, нужно использовать в корневом файле CMakeLists.txt CMake-команду get_property() следующим образом:

    get_property(CAN_SHARED GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) if(CAN_SHARED) message(STATUS "Dynamic linking is supported.") endif()
  3. Исполняемый код программ, использующих динамические библиотеки, должен быть собран с флагом -rdynamic (с динамической компоновкой).

    Если тулчейн поддерживает динамическую компоновку, то CMake-команда initialize_platform() делает так, что для сборки всех исполняемых файлов, заданных через CMake-команды add_executable(), этот флаг используется автоматически.

Если CMake-команда initialize_platform(FORCE_STATIC) вызывается в корневом файле CMakeLists.txt, то тулчейн, поддерживающий динамическую компоновку, выполняет статическую компоновку исполняемых файлов.

CMake-команда project_static_executable_header_default() влияет на сборку исполняемых файлов, заданных через последующие CMake-команды add_executable() в одном файле CMakeLists.txt. Тулчейн, поддерживающий динамическую компоновку, выполняет статическую компоновку этих исполняемых файлов.

CMake-команда platform_target_force_static() влияет на сборку одного исполняемого файла, заданного через CMake-команду add_executable(). Тулчейн, поддерживающий динамическую компоновку, выполняет статическую компоновку этого исполняемого файла.

Исполняемый код программ, который собирается с флагом -rdynamic, компонуется со статической библиотекой, если динамическая библиотека не найдена. Например, если используется CMake-команда target_link_libraries(client -lm), программа client компонуется со статической библиотекой libm.a, если динамическая библиотека libm.so не найдена.

В начало
[Topic shared_libraries_use_conditions]

Жизненный цикл динамической библиотеки

Жизненный цикл динамической библиотеки включает следующие стадии:

  1. Загрузка в память.

    Динамическая библиотека, скомпонованная с программой, загружается в память при запуске процесса, в контексте которого эта программа исполняется. Запущенный процесс может загрузить динамическую библиотеку в память вызовом функции dlopen() интерфейса POSIX. Динамическая библиотека может быть скомпонована с другими динамическими библиотеками, поэтому программа зависит не только от непосредственно скомпонованной с ней динамической библиотеки, но и от всего графа зависимостей этой библиотеки. Динамическая библиотека загружается в память совместно с всеми динамическими библиотеками, от которых зависит.

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

    Если задать через переменную окружения LD_PRELOAD список динамических библиотек, то эти динамические библиотеки будут загружены в память, даже если программа не зависит от них. (Элементами списка должны быть абсолютные или относительные пути к динамическим библиотекам, разделенные двоеточием, например: LD_PRELOAD=libmalloc.so:libfree.so:/usr/somepath/lib/libfoo.so.) Функции, которые экспортируются динамическими библиотеками, указанными в LD_PRELOAD, замещают одноименные функции, которые экспортируются другими загруженными в разделяемую память или память процесса динамическими библиотеками. Это можно использовать для целей отладки, если требуется подменить функции, импортируемые из динамических библиотек.

    Загрузчик динамических библиотек выполняет поиск динамических библиотек, от которых зависят программы, в следующем порядке:

    1. По абсолютным путям, заданным через переменную окружения LD_LIBRARY_PATH.

      Пути должны быть разделены двоеточием, например: LD_LIBRARY_PATH=/usr/lib:/home/user/lib.

    2. По абсолютным путям, заданным в поле DT_RUNPATH или DT_RPATH секции .dynamic исполняемых файлов и динамических библиотек.

      При компоновке исполняемых файлов и динамических библиотек могут быть заданы пути, по которым загрузчик динамических библиотек будет выполнять поиск. (Это можно сделать, например, через свойство INSTALL_RPATH в CMake-команде set_target_properties().) Пути для поиска динамических библиотек сохраняются в поле DT_RUNPATH или DT_RPATH секции .dynamic. Это поле может быть как в исполняемых файлах, скомпонованных с динамическими библиотеки, так и в самих динамических библиотеках, скомпонованных с другими динамическими библиотеками.

    3. По пути /lib.

    Загрузчик динамических библиотек выполняет поиск в том же порядке, если в параметре filename функции dlopen() или в переменной окружения LD_PRELOAD указан относительный путь к динамической библиотеке. Если указан абсолютный путь, то загрузчик помещает динамическую библиотеку в память без выполнения поиска.

  2. Использование процессом (процессами).
  3. Выгрузка из памяти.

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

В начало
[Topic shared_libraries_lifecycle]

Включение системной программы BlobContainer в решение на базе KasperskyOS

Если программа BlobContainer поставляется в составе KasperskyOS SDK, ее необходимо включить в решение, в котором используются динамические библиотеки. Чтобы проверить, поставляется ли программа BlobContainer в составе KasperskyOS SDK, нужно убедиться в наличии исполняемого файла sysroot-*-kos/bin/BlobContainer.

Программа BlobContainer может быть включена в решение автоматически или вручную. Автоматическое включение этой программы в решение выполняется CMake-командами build_kos_qemu_image() и build_kos_hw_image(), если как минимум одна программа в решении скомпонована с динамической библиотекой. (Чтобы отключить автоматическое включение программы BlobContainer в решение, нужно добавить значение NO_AUTO_BLOB_CONTAINER в параметры CMake-команд build_kos_qemu_image() и build_kos_hw_image().) Если программы в решении работают с динамическими библиотеками, используя только интерфейс POSIX (функции dlopen(), dlsym(), dlerror(), dlclose()), то программу BlobContainer нужно включить в решение вручную.

В случае применения программы BlobContainer должны быть созданы IPC-каналы от процессов, использующих динамические библиотеки, к процессу программы BlobContainer. Эти IPC-каналы могут быть созданы как статически, так и динамически. Если статически созданный IPC-канал отсутствует, клиентская и серверная части программы BlobContainer пытаются создать IPC-канал динамически, используя сервер имен.

Если программа BlobContainer включена в решение автоматически, то макросы @INIT_EXTERNAL_ENTITIES@, @INIT_<имя программы>_ENTITY_CONNECTIONS@ и @INIT_<имя программы>_ENTITY_CONNECTIONS+@, используемые в файле init.yaml.in, автоматически создают в init-описании словари IPC-каналов, которые обеспечивают статическое создание IPC-каналов от процессов программ, скомпонованных с динамическими библиотеками, к процессу программы BlobContainer. (Процесс программы BlobContainer получает имя kl.bc.BlobContainer, а IPC-каналы получают имя kl.BlobContainer.) При этом для процессов, которые работают с динамическими библиотеками, используя только интерфейс POSIX, словари IPC-каналов к процессу программы BlobContainer автоматически не создаются, и, чтобы требуемые IPC-каналы были созданы статически, нужно создать эти словари вручную (эти IPC-каналы должны иметь имя kl.BlobContainer).

Если программа BlobContainer включена в решение вручную, и требуется статически создать IPC-каналы от процессов, использующих динамические библиотеки, к процессу программы BlobContainer, то нужно вручную создать словари необходимых IPC-каналов в init-описании. По умолчанию IPC-канал к процессу программы BlobContainer имеет имя kl.BlobContainer, но это имя можно изменить через переменную окружения _BLOB_CONTAINER_BACKEND. Эту переменную нужно задать как для процесса BlobContainer, так и для процессов, использующих динамические библиотеки.

Переменная окружения _BLOB_CONTAINER_BACKEND задает не только имя статически создаваемых IPC-каналов к процессу программы BlobContainer, но и имя службы, публикуемое на сервере имен, которое используется для динамического создания IPC-каналов к процессу программы BlobContainer. Это удобно использовать, когда запущено одновременно несколько процессов программы BlobContainer (например, с целью изоляции собственных динамических библиотек от сторонних), и разные процессы, использующие динамические библиотеки, должны взаимодействовать через IPC с разными процессами программы BlobContainer. В таком случае для разных процессов программы BlobContainer нужно задать разные значения переменной окружения _BLOB_CONTAINER_BACKEND, а затем использовать эти значения для переменной окружения _BLOB_CONTAINER_BACKEND процессов, использующих динамические библиотеки, выбирая конкретное значение в зависимости того, с каким именно процессом программы BlobContainer требуется динамически создать IPC-канал.

Пример использования переменной окружения _BLOB_CONTAINER_BACKEND в файле init.yaml.in:

entities: - name: example.BlobContainer path: example_blob_container args: - "-v" env: _BLOB_CONTAINER_BACKEND: kl.custombc @INIT_example_blob_container_ENTITY_CONNECTIONS@ - name: client.Client path: client env: _BLOB_CONTAINER_BACKEND: kl.custombc @INIT_client_ENTITY_CONNECTIONS@ @INIT_EXTERNAL_ENTITIES@

Пример использования переменной окружения _BLOB_CONTAINER_BACKEND в CMake-командах:

set_target_properties (ExecMgrEntity PROPERTIES EXTRA_ENV " _BLOB_CONTAINER_BACKEND: kl.custombc") set_target_properties (dump_collector::entity PROPERTIES EXTRA_ENV " _BLOB_CONTAINER_BACKEND: kl.custombc")

Если используется программа BlobContainer, то VFS, работающая с файлами динамических библиотек, должна быть отдельным процессом. Также должен быть создан IPC-канал от процесса программы BlobContainer к процессу VFS.

В начало
[Topic shared_libraries_blobcontainer]

Сборка динамических библиотек

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

Чтобы выполнить сборку динамической библиотеки, нужно использовать следующую CMake-команду:

add_library(<имя цели сборки> SHARED [список путей к файлам исходного кода библиотеки])

При использовании этой CMake-команды возникает ошибка, если тулчейн не поддерживает динамическую компоновку.

Также можно выполнить сборку динамической библиотеки следующей CMake-командой:

add_library(<имя цели сборки> [список путей к файлам исходного кода библиотеки])

При этом shell-команду cmake нужно вызвать с параметром -D BUILD_SHARED_LIBS=YES. (Если вызвать shell-команду cmake без параметра -D BUILD_SHARED_LIBS=YES, будет выполнена сборка статической библиотеки.)

Пример:

#!/bin/bash ... cmake -G "Unix Makefiles" \ -D CMAKE_BUILD_TYPE:STRING=Debug \ -D CMAKE_TOOLCHAIN_FILE=$SDK_PREFIX/toolchain/share/toolchain-$TARGET.cmake \ -D BUILD_SHARED_LIBS=YES \ -B build \ && cmake --build build --target kos-image

По умолчанию имя файла библиотеки совпадает с именем цели сборки, заданным через параметр CMake-команды add_library(). Имя файла библиотеки можно изменить, используя CMake-команду set_target_properties(). Это можно использовать, чтобы имя файла библиотеки было одинаковым для ее динамического и статического варианта.

Пример:

# Сборка статической библиотеки add_library(somelib_static STATIC src/somesrc.cpp) set_target_properties(somelib_static PROPERTIES OUTPUT_NAME "somelib") # Переменная PLATFORM_SUPPORTS_DYNAMIC_LINKING имеет # значение "истина", если используется динамическая # компоновка. Если вызывается initialize_platform(FORCE_STATIC), # эта переменная имеет значение "ложь". if(PLATFORM_SUPPORTS_DYNAMIC_LINKING) # Сборка динамической библиотеки add_library(somelib_shared SHARED src/somesrc.cpp) set_target_properties(somelib_shared PROPERTIES OUTPUT_NAME "somelib") endif()

Динамическая библиотека может быть скомпонована с другими статическими и динамическими библиотеками CMake-командой target_link_libraries(). При этом статические библиотеки должны быть собраны с флагом -fPIC. Этот флаг применяется при сборке статической библиотеки, если используется следующая CMake-команда:

set_property(TARGET <список имен целей сборки> PROPERTY POSITION_INDEPENDENT_CODE ON)
В начало
[Topic shared_libraries_building]

Добавление динамических библиотек в образ решения на базе KasperskyOS

Чтобы добавить динамические библиотеки в образ решения на базе KasperskyOS, нужно использовать параметры PACK_DEPS_COPY_ONLY ON, PACK_DEPS_LIBS_PATH и PACK_DEPS_COPY_TARGET в CMake-командах build_kos_qemu_image() и build_kos_hw_image().

Пример:

set(RESOURCES ${CMAKE_SOURCE_DIR}/resources) set(FSTAB ${RESOURCES}/fstab) set(DISK_IMG ${CMAKE_CURRENT_BINARY_DIR}/ramdisk0.img) set(RESOURCES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../resources) set(EXT4_PART_DIR ${CMAKE_CURRENT_BINARY_DIR}/../system_hdd) set_target_properties(${vfs_ENTITY} PROPERTIES EXTRA_ARGS " - \"-f\" - \"fstab\"" EXTRA_ENV " ROOTFS: ramdisk0 / ext4 0" ${blkdev_ENTITY}_REPLACEMENT "${ramdisk_ENTITY};${sdcard_ENTITY}") add_custom_target(copy-so) add_custom_command(OUTPUT ${DISK_IMG} COMMAND ${CMAKE_COMMAND} -E copy_directory ${RESOURCES_DIR}/rootdir ${EXT4_PART_DIR} COMMAND mke2fs -v -d ${EXT4_PART_DIR} -t ext4 ${DISK_IMG} 40M DEPENDS copy-so COMMENT "Creating disk image '${DISK_IMG}' from files in '${EXT4_PART_DIR}' ...") build_kos_hw_image(kos-image ... IMAGE_FILES ${ENTITIES_LIST} ${FSTAB} ${DISK_IMG} PACK_DEPS_COPY_ONLY ON PACK_DEPS_LIBS_PATH ${EXT4_PART_DIR}/lib PACK_DEPS_COPY_TARGET copylibs) if(PLATFORM_SUPPORTS_DYNAMIC_LINKING) add_dependencies(copy-so copylibs) endif()

Динамические библиотеки, от которых зависят программы решения, будут добавлены в образ накопителя (например, с файловой системой ext4), который будет включен в образ решения.

Динамические библиотеки, которые загружаются в память вызовом функции dlopen() интерфейса POSIX, не попадут в образ решения.

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

  • Осуществляет поиск динамических библиотек и копирует эти библиотеки в директорию, путь к которой указан в параметре PACK_DEPS_LIBS_PATH CMake-команд build_kos_qemu_image() и build_kos_hw_image(). (Чтобы найденные динамические библиотеки попали в образ накопителя, эта директория должна находиться в файловой системе, которая будет помещена в образ накопителя.)
  • Создает образ накопителя, который включает директорию с динамическими библиотеками.

    Чтобы создать образ накопителя, нужно использовать CMake-команду add_custom_command(). Цель, указанная в параметре DEPENDS CMake-команды add_custom_command(), означает создание образа накопителя. Цель, указанная в параметре PACK_DEPS_COPY_TARGET CMake-команд build_kos_qemu_image() и build_kos_hw_image(), означает копирование динамических библиотек. Чтобы образ накопителя был создан только после завершения копирования динамических библиотек, нужно использовать CMake-команду add_dependencies().

  • Добавляет образ накопителя в образ решения.

    Чтобы добавить образ накопителя в образ решения, нужно указать полный путь к образу накопителя в параметре IMAGE_FILES CMake-команд build_kos_qemu_image() и build_kos_hw_image().

В начало
[Topic shared_libraries_adding_to_image]