ในหน้านี้ คุณจะได้เรียนรู้วิธีสร้างไลบรารี C/C++ ที่อยู่ในแซนด์บ็อกซ์ของคุณเองด้วย Sandboxed API (SAPI) โดยใช้เป็นแนวทางควบคู่ไปกับ ตัวอย่างและเอกสารประกอบของโค้ดใน ไฟล์ส่วนหัว
การพึ่งพิงบิวด์
คุณต้องติดตั้งการพึ่งพิงต่อไปนี้ในระบบ
- เคอร์เนล Linux ที่รองรับเนมสเปซ UTS, IPC, ผู้ใช้, PID และเครือข่าย
- ส่วนหัว API ของพื้นที่ผู้ใช้ Linux
- หากต้องการคอมไพล์โค้ด ให้ใช้ GCC 6 (แนะนำให้ใช้เวอร์ชัน 7 ขึ้นไป) หรือ Clang 7 (ขึ้นไป)
- หากต้องการสร้างไฟล์ส่วนหัวโดยอัตโนมัติ ให้ใช้ Clang Python Bindings
- Python 3.5 ขึ้นไป
- Bazel เวอร์ชัน 2.2.0 หรือ CMake เวอร์ชัน 3.12 ขึ้นไป
การใช้ Bazel
เราขอแนะนำให้ใช้ Bazel เป็นระบบบิวด์ เนื่องจากผสานรวมได้ง่ายที่สุด
เอกสารประกอบของเราใช้คอมไพเลอร์ Clang หากคุณต้องการ Toolchain ที่เฉพาะเจาะจง (เช่น คอมไพเลอร์ ลิงเกอร์ ฯลฯ) โปรดดูเอกสารประกอบของ Bazelเพื่อ ดูข้อมูลเกี่ยวกับวิธีเปลี่ยน Toolchain คอมไพเลอร์เริ่มต้น
Debian 10 (Buster)
วิธีติดตั้งการพึ่งพิงบิวด์
echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \ sudo tee /etc/apt/sources.list.d/bazel.listwget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -sudo apt-get updatesudo apt-get install -qy build-essential linux-libc-dev bazel python3 \ python3-pip libclang-devpip3 install clang
Gentoo
ตัวเลือกเคอร์เนลที่จำเป็น
General setup --->
-*- Namespaces support
[*] UTS namespace
[*] IPC namespace
[*] User namespace (EXPERIMENTAL)
[*] PID Namespaces
[*] Network namespace
วิธีติดตั้งการพึ่งพิงบิวด์
emerge dev-util/bazel dev-python/typing dev-python/clang-pythonการใช้ CMake
CMake เป็นระบบเมตาบิลด์แบบโอเพนซอร์สยอดนิยมที่ สร้างไฟล์โปรเจ็กต์สำหรับเครื่องมือบิลด์ เช่น Ninja หรือ Make
Debian 10 (Buster)
วิธีติดตั้งการพึ่งพิงบิวด์
sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \ python3 python3-pip libclang-dev libcap-devpip3 install absl-py clang
Gentoo
ตัวเลือกเคอร์เนลที่จำเป็น
General setup --->
-*- Namespaces support
[*] UTS namespace
[*] IPC namespace
[*] User namespace (EXPERIMENTAL)
[*] PID Namespaces
[*] Network namespace
วิธีติดตั้งการพึ่งพิงบิวด์
emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \
dev-python/clang-pythonกระบวนการพัฒนา
หากต้องการใส่ไลบรารี C/C++ ไว้ในแซนด์บ็อกซ์ คุณจะต้องเตรียม 2 รายการสำหรับโปรเจ็กต์
- ไลบรารีที่อยู่ในแซนด์บ็อกซ์
- โค้ดโฮสต์ที่จะ ใช้ฟังก์ชันการทำงานที่ไลบรารีที่อยู่ในแซนด์บ็อกซ์เปิดเผย SAPI จะสร้าง ออบเจ็กต์ SAPI และ RPC Stub ให้คุณโดยอัตโนมัติในระหว่างกระบวนการบิลด์
คุณอาจคุ้นเคยกับ zlib จากตัวอย่าง Sandbox2 ที่นี่ ซึ่งมีการใส่โปรแกรมทั้งหมด (zpipe.c) ไว้ในแซนด์บ็อกซ์ ในขั้นตอนต่อไปนี้ คุณจะได้เรียนรู้วิธีใช้ SAPI เพื่อ ใส่ไลบรารี zlib ไว้ในแซนด์บ็อกซ์และ ใช้ประโยชน์จากไลบรารีที่อยู่ในแซนด์บ็อกซ์
1. ตัดสินใจว่าต้องการฟังก์ชันใด
หากดูโค้ดโฮสต์ zlib
(main_zlib.cc)
คุณจะเห็นว่าฟังก์ชันการทำงานของเครื่องมือคือการอ่านข้อมูลจาก stdin และใช้
ฟังก์ชัน deflate() ของ zlib เพื่อบีบอัดข้อมูลจนกว่าจะอ่านเครื่องหมาย EOF
โดยรวมแล้ว โปรแกรมจะใช้ฟังก์ชัน 3 ฟังก์ชันจาก zlib ดังนี้
deflateInit_(): เพื่อเริ่มต้นการบีบอัดdeflate(): เพื่อดำเนินการบีบอัดข้อมูลเป็นก้อนdeflateEnd(): เพื่อสิ้นสุดการบีบอัดและปล่อยโครงสร้างข้อมูลที่จัดสรรแบบไดนามิก
ในตัวอย่างการใช้งานจริง คุณจะต้องตรวจสอบไลบรารี C/C++ และตัดสินใจว่าต้องการฟังก์ชันใด กลยุทธ์ที่เป็นไปได้คือเริ่มต้นด้วยโค้ดโฮสต์และใช้ไลบรารีที่ไม่ได้อยู่ในแซนด์บ็อกซ์ จากนั้นในขั้นตอนที่ 2 คุณสามารถสร้างไลบรารีที่อยู่ในแซนด์บ็อกซ์และปรับโค้ดโฮสต์เพื่อใช้การเรียกฟังก์ชันที่อยู่ในแซนด์บ็อกซ์
2. เขียนกฎบิวด์ sapi_library
หลังจากระบุฟังก์ชัน zlib 3 ฟังก์ชันที่ต้องการจาก
ไลบรารี zlib ที่อยู่ในแซนด์บ็อกซ์แล้ว คุณสามารถกำหนดกฎบิวด์ใน
ไฟล์ BUILD
ได้ เอกสารประกอบสำหรับกฎบิวด์ sapi_library จะอยู่ในหน้า
กฎบิวด์
ข้อมูลโค้ดด้านล่างแสดงคำจำกัดความ sapi_library สำหรับตัวอย่าง SAPI zlib การใช้แอตทริบิวต์ lib จะสั่งให้ Bazel ค้นหาไลบรารี zlib ในไฟล์
WORKSPACE
sapi_library(
name = "zlib-sapi",
srcs = [],
hdrs = [],
functions = [
"deflateInit_",
"deflate",
"deflateEnd",
],
lib = "@net_zlib//:zlib",
lib_name = "Zlib",
namespace = "sapi::zlib",
)
ผลลัพธ์ที่ได้คือการสร้างไลบรารี zlib ที่อยู่ในแซนด์บ็อกซ์ เอาต์พุตคือออบเจ็กต์ SAPI ซึ่งสามารถรวมไว้ในโค้ดโฮสต์และใช้เพื่อสื่อสารกับไลบรารีที่อยู่ในแซนด์บ็อกซ์ผ่านการเรียก RPC นโยบายแซนด์บ็อกซ์ที่ใช้ในตัวอย่างนี้คือนโยบายเริ่มต้น
3. เขียนหรือเปลี่ยนโค้ดโฮสต์
ตอนนี้ได้เวลาผสานรวมไลบรารี SAPI ที่สร้างขึ้นลงในโค้ดโฮสต์แล้ว
สร้างแซนด์บ็อกซ์
ใช้ sapi::Sandbox sandbox(sapi::zlib::zlib_sapi_embed_create()); เพื่อสร้างออบเจ็กต์แซนด์บ็อกซ์
ใช้ sapi::zlib::ZlibApi api(&sandbox); เพื่อสร้างอินสแตนซ์ออบเจ็กต์ SAPI และทำให้
ฟังก์ชันที่อยู่ในแซนด์บ็อกซ์พร้อมใช้งาน
ใช้ประเภท SAPI
ประเภท SAPI เป็นประเภทพิเศษ ในรูปแบบคลาส C++ ที่ SAPI มีให้เนื่องจากบางครั้งประเภท C ปกติ จะใช้ไม่ได้
การใช้ประเภท SAPI ครั้งแรกจะเห็นได้ในการประกาศ strm ซึ่ง
มีการใช้ Struct SAPI ดังนี้ sapi::v::Struct<sapi::zlib::z_stream> strm;
ประเภทเทมเพลต (sapi::zlib::z_stream) เป็นตัวอย่างที่ดีของโค้ดที่สร้างขึ้นโดยอัตโนมัติโดยกฎบิวด์
ดูรายละเอียดเพิ่มเติมได้ที่หน้าตัวแปร
เรียก API
หากต้องการเรียก defalteInit_, deflate หรือ deflateEnd ให้ใช้ออบเจ็กต์ SAPI
หากตัดสินใจใช้แนวทาง "เปลี่ยน" คุณต้องตรวจสอบว่าพารามิเตอร์ฟังก์ชันตรงกับค่าที่คาดไว้
ตัวอย่างการเรียกแต่ละรายการในตัวอย่าง zlib:
api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION, version.PtrBefore(), sizeof(sapi::zlib::z_stream));
api.deflate(strm.PtrBoth(), flush);
api.deflateEnd(strm.PtrBoth()).IgnoreError();
การใช้ธุรกรรม SAPI
SAPI แยกโค้ดโฮสต์ออกจากไลบรารีที่อยู่ในแซนด์บ็อกซ์ และช่วยให้ผู้เรียกสามารถรีสตาร์ทหรือยกเลิกคำขอการประมวลผลข้อมูลที่มีปัญหาได้ ธุรกรรม SAPI ทำได้มากกว่านั้น โดยจะทำซ้ำกระบวนการที่ล้มเหลวโดยอัตโนมัติ
ดูรายละเอียดเพิ่มเติมได้ที่หน้าธุรกรรม SAPI
ตัวอย่าง
ในส่วนตัวอย่าง คุณจะเห็นไลบรารี 2-3 รายการ ที่ทีม SAPI เตรียมไว้แล้ว