reproc (العملية المعاد توجيهها) هي مكتبة C/C++ مشتركة بين الأنظمة الأساسية تعمل على تبسيط بدء البرامج الخارجية وإيقافها والتواصل معها. حالة الاستخدام الرئيسية هي تنفيذ تطبيقات سطر الأوامر مباشرة من كود C أو C++ واسترداد مخرجاتها.
يتكون reproc من مكتبتين: reproc و reproc ++. reproc هي مكتبة C99 تحتوي على الكود الفعلي للعمل مع البرامج الخارجية. يعتمد reproc++ على reproc ويقوم بتكييف واجهة برمجة التطبيقات (API) الخاصة به مع واجهة برمجة تطبيقات C++ 11 الاصطلاحية. كما أنه يضيف بعض الإضافات التي تعمل على تبسيط العمل مع البرامج الخارجية من لغة C++.
#include <reproc/run.h>
int main ( void )
{
const char * args [] = { "echo" , "Hello, world!" , NULL };
return reproc_run ( args , ( reproc_options ) { 0 });
}
إذا كانت لديك أي أسئلة بعد قراءة الملف التمهيدي والوثائق، فيمكنك إما طرح مشكلة أو طرح أسئلة مباشرة في قناة reproc gitter.
ملاحظة: يتطلب بناء النسخ CMake 3.12 أو أعلى.
هناك طرق متعددة للحصول على التكرار في مشروعك. إحدى الطرق هي بناء reproc كجزء من مشروعك باستخدام CMake. للقيام بذلك، علينا أولاً الحصول على كود المصدر reproc في المشروع. يمكن القيام بذلك باستخدام أي من الخيارات التالية:
FetchContent
API لتنزيل reproc عند تشغيل CMake. راجع https://cliutils.gitlab.io/modern-cmake/chapters/projects/fetch.html للحصول على مثال.بعد تضمين الكود المصدري لـ reproc في مشروعك، يمكن إنشاؤه من الملف CMakeLists.txt الجذر كما يلي:
add_subdirectory (< path -to-reproc>) # For example: add_subdirectory(external/reproc)
يمكن تحديد خيارات CMake قبل استدعاء add_subdirectory
:
set (REPROC++ ON )
add_subdirectory (< path -to-reproc>)
ملاحظة: إذا تم بالفعل تخزين الخيار مؤقتًا في تشغيل CMake سابق، فسيتعين عليك مسح ذاكرة التخزين المؤقت لـ CMake لتطبيق القيمة الافتراضية الجديدة.
لمزيد من المعلومات حول تكوين بناء reproc، راجع خيارات CMake.
يمكنك أيضًا الاعتماد على إصدار مثبت من reproc. يمكنك إما إنشاء reproc وتثبيته بنفسك أو تثبيت reproc عبر مدير الحزم. يتوفر reproc في مستودعات الحزم التالية:
إذا لم يكن استخدام مدير الحزم خيارًا متاحًا، فيمكنك إنشاء نسخة احتياطية وتثبيتها من المصدر (CMake 3.13+):
cmake -B build
cmake --build build
cmake --install build
قم بتمكين خيار REPROC_TEST
وقم ببناء هدف test
لتشغيل الاختبارات (CMake 3.13+):
cmake -B build -DREPROC_TEST=ON
cmake --build build
cmake --build build --target test
بعد تثبيت reproc، سيتعين على نظام البناء الخاص بك العثور عليه. يوفر reproc كلاً من ملفات تكوين CMake وملفات pkg-config لتبسيط العثور على تثبيت reproc باستخدام CMake وpkg-config على التوالي. لاحظ أن reproc وreproc++ مكتبتان منفصلتان ونتيجة لذلك لهما ملفات تكوين منفصلة أيضًا. تأكد من البحث عن الشخص الذي تريد استخدامه.
للعثور على إصدار مثبت من reproc باستخدام CMake:
find_package (reproc) # Find reproc.
find_package (reproc++) # Find reproc++.
بعد إنشاء reproc كجزء من مشروعك أو العثور على إصدار مثبت من reproc، يمكنك الارتباط به من داخل ملف CMakeLists.txt كما يلي:
target_link_libraries (myapp reproc) # Link against reproc.
target_link_libraries (myapp reproc++) # Link against reproc++.
بدءًا من الإصدار Meson 0.53.2 وما بعده، يمكن تضمين reproc كمشروع فرعي لـ CMake في البرامج النصية لبناء Meson. راجع https://mesonbuild.com/CMake-module.html لمزيد من المعلومات.
بشكل افتراضي، يعتمد reproc على pthreads على أنظمة POSIX ( -pthread
) ويعتمد على Winsock 2.2 على أنظمة Windows ( -lws2_32
). يتعامل كل من CMake وpkg-config مع هذه التبعيات تلقائيًا.
يمكن تكوين بناء reproc باستخدام خيارات CMake التالية:
REPROC++
: بناء reproc++ (الافتراضي: ${REPROC_DEVELOP}
)
REPROC_TEST
: بناء الاختبارات (الافتراضي: ${REPROC_DEVELOP}
)
قم بإجراء الاختبارات عن طريق تشغيل test
الثنائي الذي يمكن العثور عليه في دليل البناء بعد إنشاء reproc.
REPROC_EXAMPLES
: إنشاء الأمثلة (الافتراضي: ${REPROC_DEVELOP}
)
سيتم وضع الثنائيات الناتجة في مجلد الأمثلة لكل دليل فرعي للمشروع في دليل الإنشاء بعد إنشاء النسخ.
REPROC_OBJECT_LIBRARIES
: إنشاء مكتبات كائنات CMake (الافتراضي: ${REPROC_DEVELOP}
)
يعد هذا مفيدًا لتضمين repro مباشرة في مكتبة أخرى. عند بناء reproc كمكتبة ثابتة أو مشتركة، يجب تثبيتها بجانب المكتبة المستهلكة مما يجعل توزيع المكتبة المستهلكة أكثر صعوبة. عند استخدام مكتبات الكائنات، يتم تضمين ملفات كائنات reproc مباشرة في المكتبة المستهلكة ولا يلزم أي تثبيت إضافي.
ملاحظة: سيتم ربط مكتبات كائنات reproc بشكل صحيح فقط من CMake 3.14 وما بعده.
ملاحظة: يتجاوز هذا الخيار BUILD_SHARED_LIBS
.
REPROC_INSTALL
: إنشاء قواعد التثبيت (الافتراضي: ON
ما لم يتم تمكين REPROC_OBJECT_LIBRARIES
)
REPROC_INSTALL_CMAKECONFIGDIR
: دليل تثبيت ملفات تكوين CMake (الافتراضي: ${CMAKE_INSTALL_LIBDIR}/cmake
)
REPROC_INSTALL_PKGCONFIG
: تثبيت ملفات pkg-config (الافتراضي: ON
)
REPROC_INSTALL_PKGCONFIGDIR
: دليل تثبيت ملفات pkg-config (الافتراضي: ${CMAKE_INSTALL_LIBDIR}/pkgconfig
)
REPROC_MULTITHREADED
: استخدم pthread_sigmask
واربطه بمكتبة سلاسل الرسائل الخاصة بالنظام (الافتراضي: ON
)
REPROC_DEVELOP
: تكوين القيم الافتراضية للخيار للتطوير (الافتراضي: OFF
ما لم يتم تعيين متغير البيئة REPROC_DEVELOP
)REPROC_SANITIZERS
: البناء باستخدام المطهرات (الافتراضي: ${REPROC_DEVELOP}
)REPROC_TIDY
: تشغيل clang-tidy عند البناء (الافتراضي: ${REPROC_DEVELOP}
)REPROC_WARNINGS
: تمكين تحذيرات المترجم (الافتراضي: ${REPROC_DEVELOP}
)REPROC_WARNINGS_AS_ERRORS
: إضافة -خطأ أو ما يعادله إلى علامات الترجمة و clang-tidy (الافتراضي: OFF
) يتم توثيق كل وظيفة وفئة على نطاق واسع في ملف الرأس الخاص بها. يمكن العثور على الأمثلة في دليل الأمثلة الفرعي لـ reproc و reproc++.
في حالة الفشل، تقوم معظم الوظائف في واجهة برمجة التطبيقات الخاصة بـ reproc بإرجاع رمز خطأ سلبي لنمط errno
(POSIX) أو GetLastError
(Windows). بالنسبة للأخطاء القابلة للتنفيذ، يوفر reproc ثوابت ( REPROC_ETIMEDOUT
, REPROC_EPIPE
, ...) يمكن استخدامها لمطابقة الخطأ دون الحاجة إلى كتابة تعليمات برمجية خاصة بالمنصة. للحصول على تمثيل سلسلة لخطأ ما، قم بتمريره إلى reproc_strerror
.
تتكامل واجهة برمجة التطبيقات الخاصة بـ reproc++ مع آلية رموز الأخطاء في مكتبة C++ القياسية ( std::error_code
و std::error_condition
). تُرجع معظم الطرق في واجهة برمجة التطبيقات الخاصة بـ reproc++ قيم std::error_code
التي تحتوي على خطأ النظام الفعلي الذي حدث. يمكنك اختبار رموز الخطأ هذه باستخدام قيم من التعداد std::errc
.
راجع الأمثلة لمزيد من المعلومات حول كيفية التعامل مع الأخطاء عند استخدام reproc.
ملحوظة:
تأخذ كل من واجهات برمجة تطبيقات reproc وreproc++ وسيطة options
التي قد تحدد واحدًا أو أكثر من إجراءات stop
مثل terminate
أو kill
. ولهذا السبب، إذا تم إنهاء العملية الفرعية أو إيقافها باستخدام إشارة على POSIX، فلن يعكس رمز الخطأ خطأً.
الأمر متروك للمشروع النهائي لتفسير رموز الحالة التي تعكس سلوكيات غير متوقعة إلى جانب رموز الخطأ (انظر هذا المثال).
لا تستدعي نفس العملية على نفس العملية الفرعية من أكثر من مؤشر ترابط واحد في نفس الوقت. على سبيل المثال: القراءة والكتابة إلى عملية فرعية من سلاسل رسائل مختلفة أمر جيد ولكن انتظار نفس العملية الفرعية من خيطين مختلفين في نفس الوقت سيؤدي إلى حدوث مشكلات.
(POSIX) يوصى بشدة بعدم استدعاء waitpid
على معرفات العمليات التي بدأت بواسطة reproc.
يستخدم reproc waitpid
للانتظار حتى تنتهي العملية. لسوء الحظ، لا يمكن استدعاء waitpid
مرتين في نفس العملية. هذا يعني أن reproc_wait
لن يعمل بشكل صحيح إذا تم استدعاء waitpid
بالفعل في عملية فرعية مسبقًا خارج reproc.
يوصى بشدة بالتأكد من خروج كل عملية فرعية باستخدام reproc_wait
أو reproc_stop
.
في POSIX، العملية الفرعية التي خرجت هي عملية زومبي حتى تنتظرها العملية الأصلية باستخدام waitpid
. تستهلك عملية الزومبي الموارد ويمكن اعتبارها بمثابة تسرب للموارد، لذا من المهم التأكد من خروج جميع العمليات بشكل صحيح وفي الوقت المناسب.
يوصى بشدة بمحاولة إنهاء عملية فرعية عن طريق انتظار خروجها أو عن طريق استدعاء reproc_terminate
قبل اللجوء إلى reproc_kill
.
عند استخدام reproc_kill
لا تحصل العملية الفرعية على فرصة لإجراء التنظيف مما قد يؤدي إلى تسرب الموارد. ومن أهم هذه التسريبات أن العملية الفرعية لن تكون قادرة على إيقاف العمليات الفرعية الخاصة بها. حاول دائمًا السماح للعملية الفرعية بالخروج بشكل طبيعي عن طريق استدعاء reproc_terminate
قبل استدعاء reproc_kill
. reproc_stop
هي وظيفة مساعدة مفيدة يمكن استخدامها لتنفيذ إجراءات توقف متعددة على التوالي مع انتهاء المهلات بينهما.
(POSIX) يوصى بشدة بتجاهل إشارة SIGPIPE
في العملية الأصلية.
في POSIX، ستؤدي الكتابة إلى أنبوب stdin مغلق لعملية فرعية إلى إنهاء العملية الأصلية بإشارة SIGPIPE
افتراضيًا. لتجنب ذلك، يجب تجاهل إشارة SIGPIPE
في العملية الأصلية. إذا تم تجاهل إشارة SIGPIPE
، فسيُرجع reproc_write
REPROC_EPIPE
كما هو متوقع عند الكتابة إلى أنبوب stdin مغلق.
بينما يسمح reproc_terminate
للعملية الفرعية بإجراء التنظيف، فإن الأمر متروك للعملية الفرعية للتنظيف بشكل صحيح بعدها. يرسل reproc فقط إشارة إنهاء إلى العملية الفرعية. العملية الفرعية نفسها مسؤولة عن تنظيف العمليات الفرعية والموارد الأخرى الخاصة بها.
(Windows) reproc_kill
غير مضمون لقتل العملية الفرعية فورًا على Windows. لمزيد من المعلومات، اقرأ قسم الملاحظات في وثائق وظيفة Windows TerminateProcess
التي تستخدمها reproc لإيقاف العمليات التابعة على Windows.
ترث العمليات الفرعية الناتجة عبر reproc مؤشر ملف إضافيًا واحدًا يُستخدم لانتظار خروج العملية الفرعية. إذا أغلقت العملية الفرعية مؤشر الملف هذا يدويًا، فسوف تكتشف عملية reproc بشكل خاطئ أن العملية الفرعية قد انتهت. إذا تم توريث هذا المقبض من خلال عمليات أخرى تتجاوز العملية الفرعية، فسوف تكتشف عملية reproc أن العملية الفرعية لا تزال قيد التشغيل حتى لو تم الخروج منها. إذا تمت كتابة البيانات إلى هذا المقبض، فسوف تكتشف عملية reproc بشكل خاطئ أيضًا خروج العملية الفرعية.
(Windows) ليس من الممكن اكتشاف ما إذا كانت العملية الفرعية تغلق تدفق stdout أو stderr الخاص بها قبل الخروج. سيتم إخطار العملية الأصلية فقط بإغلاق دفق إخراج العملية الفرعية بمجرد خروج تلك العملية الفرعية.
(Windows) يفترض reproc أن Windows يقوم بإنشاء مآخذ توصيل يمكن استخدامها ككائنات نظام الملفات. وبشكل أكثر تحديدًا، يجب أن تحتوي مآخذ التوصيل الافتراضية التي يتم إرجاعها بواسطة WSASocket
على مجموعة إشارات XP1_IFS_HANDLES
. قد لا يكون هذا هو الحال إذا كان هناك موفري LSP خارجيين مثبتين على جهاز يعمل بنظام Windows. إذا كان الأمر كذلك، فإننا نوصي بإزالة البرنامج الذي يوفر موفري الخدمة الإضافيين نظرًا لأنه تم إهمالهم ويجب عدم استخدامه بعد الآن (راجع https://docs.microsoft.com/en-us/windows/win32/winsock/ تصنيف مقدمي الخدمات والتطبيقات).