ההנחיות הבאות יעזרו לכם לשפר את העמידות והאמינות של המודולים של הספקים. יש הרבה הנחיות שבעזרתן קל יותר לקבוע את סדר הטעינה הנכון של המודולים ואת הסדר שבו מנהלי ההתקנים צריכים לחפש מכשירים.
מודול יכול להיות ספרייה או מנהל.
מודולים של ספריות הן ספריות שמספקות ממשקי API לשימוש במודולים אחרים. בדרך כלל, המודולים האלה לא ספציפיים לחומרה. דוגמאות למודולים של ספריות כוללות מודול הצפנה מסוג AES, את המסגרת
remoteproc
שמתומללת כמודול ומודול של logbuffer. קוד המודול ב-module_init()
פועל כדי להגדיר מבני נתונים, אבל אף קוד אחר לא פועל אלא אם הוא מופעל על ידי מודול חיצוני.מודולים של מנהלי התקנים הם מנהלי התקנים שמאתרים מכשיר מסוג מסוים או מתחברים אליו. המודולים האלה ספציפיים לחומרה. דוגמאות למודול של מנהל התקן כוללות UART, PCIe וחומרה של מקודד וידאו. מודולי הדרייברים מופעלים רק כשהמכשיר המשויך אליהם נמצא במערכת.
אם המכשיר לא נמצא, קוד המודול היחיד שפועל הוא הקוד
module_init()
שמרשם את מנהל ההתקן במסגרת הליבה של מנהל ההתקן.אם המכשיר נמצא והדרייבר מצליח לחפש את המכשיר או לקשר אליו, יכול להיות שקוד אחר של המודול יפעל.
שימוש נכון ב-init וב-exit של המודול
מודולים של מנהלי התקנים חייבים לרשום מנהל התקנים ב-module_init()
ולבטל את הרישום של מנהל התקנים ב-module_exit()
. אחת מהדרכים לאכוף את ההגבלות האלה היא להשתמש במאקרו-עטיפה, כדי להימנע משימוש ישיר במאקרו module_init()
, *_initcall()
או module_exit()
.
למודולים שאפשר לפרוק, משתמשים ב-
module_subsystem_driver()
. דוגמאות:module_platform_driver()
,module_i2c_driver()
ו-module_pci_driver()
.במודולים שלא ניתן לפרוק, משתמשים ב-
builtin_subsystem_driver()
. דוגמאות:builtin_platform_driver()
,builtin_i2c_driver()
ו-builtin_pci_driver()
.
בחלק ממודולי הנהגים נעשה שימוש ב-module_init()
וב-module_exit()
כי הם רושמים יותר מנהג אחד. במודול של מנהל התקן שמשתמש ב-module_init()
וב-module_exit()
כדי לרשום כמה מנהלי התקנים, נסו לשלב את מנהלי ההתקנים למנהל התקן אחד. לדוגמה, אפשר להבדיל באמצעות המחרוזת compatible
או באמצעות נתוני ה-aux של המכשיר במקום לרשום מנהלי התקנים נפרדים.
לחלופין, אפשר לפצל את מודול הנהג לשני מודולים.
חריגות של פונקציות init ו-exit
מודולים של ספריות לא רושמים מנהלי התקנים והם פטורים מההגבלות על module_init()
ו-module_exit()
, כי יכול להיות שהם יצטרכו את הפונקציות האלה כדי להגדיר מבני נתונים, תורים של משימות או חוטי ליבה.
שימוש במאקרו MODULE_DEVICE_TABLE
מודולי מנהלי התקנים חייבים לכלול את המאקרו MODULE_DEVICE_TABLE
, שמאפשר למרחב המשתמש לקבוע את המכשירים שנתמכים על ידי מודול מנהל ההתקנים לפני טעינת המודול. מערכת Android יכולה להשתמש בנתונים האלה כדי לבצע אופטימיזציה של טעינת המודולים, למשל כדי למנוע טעינת מודולים למכשירים שלא נמצאים במערכת. דוגמאות לשימוש במאקרו מפורטות בקוד של מקור הנתונים.
הימנעות מחוסר התאמה של CRC עקב סוגי נתונים שהוגדרו מראש
לא כוללים קובצי כותרות כדי לקבל גישה לסוגים של נתונים שהוצהרו מראש.
אפשר להצהיר מראש על מבנים מסוימים, על יוניונים ועל סוגי נתונים אחרים שהוגדרו בקובץ כותרת (header-A.h
) בקובץ כותרת אחר (header-B.h
) שמשתמש בדרך כלל בצבעים למעקב אחרי סוגי הנתונים האלה. דפוס הקוד הזה מציין שהליבה מנסה בכוונה לשמור על מבנה הנתונים כפרטי למשתמשים של header-B.h
.
משתמשים ב-header-B.h
לא צריכים לכלול את header-A.h
כדי לגשת ישירות לרכיבים הפנימיים של מבני הנתונים האלה שהוצהרו מראש. הפעולה הזו גורמת לבעיות של אי-התאמה ב-CRC של CONFIG_MODVERSIONS
(שגורמות לבעיות תאימות ל-ABI) כשליבה אחרת (כמו ליבה של GKI) מנסה לטעון את המודול.
לדוגמה, struct fwnode_handle
מוגדר ב-include/linux/fwnode.h
, אבל הוא מוגדר מראש כ-struct fwnode_handle;
ב-include/linux/device.h
כי הליבה מנסה לשמור על הפרטיות של struct fwnode_handle
מפני המשתמשים של include/linux/device.h
. בתרחיש הזה, לא מוסיפים את #include <linux/fwnode.h>
למודול כדי לקבל גישה לחברים ב-struct fwnode_handle
. כל עיצוב שבו צריך לכלול קבצים כאלה של כותרות הוא סימן לדפוס עיצוב שגוי.
אין לגשת ישירות למבנים של הליבה של הליבה
גישה ישירה למבנים של נתוני הליבה או שינוי שלהם עלולה להוביל להתנהגות לא רצויה, כולל דליפות זיכרון, קריסות ופגיעה בתאימות לגרסאות ליבה עתידיות. מבנה נתונים הוא מבנה נתונים של ליבה אם הוא עומד באחד מהתנאים הבאים:
מבנה הנתונים מוגדר בקטע
KERNEL-DIR/include/
. לדוגמה,struct device
ו-struct dev_links_info
. מבני נתונים שמוגדרים ב-include/linux/soc
פטורים.מבנה הנתונים מוקצה או מופעל על ידי המודול, אבל הוא מוצג לליבה על ידי העברה, באופן עקיף (דרך מצביע ב-struct) או באופן ישיר, כקלט בפונקציה שיוצאת מהליבה. לדוגמה, מודול הנהג
cpufreq
מאתחלה אתstruct cpufreq_driver
ואז מעביר אותו כקלט ל-cpufreq_register_driver()
. אחרי הנקודה הזו, מודול הנהגcpufreq
לא אמור לשנות אתstruct cpufreq_driver
ישירות, כי קריאה ל-cpufreq_register_driver()
הופכת אתstruct cpufreq_driver
גלוי לליבה.מבנה הנתונים לא מופעל על ידי המודול. לדוגמה, הערך
struct regulator_dev
שהוחזר על ידיregulator_register()
.
גישה למבני הנתונים של הליבה רק דרך פונקציות שיוצאו על ידי הליבה או דרך פרמטרים שהועברו במפורש כקלט ל-hooks של ספקים. אם אין לכם API או ווקשן של ספק כדי לשנות חלקים ממבנה הנתונים של הליבה, סביר להניח שזה מכוון ואסור לשנות את מבנה הנתונים מהמודולים. לדוגמה, אין לשנות שדות בתוך struct device
או
struct device.links
.
כדי לשנות את
device.devres_head
, משתמשים בפונקציהdevm_*()
כמוdevm_clk_get()
,devm_regulator_get()
אוdevm_kzalloc()
.כדי לשנות שדות ב-
struct device.links
, צריך להשתמש ב-API של קישור המכשיר, כמוdevice_link_add()
אוdevice_link_del()
.
לא לנתח צמתים של devicetree עם מאפיין תואם
אם לצומת של עץ מכשיר (DT) יש מאפיין compatible
, המערכת מקצה לו struct device
באופן אוטומטי או כשמתבצעת קריאה ל-of_platform_populate()
בצומת האב של DT (בדרך כלל על ידי מנהל ההתקן של המכשיר ההורה). ברירת המחדל (למעט מכשירים מסוימים שהוגדרו מראש לתזמון) היא שלצומת DT עם מאפיין compatible
יש struct device
ומנהל התקן תואם של המכשיר. כל שאר החריגות כבר מטופלות על ידי הקוד של ה-upstream.
בנוסף, fw_devlink
(לשעבר of_devlink
) מתייחס לצמתים של DT עם המאפיין compatible
כמכשירים עם struct device
שהוקצה להם ונבדק על ידי מנהל התקן. אם לצומת DT יש מאפיין compatible
אבל לא מתבצע בדיקה של struct device
שהוקצה, fw_devlink
יכול לחסום את הבדיקה של מכשירי הצרכנים שלו או לחסום את הקריאות ל-sync_state()
במכשירי הספק שלו.
אם הנהג משתמש בפונקציה of_find_*()
(כמו of_find_node_by_name()
או of_find_compatible_node()
) כדי למצוא ישירות צומת DT שיש לו מאפיין compatible
, ולאחר מכן לנתח את צומת ה-DT הזה, צריך לתקן את המודול על ידי כתיבת מנהל מכשיר שיכול לבדוק את המכשיר או להסיר את המאפיין compatible
(אפשר לעשות זאת רק אם הוא לא הועבר ל-upstream). כדי לדון בחלופות, אפשר לפנות לצוות הליבה של Android בכתובת kernel-team@android.com ולהתכונן להצדיק את תרחישי השימוש שלכם.
שימוש ב-DT phandles לחיפוש ספקים
כשהדבר אפשרי, כדאי להפנות לספק באמצעות phandle (הפניה או מצביע לצומת DT) ב-DT. שימוש בקישור DT וב-phandle רגילים כדי להפנות לספקים מאפשר ל-fw_devlink
(לשעבר of_devlink
) לקבוע באופן אוטומטי יחסי תלות בין מכשירים על ידי ניתוח ה-DT בזמן הריצה. לאחר מכן, הליבה יכולה לבדוק את המכשירים באופן אוטומטי בסדר הנכון, וכך לבטל את הצורך בסדר טעינה של מודולים או ב-MODULE_SOFTDEP()
.
תרחיש מדור קודם (אין תמיכה ב-DT בליבה של ARM)
בעבר, לפני שתמיכת DT נוספה לליבות ARM, צרכנים כמו מכשירי מגע חיפשו ספקים כמו רגולטורים באמצעות מחרוזות ייחודיות ברחבי העולם.
לדוגמה, מנהל ה-PMIC של ACME יכול לרשום או לפרסם מספר רגולטורים (כמו acme-pmic-ldo1
עד acme-pmic-ldo10
), ומנהל מגע יכול לחפש רגולטור באמצעות regulator_get(dev, "acme-pmic-ldo10")
.
עם זאת, בלוח אחר, ה-LDO8 עשוי לספק את מכשיר המגע, וכך נוצרת מערכת מסורבלת שבה אותו מנהל התקן של המגע צריך לקבוע את מחרוזת החיפוש הנכונה לרגולטור לכל לוח שבו מכשיר המגע נמצא בשימוש.
התרחיש הנוכחי (תמיכה ב-DT בליבה של ARM)
אחרי שתמיכת DT נוספה לליבת ARM, הצרכנים יכולים לזהות ספקים ב-DT על ידי הפניה לצומת של עץ המכשיר של הספק באמצעות phandle.
הצרכנים יכולים גם לתת שם למשאב על סמך המטרה שלו, במקום על סמך מי שספק אותו. לדוגמה, מנהל ההתקן של המגע מהדוגמה הקודמת יכול להשתמש ב-regulator_get(dev, "core")
וב-regulator_get(dev, "sensor")
כדי לקבל את הספקים שמפעילים את הליבה והחיישן של מכשיר המגע. ה-DT המשויך למכשיר כזה דומה לדוגמת הקוד הבאה:
touch-device {
compatible = "fizz,touch";
...
core-supply = <&acme_pmic_ldo4>;
sensor-supply = <&acme_pmic_ldo10>;
};
acme-pmic {
compatible = "acme,super-pmic";
...
acme_pmic_ldo4: ldo4 {
...
};
...
acme_pmic_ldo10: ldo10 {
...
};
};
תרחיש הכי גרוע
חלק מהדריברים שהועברו מליבת ליבה ישנות יותר כוללים התנהגות מדור קודם ב-DT, שמשתמשת בחלק הגרוע ביותר מהתוכנית הקודמת ומאלצת אותה על התוכנית החדשה שנועדה להקל על הדברים. בדרייברים כאלה, מנהל ההתקן של הצרכן קורא את המחרוזת לשימוש בחיפוש באמצעות מאפיין DT ספציפי למכשיר, הספק משתמש במאפיין אחר ספציפי לספק כדי להגדיר את השם שישמש לרישום המשאב של הספק, ולאחר מכן הצרכן והספק ממשיכים להשתמש באותה סכימה ישנה של שימוש במחרוזות כדי לחפש את הספק. בתרחיש הזה, שמשלב את הכי גרוע משני העולמות:
מנהל ההתקן של המגע משתמש בקוד דומה לקוד הבא:
str = of_property_read(np, "fizz,core-regulator"); core_reg = regulator_get(dev, str); str = of_property_read(np, "fizz,sensor-regulator"); sensor_reg = regulator_get(dev, str);
ב-DT נעשה שימוש בקוד דומה לזה:
touch-device { compatible = "fizz,touch"; ... fizz,core-regulator = "acme-pmic-ldo4"; fizz,sensor-regulator = "acme-pmic-ldo4"; }; acme-pmic { compatible = "acme,super-pmic"; ... ldo4 { regulator-name = "acme-pmic-ldo4" ... }; ... acme_pmic_ldo10: ldo10 { ... regulator-name = "acme-pmic-ldo10" }; };
לא לשנות שגיאות API של מסגרת
ממשקי API של מסגרות, כמו regulator
, clocks
, irq
, gpio
, phys
ו-extcon
, מחזירים את הערך -EPROBE_DEFER
כערך החזרה של שגיאה כדי לציין שהמכשיר מנסה לבצע בדיקה אבל לא יכול לעשות זאת כרגע, וליבה צריכה לנסות שוב לבצע את הבדיקה מאוחר יותר. כדי לוודא שהפונקציה .probe()
במכשיר תיכשל כצפוי במקרים כאלה, אל מחליפים את ערך השגיאה או ממפים אותו מחדש.
החלפה או מיפוי מחדש של ערך השגיאה עלולים לגרום לביטול של -EPROBE_DEFER
, וכתוצאה מכך המכשיר לא ייבדק אף פעם.
שימוש בגרסאות API של devm_*()
כשהמכשיר רוכש משאב באמצעות devm_*()
API, הליבה משחררת את המשאב באופן אוטומטי אם המכשיר לא מצליח לבצע בדיקה, או אם הוא מצליח לבצע בדיקה ולאחר מכן הקישור שלו מתבטל. היכולת הזו מאפשרת ליצור קוד טיפול בשגיאות בפונקציה probe()
בצורה נקייה יותר, כי היא לא דורשת קפיצות של goto
כדי לשחרר את המשאבים שנרכשו על ידי devm_*()
, ומפשטת את פעולות ביטול הקישור של הנהג.
טיפול בביטול הקישור של הנהג למכשיר
חשוב לבטל את הקישור של מנהלי ההתקנים באופן מכוון ולא להשאיר את ביטול הקישור לא מוגדר, כי לא מוגדר לא מעיד על איסור. צריך להטמיע באופן מלא את ביטול הקישור של מנהל ההתקן למכשיר או להשבית באופן מפורש את ביטול הקישור של מנהל ההתקן למכשיר.
הטמעת ביטול קישור של מנהל התקן למכשיר
אם בוחרים להטמיע באופן מלא את ביטול הקישור של מנהלי ההתקנים, צריך לבטל את הקישור של מנהלי ההתקנים בצורה מסודרת כדי למנוע דליפות של זיכרון או משאבים ובעיות אבטחה. כדי לקשר מכשיר לנהג, קוראים לפונקציה probe()
של הנהג. כדי לבטל את הקישור של מכשיר, קוראים לפונקציה remove()
של הנהג. אם אין פונקציית remove()
, הליבה עדיין יכולה לבטל את הקישור למכשיר. הליבה של מנהל ההתקן מניחה שאין צורך בפעולות ניקוי כשמנהל ההתקן מבטל את הקישור למכשיר. נהג שלא מקושר למכשיר לא צריך לבצע פעולת ניקוי מפורשת אם מתקיימים שני התנאים הבאים:
כל המשאבים שנרכשו על ידי הפונקציה
probe()
של הנהג הם דרך ממשקי ה-API שלdevm_*()
.אין צורך בסדרת כיבוי או השהיה של מכשיר החומרה.
במקרה כזה, הליבה של מנהל ההתקן מטפלת בשחרור כל המשאבים שנרכשו באמצעות ממשקי ה-API של devm_*()
. אם אחת מההצהרות הקודמות לא נכונה, הדרייבר צריך לבצע ניקוי (שחרור משאבים וכיבוי או השבתה של החומרה) כשהקישור למכשיר מתבטל. כדי לוודא שמכשיר יכול לבטל את הקישור של מודול הנהג בצורה נקייה, צריך להשתמש באחת מהאפשרויות הבאות:
אם לחומרה לא נדרשת רצף כיבוי או השהיה, צריך לשנות את המודול של המכשיר כדי לקבל משאבים באמצעות ממשקי API של
devm_*()
.מטמיעים את פעולת הנהג
remove()
באותו מבנה (struct) שבו מטמיעים את הפונקציהprobe()
, ולאחר מכן מבצעים את שלבי הניקוי באמצעות הפונקציהremove()
.
השבתה מפורשת של ביטול הקישור של מנהל ההתקן למכשיר (לא מומלץ)
אם בוחרים להשבית באופן מפורש את ביטול הקישור של מנהל ההתקן למכשיר, צריך לאסור את ביטול הקישור וגם את פריקה של המודול.
כדי לא לאפשר ביטול קישור, מגדירים את הדגל
suppress_bind_attrs
כ-true
בקובץstruct device_driver
של הנהג. ההגדרה הזו מונעת את הצגת הקבציםbind
ו-unbind
בספרייהsysfs
של הנהג. הקובץunbind
מאפשר למרחב המשתמש להפעיל את ביטול הקישור של הנהג מהמכשיר.כדי לא לאפשר את פריקת המודול, צריך לוודא שהמודול מכיל את הערך
[permanent]
בקובץlsmod
. אם לא משתמשים ב-module_exit()
או ב-module_XXX_driver()
, המודול מסומן בתור[permanent]
.
לא טוענים קושחת מתוך פונקציית הבדיקה
לא מומלץ לטעון את הקושחה מהפונקציה .probe()
, כי יכול להיות שלא תהיה גישה לקושחה אם הבדיקה של הנהג תתבצע לפני הטעינה של מערכת הקבצים שמבוססת על אחסון קבוע או אחסון פלאש. במקרים כאלה, יכול להיות שממשק ה-API של request_firmware*()
ייחסם למשך זמן רב ואז ייכשל, מה שעלול להאט את תהליך האתחול ללא צורך. במקום זאת, כדאי לדחות את טעינת הקושחה למועד שבו הלקוח יתחיל להשתמש במכשיר. לדוגמה, מנהל מסך יכול לטעון את הקושחה כשמכשיר המסך נפתח.
שימוש ב-.probe()
כדי לטעון קושחת יכול להיות בסדר במקרים מסוימים, למשל בדרייבר של שעון שצריך קושחת כדי לפעול אבל המכשיר לא חשוף למרחב המשתמש. יש תרחישי שימוש מתאימים אחרים.
הטמעת בדיקה אסינכרונית
תמיכה בבדיקה אסינכררונית ושימוש בה כדי ליהנות משיפורים עתידיים, כמו טעינת מודולים במקביל או בדיקה של המכשיר כדי לזרז את זמן האתחול, שיתווספו ל-Android בגרסאות עתידיות. מודולים של מנהלי התקנים שלא משתמשים בבדיקה אסינכררונית עלולים להפחית את היעילות של אופטימיזציות כאלה.
כדי לסמן נהג שתומך בבדיקה אסינכררונית ומעדיף אותה, מגדירים את השדה probe_type
במאפיין struct device_driver
של הנהג. בדוגמה הבאה מוצגת תמיכה כזו שמופעלת במנהל פלטפורמה:
static struct platform_driver acme_driver = {
.probe = acme_probe,
...
.driver = {
.name = "acme",
...
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
כדי לגרום לנהג לפעול עם בדיקה אסינכרונית, לא נדרש קוד מיוחד. עם זאת, חשוב לזכור את הדברים הבאים כשמוסיפים תמיכה בבדיקה אסינכרונית:
אל תניחו הנחות לגבי יחסי תלות שנבדקו בעבר. בודקים באופן ישיר או עקיף (רוב הקריאות ל-Framework) ומחזירים את הערך
-EPROBE_DEFER
אם ספק אחד או יותר עדיין לא מוכן.אם מוסיפים מכשירי צאצא לפונקציית הבדיקה של מכשיר הורה, אל תניחו שהבדיקה של מכשירי הצאצא תתבצע באופן מיידי.
אם הבדיקה נכשלת, מבצעים טיפול תקין בשגיאה וניקוי (ראו שימוש בגרסאות API של devm_*()).
אין להשתמש ב-MODULE_SOFTDEP כדי להזמין בדיקות של מכשירים
הפונקציה MODULE_SOFTDEP()
היא לא פתרון מהימן להבטחת הסדר של בדיקות המכשיר, אסור להשתמש בה מהסיבות הבאות.
בדיקה מושהית. כשמודול נטען, יכול להיות שבדיקת המכשיר תידחה כי אחד מהספקים שלו לא מוכן. זה עלול להוביל לחוסר התאמה בין סדר הטעינה של המודול לסדר הבדיקה של המכשיר.
מנהל התקן אחד, הרבה מכשירים מודול של מנהל יכול לנהל סוג מכשיר ספציפי. אם המערכת כוללת יותר ממכונה אחת של סוג מכשיר, וכל מכשיר כזה כולל דרישה שונה לסדר הבדיקה, לא תוכלו לעמוד בדרישות האלה באמצעות סדר הטעינה של המודולים.
בדיקה אסינכרונית מודולים של מנהלי התקנים שמבצעים בדיקה אסינכרונית לא בודקים מכשיר באופן מיידי כשהמודול נטען. במקום זאת, בדיקת המכשיר מתבצעת על ידי שרשור מקביל, דבר שעלול להוביל לחוסר התאמה בין סדר הטעינה של המודול לסדר בדיקת המכשיר. לדוגמה, כשמודול של מנהל ראשי מסוג I2C מבצע בדיקה אסינכרונית ומודול של מנהל מסך מגע תלוי ב-PMIC שנמצא באוטובוס I2C, גם אם מנהל מסך המגע ומנהל ה-PMIC נטענים בסדר הנכון, יכול להיות שיתבצע ניסיון לבדיקת מנהל מסך המגע לפני הבדיקה של מנהל ה-PMIC.
אם יש לכם מודולים של מנהלי התקנים שמשתמשים בפונקציה MODULE_SOFTDEP()
, צריך לתקן אותם כך שלא ישתמשו בפונקציה הזו. כדי לעזור לך, צוות Android העביר לשינויים ל-upstream, שמאפשרים לליבה לטפל בבעיות שקשורות לסדר בלי להשתמש ב-MODULE_SOFTDEP()
. באופן ספציפי, אפשר להשתמש ב-fw_devlink
כדי לוודא את סדר הבדיקה, ואחרי שכל הצרכנים של המכשיר יבצעו בדיקה, אפשר להשתמש בקריאה החוזרת (callback) sync_state()
כדי לבצע את המשימות הנדרשות.
שימוש ב-#if IS_ENABLED() במקום ב-#ifdef להגדרות
משתמשים ב-#if IS_ENABLED(CONFIG_XXX)
במקום ב-#ifdef CONFIG_XXX
כדי לוודא שהקוד בתוך הבלוק #if
ימשיך להדר אם ההגדרה תשתנה בעתיד להגדרה של tristate. ההבדלים הם:
הערך של
#if IS_ENABLED(CONFIG_XXX)
מחושב כ-true
כשהערך שלCONFIG_XXX
מוגדר כמודול (=m
) או כתוכנה מובנית (=y
).הערך של
#ifdef CONFIG_XXX
מחושב כ-true
כשהערך שלCONFIG_XXX
מוגדר כ'מוטמע' (=y
) , אבל לא כשהערך שלCONFIG_XXX
מוגדר כ'מודול' (=m
). צריך להשתמש באפשרות הזו רק אם אתם בטוחים שאתם רוצים לעשות את אותו הדבר כשהתצורה מוגדרת כ'מודול' או כ'מושבתת'.
שימוש במאקרו הנכון ל-compiles מותנים
אם CONFIG_XXX
מוגדר כמודול (=m
), מערכת ה-build מגדירה את CONFIG_XXX_MODULE
באופן אוטומטי. אם הנהג נשלט על ידי CONFIG_XXX
ואתם רוצים לבדוק אם הוא מופעל כמודול, תוכלו להיעזר בהנחיות הבאות:
בקובץ ה-C (או בכל קובץ מקור שאינו קובץ כותרת) של הנהג, אל תשתמשו ב-
#ifdef CONFIG_XXX_MODULE
כי הוא מגביל ללא צורך וגורם לשגיאות אם שם הקובץ של התצורה משתנה ל-CONFIG_XYZ
. לכל קובץ מקור שאינו כותרת שמתבצע לו הידור למודול, מערכת ה-build מגדירה באופן אוטומטי אתMODULE
להיקף של הקובץ הזה. לכן, כדי לבדוק אם קובץ C (או כל קובץ מקור שאינו כותרת) עובר הידור כחלק ממודול, צריך להשתמש ב-#ifdef MODULE
(ללא הקידומתCONFIG_
).בקבצי הכותרת, אותה בדיקה מורכבת יותר כי קבצי הכותרת לא עוברים הידור ישירות לקובץ בינארי, אלא כחלק מקובץ C (או מקובצי מקור אחרים). יש להשתמש בכללים הבאים לגבי קובצי הכותרת:
בקובץ כותרת שמשתמש ב-
#ifdef MODULE
, התוצאה משתנה בהתאם לקובץ המקור שבו נעשה בו שימוש. כלומר, באותו קובץ כותרת באותו build יכולים להיות חלקים שונים של הקוד שעבר הידור עבור קובצי מקור שונים (מודול לעומת מובנה או מושבת). אפשר להשתמש באפשרות הזו כשרוצים להגדיר מאקרו שצריך להתרחב בדרך אחת לקוד מובנה ובדרך אחרת למודול.בקובץ כותרת שצריך להדרג קטע קוד כש
CONFIG_XXX
ספציפי מוגדר כמודול (ללא קשר אם קובץ המקור שכולל אותו הוא מודול), צריך להשתמש ב-#ifdef CONFIG_XXX_MODULE
בקובץ הכותרת.