На этой странице вы узнаете, как создать собственную изолированную библиотеку C/C++ с использованием изолированного API (SAPI). Используйте её в качестве руководства вместе с примерами и документацией по коду в заголовочных файлах.
Создание зависимостей
В системе должны быть установлены следующие зависимости:
- Ядро Linux с поддержкой пространств имен UTS, IPC, user, PID и network.
- Заголовки API пользовательского пространства Linux
- Для компиляции кода: GCC 6 (предпочтительно версия 7 или выше) или Clang 7 (или выше).
- Для автоматической генерации заголовочных файлов: Привязки Python для Clang
- Python 3.5 или более поздняя версия
- Версия Bazel 2.2.0 или CMake 3.12 или выше.
Использование Bazel
Bazel — рекомендуемая система сборки, и с ней проще всего интегрироваться.
В нашей документации используется компилятор Clang. Если вам требуется определенный набор инструментов (например, компилятор, компоновщик и т. д.), обратитесь к документации Bazel за информацией о том, как изменить набор инструментов компилятора по умолчанию.
Debian 10 (Buster)
Для установки зависимостей сборки:
echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \ sudo tee /etc/apt/sources.list.d/bazel.listwget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -sudo apt-get updatesudo apt-get install -qy build-essential linux-libc-dev bazel python3 \ python3-pip libclang-devpip3 install clang
Gentoo
Необходимые параметры ядра:
General setup --->
-*- Namespaces support
[*] UTS namespace
[*] IPC namespace
[*] User namespace (EXPERIMENTAL)
[*] PID Namespaces
[*] Network namespace
Для установки зависимостей сборки:
emerge dev-util/bazel dev-python/typing dev-python/clang-pythonИспользование CMake
CMake — это популярная система сборки с открытым исходным кодом, которая генерирует файлы проектов для таких инструментов сборки, как Ninja или Make .
Debian 10 (Buster)
Для установки зависимостей сборки:
sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \ python3 python3-pip libclang-dev libcap-devpip3 install absl-py clang
Gentoo
Необходимые параметры ядра:
General setup --->
-*- Namespaces support
[*] UTS namespace
[*] IPC namespace
[*] User namespace (EXPERIMENTAL)
[*] PID Namespaces
[*] Network namespace
Для установки зависимостей сборки:
emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \
dev-python/clang-pythonПроцесс разработки
Для изоляции библиотеки C/C++ от внешнего мира вам потребуется подготовить для своего проекта два элемента:
- Библиотека в песочнице
- Код хоста , который будет использовать функциональность, предоставляемую вашей изолированной библиотекой. SAPI автоматически сгенерирует для вас объект SAPI и заглушку RPC в процессе сборки.
Возможно, вам знакома библиотека zlib по примерам из Sandbox2, где целая программа ( zpipe.c ) была изолирована. В следующих шагах вы узнаете, как использовать SAPI для изоляции библиотеки zlib и использования изолированной библиотеки.
1. Определите, какие функции необходимы.
Если вы посмотрите на код хоста zlib ( main_zlib.cc ), вы увидите, что функциональность инструмента заключается в чтении данных из стандартного ввода и использовании функции deflate() из zlib для сжатия данных до тех пор, пока не будет считан маркер EOF . В общей сложности программа использует три функции из zlib:
-
deflateInit_(): Инициализация для сжатия -
deflate(): Выполняет операцию сжатия фрагмента данных. -
deflateEnd(): Завершает сжатие и освобождает динамически выделенные структуры данных.
В реальном примере вам нужно будет проанализировать библиотеку C/C++ и определить, какие функции необходимы. Возможная стратегия — начать с основного кода и использовать библиотеку без песочницы. Затем, на втором этапе, можно сгенерировать библиотеку в песочнице и адаптировать основной код для использования вызовов функций в песочнице.
2. Напишите правило сборки sapi_library.
После того, как вы определили три необходимые функции zlib из изолированной библиотеки zlib, вы можете определить правило сборки в файле BUILD . Документацию по правилу сборки sapi_library можно найти на странице «Правила сборки» .
Приведённый ниже фрагмент кода демонстрирует определение sapi_library для примера SAPI zlib. Используя атрибут lib , Bazel получает указание искать библиотеку zlib в файле WORKSPACE .
sapi_library(
name = "zlib-sapi",
srcs = [],
hdrs = [],
functions = [
"deflateInit_",
"deflate",
"deflateEnd",
],
lib = "@net_zlib//:zlib",
lib_name = "Zlib",
namespace = "sapi::zlib",
)
В результате генерируется изолированная библиотека zlib. Выходными данными является объект SAPI, который можно включить в код хоста и использовать для связи с изолированной библиотекой посредством вызовов RPC. В этом примере используется политика песочницы по умолчанию.
3. Напишите или измените код хоста.
Теперь пришло время интегрировать сгенерированную библиотеку SAPI в основной код.
Создайте песочницу
Используйте sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); для создания объекта песочницы.
Используйте sapi::zlib::ZlibApi api(&sandbox); для создания экземпляра объекта SAPI и, таким образом, сделайте функции, работающие в изолированной среде, доступными для использования.
Используйте типы SAPI.
Типы SAPI — это специальные типы в виде классов C++, предоставляемые SAPI, поскольку в некоторых случаях обычные типы C не будут работать.
Первое использование типа SAPI можно наблюдать в объявлении функции strm , где используется структура SAPI: sapi::v::Struct<sapi::zlib::z_stream> strm;
Тип шаблона ( sapi::zlib::z_stream ) — хороший пример кода, автоматически генерируемого правилом сборки.
Для получения более подробной информации ознакомьтесь со страницей «Переменные» .
Выполняйте вызовы API
Для вызова функций defalteInit_ , deflate или deflateEnd используйте объект SAPI. Если вы решите использовать подход с изменением, необходимо убедиться, что параметры функции соответствуют ожидаемым значениям.
Пример каждого из вызовов в примере с библиотекой zlib :
api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION, version.PtrBefore(), sizeof(sapi::zlib::z_stream));
api.deflate(strm.PtrBoth(), flush);
api.deflateEnd(strm.PtrBoth()).IgnoreError();
Использование транзакций SAPI
SAPI изолирует код хоста от изолированной библиотеки и предоставляет вызывающей стороне возможность перезапускать или прерывать проблемные запросы на обработку данных. SAPI Transaction идет еще дальше и автоматически повторяет неудачные процессы.
Для получения более подробной информации ознакомьтесь со страницей транзакций SAPI .
Примеры
В разделе «Примеры» вы найдете несколько библиотек, уже подготовленных командой SAPI.