reproc (Redirected Process) ist eine plattformübergreifende C/C++-Bibliothek, die das Starten, Stoppen und die Kommunikation mit externen Programmen vereinfacht. Der Hauptanwendungsfall besteht darin, Befehlszeilenanwendungen direkt aus C- oder C++-Code auszuführen und deren Ausgabe abzurufen.
reproc besteht aus zwei Bibliotheken: reproc und reproc++. reproc ist eine C99-Bibliothek, die den eigentlichen Code für die Arbeit mit externen Programmen enthält. reproc++ ist von reproc abhängig und passt seine API an eine idiomatische C++11-API an. Außerdem werden einige Extras hinzugefügt, die die Arbeit mit externen Programmen aus C++ vereinfachen.
#include <reproc/run.h>
int main ( void )
{
const char * args [] = { "echo" , "Hello, world!" , NULL };
return reproc_run ( args , ( reproc_options ) { 0 });
}
Wenn Sie nach dem Lesen der Readme-Datei und der Dokumentation Fragen haben, können Sie entweder ein Problem melden oder Fragen direkt im Reproduktionskanal stellen.
Hinweis: Für die Erstellung der Reproduktion ist CMake 3.12 oder höher erforderlich.
Es gibt mehrere Möglichkeiten, die Reproduktion in Ihr Projekt zu integrieren. Eine Möglichkeit besteht darin, reproc mithilfe von CMake als Teil Ihres Projekts zu erstellen. Dazu müssen wir zunächst den Reproc-Quellcode in das Projekt übernehmen. Dies kann mit einer der folgenden Optionen erfolgen:
FetchContent
API verwenden, um die Reproduktion herunterzuladen, wenn Sie CMake ausführen. Ein Beispiel finden Sie unter https://cliutils.gitlab.io/modern-cmake/chapters/projects/fetch.html.Nachdem Sie den Quellcode von reproc in Ihr Projekt eingebunden haben, kann er wie folgt aus der Stammdatei CMakeLists.txt erstellt werden:
add_subdirectory (< path -to-reproc>) # For example: add_subdirectory(external/reproc)
CMake-Optionen können vor dem Aufruf add_subdirectory
angegeben werden:
set (REPROC++ ON )
add_subdirectory (< path -to-reproc>)
Hinweis: Wenn die Option bereits in einem früheren CMake-Lauf zwischengespeichert wurde, müssen Sie den Cache von CMake leeren, um den neuen Standardwert anzuwenden.
Weitere Informationen zum Konfigurieren des Reproc-Builds finden Sie unter CMake-Optionen.
Sie können sich auch auf eine installierte Version von reproc verlassen. Sie können reproc entweder selbst erstellen und installieren oder reproc über einen Paketmanager installieren. reproc ist in den folgenden Paket-Repositories verfügbar:
Wenn die Verwendung eines Paketmanagers keine Option ist, können Sie Reproc aus der Quelle erstellen und installieren (CMake 3.13+):
cmake -B build
cmake --build build
cmake --install build
Aktivieren Sie die Option REPROC_TEST
und erstellen Sie das test
um die Tests auszuführen (CMake 3.13+):
cmake -B build -DREPROC_TEST=ON
cmake --build build
cmake --build build --target test
Nach der Installation von reproc muss Ihr Build-System es finden. reproc stellt sowohl CMake-Konfigurationsdateien als auch pkg-config-Dateien bereit, um die Suche nach einer Reproc-Installation mit CMake bzw. pkg-config zu vereinfachen. Beachten Sie, dass reproc und reproc++ separate Bibliotheken sind und daher auch separate Konfigurationsdateien haben. Stellen Sie sicher, dass Sie nach dem suchen, den Sie verwenden möchten.
So finden Sie eine installierte Version von reproc mit CMake:
find_package (reproc) # Find reproc.
find_package (reproc++) # Find reproc++.
Nachdem Sie reproc als Teil Ihres Projekts erstellt oder eine installierte Version von reproc gefunden haben, können Sie in Ihrer CMakeLists.txt-Datei wie folgt einen Link dazu erstellen:
target_link_libraries (myapp reproc) # Link against reproc.
target_link_libraries (myapp reproc++) # Link against reproc++.
Ab Meson 0.53.2 kann reproc als CMake-Unterprojekt in Meson-Build-Skripten eingebunden werden. Weitere Informationen finden Sie unter https://mesonbuild.com/CMake-module.html.
Standardmäßig besteht für reproc eine Abhängigkeit von pthreads auf POSIX-Systemen ( -pthread
) und eine Abhängigkeit von Winsock 2.2 auf Windows-Systemen ( -lws2_32
). CMake und pkg-config verarbeiten diese Abhängigkeiten automatisch.
Der Build von reproc kann mit den folgenden CMake-Optionen konfiguriert werden:
REPROC++
: Reproc++ erstellen (Standard: ${REPROC_DEVELOP}
)
REPROC_TEST
: Tests erstellen (Standard: ${REPROC_DEVELOP}
)
Führen Sie die Tests aus, indem Sie die test
ausführen, die sich nach dem Erstellen von Reproc im Build-Verzeichnis befindet.
REPROC_EXAMPLES
: Build-Beispiele (Standard: ${REPROC_DEVELOP}
)
Die resultierenden Binärdateien befinden sich nach der Erstellung der Reproduktion im Beispielordner jedes Projektunterverzeichnisses im Build-Verzeichnis.
REPROC_OBJECT_LIBRARIES
: CMake-Objektbibliotheken erstellen (Standard: ${REPROC_DEVELOP}
)
Dies ist nützlich, um reproc direkt in eine andere Bibliothek einzubinden. Wenn Sie reproc als statische oder gemeinsam genutzte Bibliothek erstellen, muss diese zusammen mit der konsumierenden Bibliothek installiert werden, was die Verteilung der konsumierenden Bibliothek erschwert. Bei Verwendung von Objektbibliotheken werden die Objektdateien von reproc direkt in die konsumierende Bibliothek eingebunden und es ist keine zusätzliche Installation erforderlich.
Hinweis: Die Objektbibliotheken von reproc werden erst ab CMake 3.14 korrekt verknüpft.
Hinweis: Diese Option überschreibt BUILD_SHARED_LIBS
.
REPROC_INSTALL
: Installationsregeln generieren (Standard: ON
, sofern REPROC_OBJECT_LIBRARIES
nicht aktiviert ist)
REPROC_INSTALL_CMAKECONFIGDIR
: Installationsverzeichnis der CMake-Konfigurationsdateien (Standard: ${CMAKE_INSTALL_LIBDIR}/cmake
)
REPROC_INSTALL_PKGCONFIG
: pkg-config-Dateien installieren (Standard: ON
)
REPROC_INSTALL_PKGCONFIGDIR
: Installationsverzeichnis für pkg-config-Dateien (Standard: ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
REPROC_MULTITHREADED
: pthread_sigmask
verwenden und mit der Thread-Bibliothek des Systems verknüpfen (Standard: ON
)
REPROC_DEVELOP
: Konfigurieren Sie die Standardwerte der Optionen für die Entwicklung (Standard: OFF
sofern die Umgebungsvariable REPROC_DEVELOP
nicht festgelegt ist).REPROC_SANITIZERS
: Mit Desinfektionsmitteln erstellen (Standard: ${REPROC_DEVELOP}
)REPROC_TIDY
: clang-tidy beim Erstellen ausführen (Standard: ${REPROC_DEVELOP}
)REPROC_WARNINGS
: Compiler-Warnungen aktivieren (Standard: ${REPROC_DEVELOP}
)REPROC_WARNINGS_AS_ERRORS
: -Werror oder Äquivalent zu den Kompilierungsflags und clang-tidy hinzufügen (Standard: OFF
) Jede Funktion und Klasse ist ausführlich in ihrer Header-Datei dokumentiert. Beispiele finden Sie im Beispiel-Unterverzeichnis von reproc und reproc++.
Bei einem Fehler geben die meisten Funktionen in der Reproc-API einen negativen Fehlercode im Stil errno
(POSIX) oder GetLastError
(Windows) zurück. Für umsetzbare Fehler stellt reproc Konstanten ( REPROC_ETIMEDOUT
, REPROC_EPIPE
, ...) bereit, die zum Abgleich mit dem Fehler verwendet werden können, ohne dass plattformspezifischer Code geschrieben werden muss. Um eine Zeichenfolgendarstellung eines Fehlers zu erhalten, übergeben Sie diese an reproc_strerror
.
Die API von reproc++ ist in den Fehlercodemechanismus der C++-Standardbibliothek integriert ( std::error_code
und std::error_condition
). Die meisten Methoden in der API von reproc++ geben std::error_code
Werte zurück, die den tatsächlich aufgetretenen Systemfehler enthalten. Sie können diese Fehlercodes mit Werten aus der Enumeration std::errc
testen.
Weitere Informationen zum Umgang mit Fehlern bei der Verwendung von reproc finden Sie in den Beispielen.
Notiz:
Sowohl die APIs reproc als auch reproc++ akzeptieren options
, die eine oder mehrere stop
wie terminate
oder kill
definieren können. Aus diesem Grund spiegelt der Fehlercode keinen Fehler wider, wenn der untergeordnete Prozess mithilfe eines Signals auf POSIX beendet oder beendet wird.
Es ist Sache des nachgelagerten Projekts, neben Fehlercodes auch Statuscodes zu interpretieren , die unerwartetes Verhalten widerspiegeln (siehe dieses Beispiel).
Rufen Sie dieselbe Operation für denselben untergeordneten Prozess nicht gleichzeitig von mehr als einem Thread aus auf. Beispiel: Das Lesen und Schreiben in einen untergeordneten Prozess aus verschiedenen Threads ist in Ordnung, aber das gleichzeitige Warten auf denselben untergeordneten Prozess aus zwei verschiedenen Threads führt zu Problemen.
(POSIX) Es wird dringend empfohlen, waitpid
nicht für PIDs von Prozessen aufzurufen, die durch reproc gestartet wurden.
reproc verwendet waitpid
um zu warten, bis ein Prozess beendet wurde. Leider kann waitpid
nicht zweimal im selben Prozess aufgerufen werden. Das bedeutet, dass reproc_wait
nicht korrekt funktioniert, wenn waitpid
bereits zuvor für einen untergeordneten Prozess außerhalb von reproc aufgerufen wurde.
Es wird dringend empfohlen, sicherzustellen, dass jeder untergeordnete Prozess tatsächlich mit reproc_wait
oder reproc_stop
beendet wird.
Unter POSIX ist ein untergeordneter Prozess, der beendet wurde, ein Zombie-Prozess, bis der übergeordnete Prozess mit waitpid
auf ihn wartet. Ein Zombie-Prozess beansprucht Ressourcen und kann als Ressourcenleck angesehen werden. Daher ist es wichtig, sicherzustellen, dass alle Prozesse rechtzeitig korrekt beendet werden.
Es wird dringend empfohlen, zu versuchen, einen untergeordneten Prozess zu beenden, indem Sie darauf warten, dass er beendet wird, oder indem Sie reproc_terminate
aufrufen, bevor Sie auf reproc_kill
zurückgreifen.
Bei Verwendung von reproc_kill
erhält der untergeordnete Prozess keine Chance, eine Bereinigung durchzuführen, was zu einem Verlust von Ressourcen führen könnte. Das Hauptproblem dieser Lecks besteht darin, dass der untergeordnete Prozess seine eigenen untergeordneten Prozesse nicht stoppen kann. Versuchen Sie immer, einen untergeordneten Prozess normal beenden zu lassen, indem Sie reproc_terminate
aufrufen, bevor Sie reproc_kill
aufrufen. reproc_stop
ist eine praktische Hilfsfunktion, mit der mehrere Stoppaktionen hintereinander mit dazwischen liegenden Zeitüberschreitungen ausgeführt werden können.
(POSIX) Es wird dringend empfohlen, das SIGPIPE
Signal im übergeordneten Prozess zu ignorieren.
Unter POSIX beendet das Schreiben in eine geschlossene stdin-Pipe eines untergeordneten Prozesses standardmäßig den übergeordneten Prozess mit dem SIGPIPE
Signal. Um dies zu vermeiden, muss das SIGPIPE
Signal im übergeordneten Prozess ignoriert werden. Wenn das SIGPIPE
-Signal ignoriert wird, gibt reproc_write
beim Schreiben in eine geschlossene Standardpipe wie erwartet REPROC_EPIPE
zurück.
Während reproc_terminate
es dem untergeordneten Prozess ermöglicht, eine Bereinigung durchzuführen, ist es Sache des untergeordneten Prozesses, nach sich selbst korrekt aufzuräumen. reproc sendet nur ein Beendigungssignal an den untergeordneten Prozess. Der untergeordnete Prozess selbst ist für die Bereinigung seiner eigenen untergeordneten Prozesse und anderer Ressourcen verantwortlich.
(Windows) reproc_kill
garantiert nicht, dass ein untergeordneter Prozess unter Windows sofort beendet wird. Weitere Informationen finden Sie im Abschnitt „Bemerkungen“ in der Dokumentation der Windows-Funktion TerminateProcess
, die reproc zum Beenden untergeordneter Prozesse unter Windows verwendet.
Über reproc erzeugte untergeordnete Prozesse erben ein einzelnes zusätzliches Dateihandle, das verwendet wird, um auf das Beenden des untergeordneten Prozesses zu warten. Wenn der untergeordnete Prozess dieses Dateihandle manuell schließt, erkennt Reproc fälschlicherweise, dass der untergeordnete Prozess beendet wurde. Wenn dieses Handle weiter von anderen Prozessen geerbt wird, die den untergeordneten Prozess überleben, erkennt reproc, dass der untergeordnete Prozess noch läuft, selbst wenn er beendet wurde. Wenn Daten in dieses Handle geschrieben werden, erkennt Reproc auch fälschlicherweise, dass der untergeordnete Prozess beendet wurde.
(Windows) Es ist nicht möglich zu erkennen, ob ein untergeordneter Prozess seinen stdout- oder stderr-Stream schließt, bevor er beendet wird. Der übergeordnete Prozess wird erst dann benachrichtigt, wenn der Ausgabestrom eines untergeordneten Prozesses geschlossen wird, sobald dieser untergeordnete Prozess beendet wird.
(Windows) reproc geht davon aus, dass Windows Sockets erstellt, die als Dateisystemobjekte verwendet werden können. Genauer gesagt sollte für die von WSASocket
zurückgegebenen Standard-Sockets das Flag XP1_IFS_HANDLES
gesetzt sein. Dies ist möglicherweise nicht der Fall, wenn auf einem Windows-Computer externe LSP-Anbieter installiert sind. In diesem Fall empfehlen wir, die Software zu entfernen, die die zusätzlichen Dienstanbieter bereitstellt, da diese veraltet sind und nicht mehr verwendet werden sollten (siehe https://docs.microsoft.com/en-us/windows/win32/winsock/ Kategorisieren von mehrschichtigen Dienstanbietern und Anwendungen).