בדף הזה נסביר איך ליצור ספריית C/C++ משלכם עם ארגז חול באמצעות Sandboxed API (SAPI). אפשר להיעזר בו לצד הדוגמאות והתיעוד של הקוד בקובצי הכותרת.
יחסי תלות של גרסאות build
צריך להתקין במערכת את יחסי התלות הבאים:
- ליבת Linux עם תמיכה במרחבי שמות של UTS, IPC, user, PID ורשת
- כותרות של API במרחב המשתמש של Linux
- כדי לקמפל את הקוד: GCC 6 (מומלצת גרסה 7 ומעלה) או Clang 7 (או גרסה מתקדמת יותר)
- ליצירה אוטומטית של קובצי כותרות: Clang Python Bindings
- Python 3.5 ואילך
- Bazel בגרסה 2.2.0 או CMake בגרסה 3.12 ואילך.
שימוש ב-Bazel
Bazel היא מערכת ה-build המומלצת והכי קל לשלב אותה.
במסמכים שלנו אנחנו משתמשים במהדר Clang. אם אתם צריכים toolchain ספציפי (למשל קומפיילר, מקשר וכו'), עיינו במסמכי התיעוד של Bazel כדי ללמוד איך לשנות את ה-toolchain של הקומפיילר שמוגדר כברירת מחדל.
Debian 10 (Buster)
כדי להתקין יחסי תלות ב-build:
echo "deb http://storage.googleapis.com/bazel-apt stable jdk1.8" | \ sudo tee /etc/apt/sources.list.d/bazel.listwget -qO - https://releases.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
כדי להתקין יחסי תלות ב-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-devpip3 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++, צריך להכין שני פריטים לפרויקט:
- Sandboxed Library
- קוד המארח, שישתמש בפונקציונליות שחשופה על ידי הספרייה בארגז החול. SAPI ייצור בשבילכם את אובייקט SAPI ו-RPC Stub באופן אוטומטי במהלך תהליך ה-build.
יכול להיות שאתם מכירים את zlib מהדוגמאות של Sandbox2. בדוגמה הזו, תוכנית שלמה (zpipe.c) הוכנסה לארגז חול. בשלבים הבאים נסביר איך להשתמש ב-SAPI כדי להפעיל את ספריית zlib בארגז חול ולהשתמש בספרייה שבארגז החול.
1. החלטה אילו פונקציות נדרשות
אם תסתכלו על קוד המארח של zlib (main_zlib.cc), תוכלו לראות שהפונקציונליות של הכלי היא לקרוא נתונים מ-stdin ולהשתמש בפונקציה deflate() של zlib כדי לדחוס את הנתונים עד לקריאת סמן EOF.
בסך הכול, התוכנית משתמשת בשלוש פונקציות מ-zlib:
-
deflateInit_(): כדי לאתחל לדחיסה -
deflate(): כדי לבצע את פעולת הדחיסה על נתח הנתונים -
deflateEnd(): כדי להפסיק את הדחיסה ולפנות מבני נתונים שהוקצו באופן דינמי
בדוגמה מהחיים האמיתיים, הייתם בודקים את ספריית C/C++ ומחליטים אילו פונקציות נדרשות. אסטרטגיה אפשרית היא להתחיל עם קוד המארח ולהשתמש בספרייה ללא ארגז חול. בשלב השני, אפשר ליצור את הספרייה בתוך ארגז חול ולהתאים את קוד המארח כך שישתמש בבקשות להפעלת פונקציות בתוך ארגז החול.
2. כתיבת כלל ה-Build של sapi_library
אחרי שזיהיתם את שלוש הפונקציות של zlib שנדרשות מספריית zlib בארגז החול, אתם יכולים להגדיר את כלל ה-build בקובץ BUILD. המסמכים של כלל ה-build sapi_library נמצאים בדף Build Rules.
בקטע הקוד הבא מוצגת ההגדרה של sapi_library לדוגמה של zlib SAPI. באמצעות המאפיין 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.
בדוגמה הזו נעשה שימוש בהגדרת ברירת המחדל של ארגז החול שסופקה על ידי DefaultConfig (sapi::SandboxConfig::DefaultConfig()).
3. כתיבה או שינוי של קוד המארח
עכשיו צריך לשלב את ספריית ה-SAPI שנוצרה בקוד המארח.
יצירת ארגז החול
משתמשים ב-sapi::zlib::ZlibSandbox sandbox; כדי ליצור אובייקט בארגז החול.
משתמשים ב-sapi::zlib::ZlibApi api(&sandbox); כדי ליצור מופע של אובייקט SAPI, וכך להפוך את הפונקציות בארגז החול לזמינות לשימוש.
כדי להתאים אישית את המדיניות, הדגלים, משתני הסביבה או המגבלות של ארגז החול, מתחילים מ-sapi::SandboxConfig::DefaultConfig(), משנים את השדות הרלוונטיים (באמצעות sapi::Sandbox2Config::DefaultPolicyBuilder(), sapi::SandboxConfig::DefaultFlags() או sapi::SandboxConfig::DefaultEnvironmentVariables() כדי לשמור על הגדרות הבסיס) ומעבירים את sapi::SandboxConfig ל-constructor של ארגז החול:
sapi::SandboxConfig config = sapi::SandboxConfig::DefaultConfig();
config.sandbox2.policy = sapi::Sandbox2Config::DefaultPolicyBuilder()
.AddFile("/path/to/file")
.BuildOrDie();
auto flags = sapi::SandboxConfig::DefaultFlags();
flags["my_flag"] = "value";
config.command_line_flags = std::move(flags);
sapi::zlib::ZlibSandbox sandbox(std::move(config));
שימוש בסוגי SAPI
סוגי SAPI הם סוגים מיוחדים בצורה של מחלקות C++ ש-SAPI מספק כי לפעמים סוגי C רגילים לא יפעלו.
השימוש הראשון בסוג SAPI מופיע בהצהרה על strm, שבה נעשה שימוש ב-SAPI Struct: sapi::v::Struct<sapi::zlib::z_stream> strm;
סוג התבנית (sapi::zlib::z_stream) הוא דוגמה טובה לקוד שנוצר באופן אוטומטי על ידי כלל ה-build.
פרטים נוספים זמינים בדף המשתנים.
ביצוע קריאות ל-API
כדי להתקשר למספר defalteInit_, deflate או deflateEnd, משתמשים באובייקט SAPI. אם אתם מחליטים להשתמש בגישת change, אתם צריכים לוודא שהפרמטרים של הפונקציה תואמים לערכים הצפויים.
דוגמה לכל אחת מהקריאות בדוגמה של 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 Transaction יש שלב נוסף שבו המערכת חוזרת באופן אוטומטי על תהליכים שנכשלו.
לפרטים נוספים, אפשר לעיין בדף SAPI Transactions.
דוגמאות
בקטע Examples יש כמה ספריות שהצוות של SAPI כבר הכין.