reproc (Redirected Process) é uma biblioteca C/C++ multiplataforma que simplifica a inicialização, parada e comunicação com programas externos. O principal caso de uso é executar aplicativos de linha de comando diretamente do código C ou C++ e recuperar sua saída.
reproc consiste em duas bibliotecas: reproc e reproc++. reproc é uma biblioteca C99 que contém o código real para trabalhar com programas externos. reproc++ depende de reproc e adapta sua API para uma API idiomática C++11. Ele também adiciona alguns extras que simplificam o trabalho com programas externos de C++.
#include <reproc/run.h>
int main ( void )
{
const char * args [] = { "echo" , "Hello, world!" , NULL };
return reproc_run ( args , ( reproc_options ) { 0 });
}
Se você tiver alguma dúvida depois de ler o leia-me e a documentação, você pode criar um problema ou fazer perguntas diretamente no canal reproc gitter.
Nota: A construção de reprodução requer CMake 3.12 ou superior.
Existem várias maneiras de obter reprodução em seu projeto. Uma maneira é construir o reproc como parte do seu projeto usando o CMake. Para fazer isso, primeiro precisamos colocar o código-fonte do reproc no projeto. Isso pode ser feito usando qualquer uma das seguintes opções:
FetchContent
para baixar o reproc ao executar o CMake. Consulte https://cliutils.gitlab.io/modern-cmake/chapters/projects/fetch.html para obter um exemplo.Depois de incluir o código-fonte do reproc em seu projeto, ele pode ser compilado a partir do arquivo raiz CMakeLists.txt da seguinte maneira:
add_subdirectory (< path -to-reproc>) # For example: add_subdirectory(external/reproc)
As opções do CMake podem ser especificadas antes de chamar add_subdirectory
:
set (REPROC++ ON )
add_subdirectory (< path -to-reproc>)
Nota: Se a opção já tiver sido armazenada em cache em uma execução anterior do CMake, você terá que limpar o cache do CMake para aplicar o novo valor padrão.
Para obter mais informações sobre como configurar a compilação do reproc, consulte Opções do CMake.
Você também pode depender de uma versão instalada do reproc. Você pode construir e instalar o reproc sozinho ou instalar o reproc por meio de um gerenciador de pacotes. reproc está disponível nos seguintes repositórios de pacotes:
Se usar um gerenciador de pacotes não for uma opção, você pode compilar e instalar o reproc a partir do código-fonte (CMake 3.13+):
cmake -B build
cmake --build build
cmake --install build
Habilite a opção REPROC_TEST
e construa o alvo test
para executar os testes (CMake 3.13+):
cmake -B build -DREPROC_TEST=ON
cmake --build build
cmake --build build --target test
Depois de instalar o reproc, seu sistema de compilação terá que encontrá-lo. reproc fornece arquivos de configuração CMake e arquivos pkg-config para simplificar a localização de uma instalação reproc usando CMake e pkg-config respectivamente. Observe que reproc e reproc++ são bibliotecas separadas e, como resultado, também possuem arquivos de configuração separados. Certifique-se de pesquisar aquele que deseja usar.
Para encontrar uma versão instalada do reproc usando CMake:
find_package (reproc) # Find reproc.
find_package (reproc++) # Find reproc++.
Depois de criar o reproc como parte do seu projeto ou encontrar uma versão instalada do reproc, você pode vinculá-lo a partir do arquivo CMakeLists.txt da seguinte maneira:
target_link_libraries (myapp reproc) # Link against reproc.
target_link_libraries (myapp reproc++) # Link against reproc++.
Do Meson 0.53.2 em diante, o reproc pode ser incluído como um subprojeto CMake nos scripts de construção do Meson. Consulte https://mesonbuild.com/CMake-module.html para obter mais informações.
Por padrão, reproc depende de pthreads em sistemas POSIX ( -pthread
) e de Winsock 2.2 em sistemas Windows ( -lws2_32
). CMake e pkg-config lidam com essas dependências automaticamente.
A compilação do reproc pode ser configurada usando as seguintes opções do CMake:
REPROC++
: Construa reproc++ (padrão: ${REPROC_DEVELOP}
)
REPROC_TEST
: testes de compilação (padrão: ${REPROC_DEVELOP}
)
Execute os testes executando o binário test
que pode ser encontrado no diretório de construção após a construção do reproc.
REPROC_EXAMPLES
: exemplos de construção (padrão: ${REPROC_DEVELOP}
)
Os binários resultantes estarão localizados na pasta de exemplos de cada subdiretório do projeto no diretório de construção após a construção do reproc.
REPROC_OBJECT_LIBRARIES
: Construa bibliotecas de objetos CMake (padrão: ${REPROC_DEVELOP}
)
Isso é útil para incluir diretamente o reproc em outra biblioteca. Ao construir o reproc como uma biblioteca estática ou compartilhada, ele deve ser instalado junto com a biblioteca de consumo, o que dificulta a distribuição da biblioteca de consumo. Ao usar bibliotecas de objetos, os arquivos de objetos do reproc são incluídos diretamente na biblioteca de consumo e nenhuma instalação extra é necessária.
Nota: as bibliotecas de objetos do reproc só serão vinculadas corretamente a partir do CMake 3.14.
Nota: Esta opção substitui BUILD_SHARED_LIBS
.
REPROC_INSTALL
: Gera regras de instalação (padrão: ON
a menos que REPROC_OBJECT_LIBRARIES
esteja habilitado)
REPROC_INSTALL_CMAKECONFIGDIR
: diretório de instalação dos arquivos de configuração do CMake (padrão: ${CMAKE_INSTALL_LIBDIR}/cmake
)
REPROC_INSTALL_PKGCONFIG
: instala arquivos pkg-config (padrão: ON
)
REPROC_INSTALL_PKGCONFIGDIR
: diretório de instalação dos arquivos pkg-config (padrão: ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
REPROC_MULTITHREADED
: Use pthread_sigmask
e vincule-se à biblioteca de threads do sistema (padrão: ON
)
REPROC_DEVELOP
: configura os valores padrão da opção para desenvolvimento (padrão: OFF
a menos que a variável de ambiente REPROC_DEVELOP
esteja definida)REPROC_SANITIZERS
: Construído com desinfetantes (padrão: ${REPROC_DEVELOP}
)REPROC_TIDY
: Execute clang-tidy ao construir (padrão: ${REPROC_DEVELOP}
)REPROC_WARNINGS
: Habilita avisos do compilador (padrão: ${REPROC_DEVELOP}
)REPROC_WARNINGS_AS_ERRORS
: Adicione -Werror ou equivalente aos sinalizadores de compilação e clang-tidy (padrão: OFF
) Cada função e classe é documentada extensivamente em seu arquivo de cabeçalho. Exemplos podem ser encontrados no subdiretório de exemplos de reproc e reproc++.
Em caso de falha, a maioria das funções na API do reproc retorna um código de erro no estilo errno
negativo (POSIX) ou GetLastError
(Windows). Para erros acionáveis, reproc fornece constantes ( REPROC_ETIMEDOUT
, REPROC_EPIPE
, ...) que podem ser usadas para corresponder ao erro sem a necessidade de escrever código específico da plataforma. Para obter uma representação em string de um erro, passe-a para reproc_strerror
.
A API do reproc++ se integra ao mecanismo de códigos de erro da biblioteca padrão C++ ( std::error_code
e std::error_condition
). A maioria dos métodos na API do reproc++ retorna valores std::error_code
que contêm o erro real do sistema que ocorreu. Você pode testar esses códigos de erro usando valores da enumeração std::errc
.
Consulte os exemplos para obter mais informações sobre como lidar com erros ao usar o reproc.
Observação:
Ambas as APIs reproc e reproc++ aceitam argumentos options
que podem definir uma ou mais ações stop
, como terminate
ou kill
. Por esse motivo, se o processo filho estiver sendo encerrado ou eliminado usando um sinal no POSIX, o código de erro não refletirá um erro.
Cabe ao projeto downstream interpretar os códigos de status que refletem comportamentos inesperados juntamente com os códigos de erro (veja este exemplo).
Não chame a mesma operação no mesmo processo filho de mais de um thread ao mesmo tempo. Por exemplo: ler e gravar em um processo filho de threads diferentes é bom, mas esperar no mesmo processo filho de dois threads diferentes ao mesmo tempo resultará em problemas.
(POSIX) É altamente recomendável não chamar waitpid
em pids de processos iniciados por reproc.
reproc usa waitpid
para esperar até que um processo seja encerrado. Infelizmente, waitpid
não pode ser chamado duas vezes no mesmo processo. Isso significa que reproc_wait
não funcionará corretamente se waitpid
já tiver sido chamado em um processo filho antes, fora do reproc.
É altamente recomendável garantir que cada processo filho realmente saia usando reproc_wait
ou reproc_stop
.
No POSIX, um processo filho que saiu é um processo zumbi até que o processo pai o aguarde usando waitpid
. Um processo zumbi consome recursos e pode ser visto como um vazamento de recursos, por isso é importante garantir que todos os processos sejam encerrados corretamente e em tempo hábil.
É altamente recomendável tentar encerrar um processo filho aguardando sua saída ou chamando reproc_terminate
antes de recorrer a reproc_kill
.
Ao usar reproc_kill
o processo filho não tem a chance de realizar a limpeza, o que pode resultar no vazamento de recursos. O principal desses vazamentos é que o processo filho não será capaz de interromper seus próprios processos filhos. Sempre tente deixar um processo filho sair normalmente chamando reproc_terminate
antes de chamar reproc_kill
. reproc_stop
é uma função auxiliar útil que pode ser usada para executar várias ações de parada consecutivas com tempos limite entre elas.
(POSIX) É altamente recomendável ignorar o sinal SIGPIPE
no processo pai.
No POSIX, gravar em um canal stdin fechado de um processo filho encerrará o processo pai com o sinal SIGPIPE
por padrão. Para evitar isso, o sinal SIGPIPE
deve ser ignorado no processo pai. Se o sinal SIGPIPE
for ignorado, reproc_write
retornará REPROC_EPIPE
conforme esperado ao gravar em um canal stdin fechado.
Embora reproc_terminate
permita que o processo filho execute a limpeza, cabe ao processo filho limpar corretamente após si mesmo. reproc envia apenas um sinal de encerramento para o processo filho. O próprio processo filho é responsável por limpar seus próprios processos filhos e outros recursos.
(Windows) Não é garantido que reproc_kill
elimine um processo filho imediatamente no Windows. Para obter mais informações, leia a seção Comentários na documentação da função Windows TerminateProcess
que o reproc usa para eliminar processos filho no Windows.
Os processos filhos gerados por meio de reproc herdam um único identificador de arquivo extra que é usado para aguardar a saída do processo filho. Se o processo filho fechar esse identificador de arquivo manualmente, o reproc detectará erroneamente que o processo filho foi encerrado. Se esse identificador for herdado por outros processos que sobrevivem ao processo filho, o reproc detectará que o processo filho ainda está em execução, mesmo que tenha sido encerrado. Se os dados forem gravados nesse identificador, o reproc também detectará erroneamente que o processo filho foi encerrado.
(Windows) Não é possível detectar se um processo filho fecha seu fluxo stdout ou stderr antes de sair. O processo pai só será notificado de que o fluxo de saída de um processo filho for fechado quando o processo filho for encerrado.
(Windows) reproc pressupõe que o Windows cria soquetes que podem ser usados como objetos do sistema de arquivos. Mais especificamente, os soquetes padrão retornados por WSASocket
devem ter o sinalizador XP1_IFS_HANDLES
definido. Este pode não ser o caso se houver provedores LSP externos instalados em uma máquina Windows. Se for esse o caso, recomendamos remover o software que fornece os provedores de serviços extras, pois eles estão obsoletos e não devem mais ser usados (consulte https://docs.microsoft.com/en-us/windows/win32/winsock/ categorizando provedores de serviços e aplicativos em camadas).