Nesta página, você vai aprender a criar sua própria biblioteca C/C++ no modo sandbox com a API Sandbox (SAPI). Use-o como um guia, junto com os exemplos e a documentação do código nos arquivos principais.
Dependências de build
As seguintes dependências precisam ser instaladas no sistema:
- Kernel do Linux com suporte a namespaces de UTS, IPC, usuário, PID e rede
- Cabeçalhos da API Linux userspace
- Para compilar o código: GCC 6 (preferencialmente versão 7 ou mais recente) ou Clang 7 (ou mais recente).
- Para geração automática de arquivos de cabeçalho: vinculações do Clang Python
- Python 3.5 ou posterior
- Bazel versão 2.2.0 ou CMake versão 3.12 ou mais recente.
Como usar o Bazel
O Bazel é o sistema de build recomendado e é o mais fácil de integrar.
Nossa documentação usa o compilador do Clang. Se você precisar de um conjunto de ferramentas específico (por exemplo, compilador, vinculador etc.), consulte a documentação do Bazel para ver informações sobre como alterar o conjunto de ferramentas do compilador padrão.
Debian 10 (Buster)
Para instalar dependências de build:
echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \ sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install -qy build-essential linux-libc-dev bazel python3 \ python3-pip libclang-dev
pip3 install clang
Gentoo
Opções do kernel necessárias:
General setup --->
-*- Namespaces support
[*] UTS namespace
[*] IPC namespace
[*] User namespace (EXPERIMENTAL)
[*] PID Namespaces
[*] Network namespace
Para instalar dependências de build:
emerge dev-util/bazel dev-python/typing dev-python/clang-python
Como usar o CMake
O CMake é um sistema conhecido de metabuild de código aberto que gera arquivos de projeto para ferramentas de build, como Ninja ou Make.
Debian 10 (Buster)
Para instalar dependências de build:
sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \ python3 python3-pip libclang-dev libcap-dev
pip3 install absl-py clang
Gentoo
Opções do kernel necessárias:
General setup --->
-*- Namespaces support
[*] UTS namespace
[*] IPC namespace
[*] User namespace (EXPERIMENTAL)
[*] PID Namespaces
[*] Network namespace
Para instalar dependências de build:
emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \
dev-python/clang-python
Processo de desenvolvimento
Para colocar uma biblioteca C/C++ no sandbox, você precisará preparar dois itens para seu projeto:
- A biblioteca no modo sandbox
- O código do host que vai usar a funcionalidade exposta pela sua biblioteca no modo sandbox. O SAPI vai gerar o objeto SAPI e o stub de RPC automaticamente durante o processo de compilação.
Você já deve conhecer o zlib dos exemplos de Sandbox2 (link em inglês) usado aqui: um programa inteiro (zpipe.c) foi colocado no sandbox. Nas etapas a seguir, você vai aprender a usar a SAPI para sandbox a biblioteca zlib e usar a biblioteca no modo sandbox.
1. Decidir quais funções são necessárias
Se você observar o código do host zlib (main_zlib.cc), verá que a funcionalidade da ferramenta é ler dados de stdin e usar a função deflate()
do zlib para compactar os dados até que um marcador EOF
seja lido. No total, o programa usa três funções do zlib:
deflateInit_()
: para inicializar para compactaçãodeflate()
: executar a operação de compactação no bloco de dados.deflateEnd()
: para encerrar a compactação e liberar as estruturas de dados alocadas dinamicamente
Em um exemplo real, você revisaria a biblioteca C/C++ e decidiria quais funções são necessárias. Uma estratégia possível é começar com o código de host e usar a biblioteca fora da sandbox. Em seguida, em uma segunda etapa, você pode gerar a biblioteca no modo sandbox e adaptar o código do host para usar as chamadas de função no sandbox.
2. Escrever a regra de build sapi_library
Depois de identificar as três funções zlib que são necessárias na biblioteca zlib no modo sandbox, você pode definir a regra de compilação no arquivo BUILD. A documentação da regra de build sapi_library
pode ser encontrada na página Regras de build.
O snippet de código abaixo mostra a definição sapi_library
para o exemplo zlib SAPI. Usando o atributo lib
, o Bazel é instruído a procurar a biblioteca zlib no arquivo WORKSPACE.
sapi_library(
name = "zlib-sapi",
srcs = [],
hdrs = [],
functions = [
"deflateInit_",
"deflate",
"deflateEnd",
],
lib = "@net_zlib//:zlib",
lib_name = "Zlib",
namespace = "sapi::zlib",
)
Como resultado, a biblioteca zlib no modo sandbox é gerada. A saída é o objeto SAPI que pode ser incluído no código do host e usado para se comunicar com a biblioteca em sandbox por chamadas RPC. A política de sandbox usada neste exemplo é a política padrão.
3. Escrever ou alterar o código de host
Agora é hora de incorporar a biblioteca SAPI gerada no código de host.
Criar o sandbox
Use sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create());
para criar um objeto de sandbox.
Use sapi::zlib::ZlibApi api(&sandbox);
para instanciar o objeto SAPI e disponibilizar as funções no sandbox para uso.
Usar tipos SAPI
Os tipos SAPI são tipos especiais na forma de classes C++ fornecidas pela SAPI porque, às vezes, os tipos C normais não funcionam.
O primeiro uso de um tipo SAPI pode ser observado na declaração de strm
, em que um Struct SAPI é usado: sapi::v::Struct<sapi::zlib::z_stream> strm;
O tipo de modelo (sapi::zlib::z_stream
) é um bom exemplo de código gerado automaticamente pela regra de criação.
Confira a página Variáveis para mais detalhes.
Fazer chamadas de API
Para fazer chamadas para defalteInit_
, deflate
ou deflateEnd
, use o objeto SAPI. Se você decidir usar a abordagem de "mudança", precisará garantir que os parâmetros da função correspondam aos valores esperados.
Um exemplo de cada uma das chamadas no exemplo de zlib (link em inglês):
api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION, version.PtrBefore(), sizeof(sapi::zlib::z_stream));
api.deflate(strm.PtrBoth(), flush);
api.deflateEnd(strm.PtrBoth()).IgnoreError();
Como usar transações SAPI
O SAPI isola o código de host da biblioteca em sandbox e permite que o autor da chamada reinicie ou cancele solicitações de processamento de dados problemáticas. A transação SAPI vai além e repete automaticamente os processos com falha.
Confira a página de transações SAPI para mais detalhes.
Exemplos
Em Exemplos, você encontra algumas bibliotecas já preparadas pela equipe de SAPI.