תחילת העבודה עם Sandboxed API

בדף הזה נסביר איך ליצור ספריית C/C++ משלכם עם ארגז חול באמצעות Sandboxed API‏ (SAPI). אפשר להיעזר בו לצד הדוגמאות והתיעוד של הקוד בקובצי הכותרת.

יחסי תלות ב-Build

צריך להתקין במערכת את יחסי התלות הבאים:

  • ליבת Linux עם תמיכה ב-UTS, ב-IPC, במשתמש, ב-PID ובמרחבי שמות ברשת
  • כותרות של ממשקי API במרחב המשתמש של Linux
  • כדי לקמפל את הקוד: GCC 6 (מומלצת גרסה 7 ומעלה) או Clang 7 (או גרסה גבוהה יותר)
  • ליצירה אוטומטית של קובצי כותרת: Clang Python Bindings
  • ‫Python 3.5 ואילך
  • Bazel מגרסה 2.2.0 ואילך או CMake מגרסה 3.12 ואילך.
    • ‫CMake בלבד: GNU Make או גרסה של כותרות הספריות libcap וכלי בנייה כמו Ninja (מומלץ).

שימוש ב-Bazel

‫Bazel היא מערכת הבנייה המומלצת והכי קלה לשילוב.

במסמכי התיעוד שלנו אנחנו משתמשים במהדר Clang. אם אתם צריכים שרשרת כלים ספציפית (למשל, קומפיילר, linker וכו'), תוכלו לעיין במסמכי Bazel כדי לקבל מידע על שינוי שרשרת הכלים של הקומפיילר שמוגדרת כברירת מחדל.

‫Debian 10 ‏ (Buster)

כדי להתקין יחסי תלות של build:

echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \
  sudo tee /etc/apt/sources.list.d/bazel.list
wget -qO - https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
sudo apt-get update
sudo apt-get install -qy build-essential linux-libc-dev bazel python3 \
  python3-pip libclang-dev
pip3 install clang

Gentoo

אפשרויות ליבה נדרשות:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

כדי להתקין יחסי תלות של build:

emerge dev-util/bazel dev-python/typing dev-python/clang-python

שימוש ב-CMake

CMake היא מערכת פופולרית בקוד פתוח ליצירת קובצי פרויקט עבור כלי בנייה כמו Ninja או Make.

‫Debian 10 ‏ (Buster)

כדי להתקין יחסי תלות של build:

sudo apt-get install -qy build-essential linux-libc-dev cmake ninja-build \
  python3 python3-pip libclang-dev libcap-dev
pip3 install absl-py clang

Gentoo

אפשרויות ליבה נדרשות:

General setup  --->
-*- Namespaces support
[*]   UTS namespace
[*]   IPC namespace
[*]   User namespace (EXPERIMENTAL)
[*]   PID Namespaces
[*]   Network namespace

כדי להתקין יחסי תלות של build:

emerge sys-kernel/linux-headers dev-util/cmake dev-util/ninja \
dev-python/clang-python

תהליך הפיתוח

כדי להפעיל ארגז חול לספריית C/C++‎, צריך להכין שני פריטים לפרויקט:

יכול להיות שאתם מכירים את zlib מהדוגמאות של Sandbox2. בדוגמה הזו, תוכנית שלמה (zpipe.c) הוכנסה לארגז חול. בשלבים הבאים נסביר איך להשתמש ב-SAPI כדי להפעיל את ספריית zlib בארגז חול ולהשתמש בספרייה שמופעלת בארגז חול.

1. החלטה אילו פונקציות נדרשות

אם בודקים את קוד המארח של zlib ‏(main_zlib.cc), אפשר לראות שהפונקציונליות של הכלי היא לקרוא נתונים מ-stdin ולהשתמש בפונקציה deflate() של zlib כדי לדחוס את הנתונים עד שסמן EOF נקרא. בסך הכול, התוכנית משתמשת בשלוש פונקציות מ-zlib:

  • deflateInit_(): לאתחול לדחיסה
  • deflate(): כדי לבצע את פעולת הדחיסה על נתח הנתונים
  • deflateEnd(): כדי לסיים את הדחיסה ולפנות מבני נתונים שהוקצו באופן דינמי

בדוגמה מהחיים האמיתיים, תצטרכו לבדוק את ספריית C/C++ ולהחליט אילו פונקציות נחוצות. אחת האפשרויות היא להתחיל עם קוד המארח ולהשתמש בספרייה ללא ארגז חול. בשלב השני, אפשר ליצור את הספרייה בתוך ארגז חול ולהתאים את קוד המארח לשימוש בקריאות לפונקציות בתוך ארגז החול.

2. כתיבת כלל הבנייה של ספריית ה-SAPI

אחרי שמזהים את שלוש פונקציות zlib שנדרשות מספריית zlib בסביבת ארגז חול, אפשר להגדיר את כלל הבנייה בקובץ BUILD. אפשר למצוא את התיעוד של כלל ה-build‏ sapi_library בדף Build Rules.

בקטע הקוד הבא מוצגת ההגדרה של zlib SAPI לדוגמה.sapi_library באמצעות המאפיין 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, שבה נעשה שימוש במבנה SAPI: sapi::v::Struct<sapi::zlib::z_stream> strm;

סוג התבנית (sapi::zlib::z_stream) הוא דוגמה טובה לקוד שנוצר אוטומטית על ידי כלל הבנייה.

פרטים נוספים זמינים בדף המשתנים.

ביצוע קריאות ל-API

כדי להתקשר אל defalteInit_, אל deflate או אל deflateEnd, צריך להשתמש באובייקט SAPI. אם תבחרו להשתמש בגישת ה'שינוי', תצטרכו לוודא שפרמטרי הפונקציה תואמים לערכים הצפויים.

דוגמה לכל אחת מהקריאות ב-zlib example:

  • 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 Transaction עושה צעד נוסף וחוזרת אוטומטית על תהליכים שנכשלו.

פרטים נוספים זמינים בדף SAPI Transactions.

דוגמאות

בקטע Examples אפשר למצוא כמה ספריות שכבר הוכנו על ידי צוות SAPI.