reproc (กระบวนการเปลี่ยนเส้นทาง) เป็นไลบรารี C/C++ ข้ามแพลตฟอร์มที่ช่วยให้การเริ่มต้น การหยุด และการสื่อสารกับโปรแกรมภายนอกทำได้ง่ายขึ้น กรณีการใช้งานหลักคือการเรียกใช้แอปพลิเคชันบรรทัดคำสั่งโดยตรงจากโค้ด C หรือ C++ และดึงข้อมูลเอาต์พุต
reproc ประกอบด้วยสองไลบรารี: reproc และ reproc++ reproc เป็นไลบรารี C99 ที่มีโค้ดจริงสำหรับการทำงานกับโปรแกรมภายนอก reproc++ ขึ้นอยู่กับ reproc และปรับ API ให้เป็น 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 });
}
หากคุณมีคำถามใดๆ หลังจากอ่าน readme และเอกสารประกอบแล้ว คุณสามารถสร้างปัญหาหรือถามคำถามได้โดยตรงในช่อง reproc gitter
หมายเหตุ: การสร้างการจำลองต้องใช้ CMake 3.12 หรือสูงกว่า
มีหลายวิธีในการทำซ้ำโปรเจ็กต์ของคุณ วิธีหนึ่งคือการสร้าง reproc โดยเป็นส่วนหนึ่งของโปรเจ็กต์ของคุณโดยใช้ CMake ในการดำเนินการนี้ อันดับแรกเราต้องนำซอร์สโค้ดจำลองเข้ามาในโปรเจ็กต์ก่อน ซึ่งสามารถทำได้โดยใช้ตัวเลือกใดๆ ต่อไปนี้:
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 เพื่อใช้ค่าเริ่มต้นใหม่
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดค่าบิลด์ของการจำลอง โปรดดูตัวเลือก CMake
คุณยังสามารถพึ่งพาเวอร์ชัน reproc ที่ติดตั้งไว้ได้อีกด้วย คุณสามารถสร้างและติดตั้ง 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 เป็นต้นไป สามารถรวมการจำลองเป็นโปรเจ็กต์ย่อย 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
ซึ่งสามารถพบได้ในไดเร็กทอรี build หลังจากสร้าง reproc
REPROC_EXAMPLES
: สร้างตัวอย่าง (ค่าเริ่มต้น: ${REPROC_DEVELOP}
)
ไบนารีที่ได้จะอยู่ในโฟลเดอร์ตัวอย่างของแต่ละไดเร็กทอรีย่อยของโปรเจ็กต์ในไดเร็กทอรี build หลังจากสร้าง reproc
REPROC_OBJECT_LIBRARIES
: สร้างไลบรารีวัตถุ CMake (ค่าเริ่มต้น: ${REPROC_DEVELOP}
)
สิ่งนี้มีประโยชน์ในการรวมการจำลองไว้ในไลบรารีอื่นโดยตรง เมื่อสร้าง reproc เป็นไลบรารีแบบสแตติกหรือแบบแบ่งใช้ จะต้องติดตั้งควบคู่ไปกับไลบรารีที่ใช้งานซึ่งทำให้การกระจายไลบรารีที่ใช้งานได้ยากขึ้น เมื่อใช้ไลบรารีอ็อบเจ็กต์ ไฟล์อ็อบเจ็กต์ของ reproc จะถูกรวมไว้ในไลบรารีที่ใช้งานโดยตรง และไม่จำเป็นต้องติดตั้งเพิ่มเติม
หมายเหตุ: ไลบรารีวัตถุของ reproc จะเชื่อมโยงอย่างถูกต้องตั้งแต่ CMake 3.14 เป็นต้นไป
หมายเหตุ: ตัวเลือกนี้จะแทนที่ BUILD_SHARED_LIBS
REPROC_INSTALL
: สร้างกฎการติดตั้ง (ค่าเริ่มต้น: ON
เว้นแต่จะเปิดใช้งาน REPROC_OBJECT_LIBRARIES
)
REPROC_INSTALL_CMAKECONFIGDIR
: ไดเร็กทอรีการติดตั้งไฟล์ CMake config (ค่าเริ่มต้น: ${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
: เพิ่ม -Werror หรือเทียบเท่ากับแฟล็กคอมไพล์และ clang-tidy (ค่าเริ่มต้น: OFF
) แต่ละฟังก์ชันและคลาสได้รับการบันทึกไว้อย่างกว้างขวางในไฟล์ส่วนหัว ตัวอย่างสามารถพบได้ในไดเร็กทอรีย่อยตัวอย่างของ reproc และ reproc++
เมื่อเกิดความล้มเหลว ฟังก์ชันส่วนใหญ่ใน API ของ reproc จะส่งกลับรหัสข้อผิดพลาดสไตล์ errno
(POSIX) หรือ GetLastError
(Windows) ที่เป็นค่าลบ สำหรับข้อผิดพลาดที่ดำเนินการได้ reproc จัดเตรียมค่าคงที่ ( REPROC_ETIMEDOUT
, REPROC_EPIPE
, ... ) ที่สามารถใช้เพื่อจับคู่กับข้อผิดพลาดโดยไม่ต้องเขียนโค้ดเฉพาะแพลตฟอร์ม หากต้องการรับการแสดงสตริงของข้อผิดพลาด ให้ส่งต่อไปที่ reproc_strerror
API ของ reproc++ ทำงานร่วมกับกลไกรหัสข้อผิดพลาดไลบรารีมาตรฐาน C++ ( std::error_code
และ std::error_condition
) วิธีการส่วนใหญ่ใน API ของ reproc++ ส่งคืน std::error_code
ที่มีข้อผิดพลาดของระบบจริงที่เกิดขึ้น คุณสามารถทดสอบกับรหัสข้อผิดพลาดเหล่านี้ได้โดยใช้ค่าจาก std::errc
enum
ดูตัวอย่างสำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการจัดการกับข้อผิดพลาดเมื่อใช้ reproc
บันทึก:
API ทั้ง reproc และ reproc++ รับอาร์กิวเมนต์ options
ที่อาจกำหนดการดำเนินการ stop
ตั้งแต่หนึ่งรายการขึ้นไป เช่น terminate
หรือ kill
ด้วยเหตุผลดังกล่าว หากกระบวนการลูกถูกยกเลิกหรือหยุดทำงานโดยใช้สัญญาณบน POSIX รหัสข้อผิดพลาดจะ ไม่ สะท้อนถึงข้อผิดพลาด
ขึ้นอยู่กับโครงการดาวน์สตรีมในการ ตีความ รหัสสถานะที่สะท้อนถึงพฤติกรรมที่ไม่คาดคิดควบคู่ไปกับรหัสข้อผิดพลาด (ดูตัวอย่างนี้)
อย่าเรียกการดำเนินการเดียวกันบนกระบวนการลูกเดียวกันจากมากกว่าหนึ่งเธรดในเวลาเดียวกัน ตัวอย่างเช่น: การอ่านและการเขียนกระบวนการลูกจากเธรดที่ต่างกันเป็นเรื่องปกติ แต่การรอกระบวนการลูกเดียวกันจากสองเธรดที่ต่างกันในเวลาเดียวกันจะส่งผลให้เกิดปัญหา
(POSIX) ขอแนะนำอย่างยิ่งว่าอย่าเรียก waitpid
บน pid ของกระบวนการที่เริ่มต้นโดย 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
ที่จำลองการใช้เพื่อฆ่ากระบวนการลูกบน Windows
กระบวนการลูกเกิดขึ้นผ่านการทำซ้ำสืบทอดการจัดการไฟล์พิเศษเพียงรายการเดียวซึ่งใช้เพื่อรอให้กระบวนการลูกออก ถ้ากระบวนการลูกปิดตัวจัดการไฟล์นี้ด้วยตนเอง reproc จะตรวจพบว่ากระบวนการลูกออกอย่างไม่ถูกต้อง ถ้าหมายเลขอ้างอิงนี้สืบทอดต่อไปโดยกระบวนการอื่นที่อยู่นานกว่ากระบวนการลูก reproc จะตรวจพบว่ากระบวนการลูกยังคงทำงานอยู่แม้ว่าจะมีออกแล้วก็ตาม ถ้าข้อมูลถูกเขียนไปยังหมายเลขอ้างอิงนี้ reproc จะตรวจพบว่ากระบวนการลูกออกอย่างไม่ถูกต้องด้วย
(Windows) ไม่สามารถตรวจพบได้ว่ากระบวนการลูกปิด stdout หรือ stderr สตรีมก่อนออกหรือไม่ กระบวนการหลักจะได้รับแจ้งว่าสตรีมเอาต์พุตของกระบวนการลูกถูกปิดเมื่อกระบวนการลูกนั้นออกเท่านั้น
(Windows) reproc ถือว่า Windows สร้างซ็อกเก็ตที่สามารถใช้เป็นออบเจ็กต์ระบบไฟล์ได้ โดยเฉพาะอย่างยิ่ง ซ็อกเก็ตเริ่มต้นที่ส่งคืนโดย WSASocket
ควรมีการตั้งค่าสถานะ XP1_IFS_HANDLES
กรณีนี้อาจไม่เกิดขึ้นหากมีการติดตั้งผู้ให้บริการ LSP ภายนอกบนเครื่อง Windows ในกรณีนี้ เราขอแนะนำให้ลบซอฟต์แวร์ที่ให้ผู้ให้บริการเพิ่มเติม เนื่องจากเลิกใช้แล้วและไม่ควรใช้อีกต่อไป (ดู https://docs.microsoft.com/en-us/windows/win32/winsock/ การจัดหมวดหมู่ผู้ให้บริการและแอปพลิเคชันแบบหลายชั้น)