הנחיות מודול הספק

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

מודול יכול להיות ספרייה או מנהל התקן .

  • מודולי ספרייה הם ספריות המספקות ממשקי 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 של המכשיר במקום לרשום מנהלי התקנים נפרדים. לחלופין, תוכל לפצל את מודול מנהל ההתקן לשני מודולים.

חריגים של פונקציות פתיחה ויציאה

מודולי ספרייה אינם רושמים מנהלי התקנים והם פטורים מהגבלות על module_init() ו- module_exit() מכיוון שהם עשויים להזדקק לפונקציות הללו כדי להגדיר מבני נתונים, תורי עבודה או שרשורי ליבה.

השתמש במאקרו MODULE_DEVICE_TABLE

מודולי מנהל ההתקן חייבים לכלול את המאקרו MODULE_DEVICE_TABLE , המאפשר למרחב המשתמש לקבוע את ההתקנים הנתמכים על ידי מודול מנהל התקן לפני טעינת המודול. אנדרואיד יכולה להשתמש בנתונים אלה כדי לייעל את טעינת המודולים, כגון להימנע מטעינת מודולים עבור מכשירים שאינם קיימים במערכת. לדוגמאות לשימוש במאקרו, עיין בקוד במעלה הזרם.

הימנע מאי התאמה של CRC עקב סוגי נתונים שהוכרזו קדימה

אל תכלול קובצי כותרות כדי לקבל חשיפה לסוגי נתונים שהוכרזו קדימה. כמה מבנים, איגודים וסוגי נתונים אחרים המוגדרים בקובץ כותרת ( header-Ah ) יכולים להיות מוצהרים קדימה בקובץ כותרת אחר ( header-Bh ) שמשתמש בדרך כלל במצביעים לסוגי נתונים אלה. דפוס קוד זה אומר שהקרנל מנסה בכוונה לשמור על מבנה הנתונים פרטי למשתמשי header-Bh .

משתמשים ב- header-Bh לא צריכים לכלול header-Ah כדי לגשת ישירות לחלק הפנימי של מבני הנתונים המוצהרים קדימה. פעולה זו גורמת לבעיות אי-התאמה CONFIG_MODVERSIONS CRC (מה שיוצר בעיות תאימות של 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 פטורים.

  • מבנה הנתונים מוקצה או מאותחל על ידי המודול אך הופך לגלוי לקרנל על ידי העברה, בעקיפין (דרך מצביע במבנה) או ישירות, כקלט בפונקציה המיוצאת על ידי הליבה. לדוגמה, מודול מנהל התקן 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 ומנהל התקן תואם. כל שאר החריגים כבר מטופלים על ידי הקוד במעלה הזרם.

בנוסף, 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 (אפשרי רק אם הוא לא הועבר במעלה זרימה). כדי לדון בחלופות, פנה לצוות קרנל Android בכתובת kernel-team@android.com והיה מוכן להצדיק את מקרי השימוש שלך.

השתמש ב- DT phandles כדי לחפש ספקים

הפנה לספק באמצעות phandle (הפניה/מצביע לצומת DT) ב-DT במידת האפשר. שימוש בקשרי DT סטנדרטיים וב-phandles כדי להתייחס לספקים מאפשר fw_devlink (לשעבר of_devlink ) לקבוע באופן אוטומטי תלות בין-מכשיר על ידי ניתוח ה-DT בזמן ריצה. לאחר מכן, הליבה יכולה לחקור אוטומטית התקנים בסדר הנכון, ולהסיר את הצורך בסידור טעינת מודול או MODULE_SOFTDEP() .

תרחיש מדור קודם (ללא תמיכה ב-DT בליבת ARM)

בעבר, לפני הוספת תמיכת DT לגרעיני ARM, צרכנים כגון מכשירי מגע חיפשו ספקים כגון רגולטורים באמצעות מחרוזות ייחודיות בעולם. לדוגמה, מנהל ההתקן של ACME PMIC יכול לרשום או לפרסם רגולטורים מרובים (כגון 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 להישמט ולגרום לכך שהמכשיר שלך לעולם לא ייבדק.

השתמש ב-devm_*() גרסאות API

כאשר ההתקן רוכש משאב באמצעות API devm_*() , המשאב משוחרר אוטומטית על ידי הליבה אם המכשיר נכשל בבדיקה, או מבצע בדיקה מוצלחת ומאוחר יותר אינו קשור. פונקציונליות זו הופכת את קוד הטיפול בשגיאות בפונקציה probe() למנקה מכיוון שהיא אינה דורשת קפיצות goto כדי לשחרר את המשאבים שנרכשו על ידי devm_*() ומפשטת את פעולות ביטול הכריכה של מנהל ההתקן.

טפל בביטול התחייבות של מנהל ההתקן

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

יישום ביטול הכריכה של מנהל ההתקן

כאשר אתה בוחר ליישם באופן מלא את ביטול הכריכה של מנהלי התקנים, בטל את קישור מנהלי ההתקנים בצורה נקייה כדי למנוע דליפות זיכרון או משאבים ובעיות אבטחה. אתה יכול לאגד התקן למנהל התקן על ידי קריאה לפונקציית probe() של מנהל התקן ולבטל קישור של התקן על ידי קריאה לפונקציית remove() של מנהל ההתקן. אם לא קיימת פונקציית remove() , הקרנל עדיין יכול לבטל את קישור ההתקן; ליבת מנהל ההתקן מניחה שלא נדרשת עבודת ניקוי על ידי מנהל ההתקן כאשר הוא מתנתק מהמכשיר. מנהל התקן שאינו קשור למכשיר אינו צריך לבצע עבודת ניקוי מפורשת כאשר שני הדברים הבאים נכונים:

  • כל המשאבים שנרכשים על ידי פונקציית probe() של מנהל התקן הם דרך ממשקי API של devm_*() .

  • התקן החומרה אינו זקוק לרצף כיבוי או השהייה.

במצב זה, ליבת מנהל ההתקן מטפלת בשחרור כל המשאבים שנרכשו באמצעות ממשקי API devm_*() . אם אחת מהמשפטים הקודמים אינה נכונה, מנהל ההתקן צריך לבצע ניקוי (לשחרר משאבים ולכבות או להשהות את החומרה) כאשר הוא מתנתק מהתקן. כדי להבטיח שהתקן יכול לבטל את הקשירה של מודול מנהל התקן בצורה נקייה, השתמש באחת מהאפשרויות הבאות:

  • אם החומרה אינה זקוקה לרצף כיבוי או השהייה, שנה את מודול ההתקן כדי לרכוש משאבים באמצעות ממשקי API devm_*() .

  • יישם את פעולת מנהל ההתקן remove() באותו מבנה כמו הפונקציה 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() לטעינת קושחה עשוי להיות בסדר במקרים מסוימים, כגון במנהל התקן שעון שזקוק לקושחה כדי לתפקד אך ההתקן אינו חשוף למרחב המשתמש. מקרי שימוש מתאימים אחרים אפשריים.

יישם בדיקה אסינכרונית

תמכו והשתמשו בבדיקה אסינכרונית כדי לנצל שיפורים עתידיים, כגון טעינת מודול מקביל או חיטוט במכשיר כדי להאיץ את זמן האתחול, שעשויים להתווסף לאנדרואיד במהדורות עתידיות. מודולי מנהלי התקנים שאינם משתמשים בבדיקה אסינכרונית יכולים להפחית את האפקטיביות של אופטימיזציות כאלה.

כדי לסמן מנהל התקן כתומך ומעדיף חיטוט אסינכרוני, הגדר את השדה probe_type ב- struct device_driver של הנהג. הדוגמה הבאה מציגה תמיכה כזו מופעלת עבור מנהל התקן של פלטפורמה:

static struct platform_driver acme_driver = {
        .probe          = acme_probe,
        ...
        .driver         = {
                .name   = "acme",
                ...
                .probe_type = PROBE_PREFER_ASYNCHRONOUS,
        },
};

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

  • אל תניח הנחות לגבי תלות שנבדקה בעבר. בדוק ישירות או בעקיפין (רוב קריאות המסגרת) והחזר -EPROBE_DEFER אם ספק אחד או יותר עדיין לא מוכן.

  • אם אתה מוסיף מכשירי צאצא בפונקציית הבדיקה של מכשיר אב, אל תניח שמכשירי הצאצא נבדקים מיד.

  • אם בדיקה נכשלת, בצע טיפול נכון בשגיאות וניקוי (ראה שימוש בגרסאות API של devm_*() ).

אל תשתמש ב-MODULE_SOFTDEP כדי להזמין בדיקות מכשיר

הפונקציה MODULE_SOFTDEP() אינה פתרון אמין להבטחת סדר בדיקות המכשיר ואין להשתמש בה מהסיבות הבאות.

  • בדיקה נדחית. כאשר מודול נטען, בדיקת המכשיר עשויה להידחות מכיוון שאחד הספקים שלו לא מוכן. זה יכול להוביל לאי התאמה בין סדר הטעינה של המודול לבין סדר הבדיקה של המכשיר.

  • דרייבר אחד, הרבה מכשירים. מודול מנהל התקן יכול לנהל סוג התקן מסוים. אם המערכת כוללת יותר ממופע אחד של סוג התקן ולכל אחד מהם יש דרישת סדר בדיקה שונה, אינך יכול לכבד את הדרישות הללו באמצעות סדר עומס מודול.

  • חיטוט אסינכרוני. מודולי מנהל התקן שמבצעים בדיקה אסינכרונית אינם בודקים מיד התקן כאשר המודול נטען. במקום זאת, חוט מקביל מטפל בחיטוט המכשיר, מה שעלול להוביל לאי התאמה בין סדר הטעינה של המודול לסדר הבדיקה של ההתקן. לדוגמה, כאשר מודול מנהל התקן I2C ראשי מבצע בדיקה אסינכרונית ומודול מנהל התקן מגע תלוי ב-PMIC שנמצא באפיק I2C, גם אם מנהל ההתקן של המגע ומנהל ההתקן של PMIC נטענים בסדר הנכון, ייתכן שתנסה את הגשש של מנהל המגע לפני בדיקה של מנהל התקן PMIC.

אם יש לך מודולי מנהל התקן המשתמשים בפונקציה MODULE_SOFTDEP() , תקן אותם כך שהם לא ישתמשו בפונקציה הזו. כדי לעזור לך, צוות אנדרואיד העלה שינויים שמאפשרים לליבה לטפל בבעיות הזמנה מבלי להשתמש MODULE_SOFTDEP() . באופן ספציפי, אתה יכול להשתמש fw_devlink כדי להבטיח הזמנת בדיקה ו(לאחר שכל הצרכנים של מכשיר בדקו) להשתמש ב- sync_state() להתקשרות חזרה כדי לבצע את כל המשימות הנחוצות.

השתמש ב-#if IS_ENABLED() במקום #ifdef עבור תצורות

השתמש #if IS_ENABLED(CONFIG_XXX) במקום #ifdef CONFIG_XXX כדי להבטיח שהקוד בתוך בלוק #if ימשיך להדר אם התצורה תשתנה לתצורה משולשת בעתיד. ההבדלים הם כדלקמן:

  • #if IS_ENABLED(CONFIG_XXX) מוערך כ- true כאשר CONFIG_XXX מוגדר למודול ( =m ) או מובנה ( =y ).

  • #ifdef CONFIG_XXX מוערך כ- true כאשר CONFIG_XXX מוגדר למובנה ( =y ), אך לא כאשר CONFIG_XXX מוגדר למודול ( =m ). השתמש בזה רק כאשר אתה בטוח שאתה רוצה לעשות את אותו הדבר כאשר התצורה מוגדרת למודול או מושבתת.

השתמש במאקרו הנכון עבור קומפילציה מותנית

אם CONFIG_XXX מוגדר למודול ( =m ), מערכת הבנייה מגדירה אוטומטית CONFIG_XXX_MODULE . אם מנהל ההתקן שלך נשלט על ידי CONFIG_XXX ואתה רוצה לבדוק אם מנהל ההתקן שלך מורכב כמודול, השתמש בהנחיות הבאות:

  • בקובץ C (או כל קובץ מקור שאינו קובץ כותרת) עבור מנהל ההתקן שלך, אל תשתמש #ifdef CONFIG_XXX_MODULE מכיוון שהוא מגביל שלא לצורך ונשבר אם שם התצורה שונה ל- CONFIG_XYZ . עבור כל קובץ מקור שאינו כותרות אשר מורכב למודול, מערכת הבנייה מגדירה באופן אוטומטי MODULE עבור היקף הקובץ. לכן, כדי לבדוק אם קובץ C (או כל קובץ מקור שאינו כותרת) עובר קומפילציה כחלק ממודול, השתמש ב- #ifdef MODULE (ללא הקידומת CONFIG_ ).

  • בקובצי כותרות, אותו בדיקה מטעה מכיוון שקובצי כותרת אינם מקומפלים ישירות לקובץ בינארי אלא מורכבים כחלק מקובץ C (או קבצי מקור אחרים). השתמש בכללים הבאים עבור קובצי כותרות:

    • עבור קובץ כותרת המשתמש #ifdef MODULE , התוצאה משתנה בהתאם לקובץ המקור שמשתמש בה. משמעות הדבר היא כי אותו קובץ כותרת באותו build יכול להרכיב חלקים שונים מהקוד שלו עבור קבצי מקור שונים (מודול לעומת מובנה או מושבת). זה יכול להיות שימושי כאשר אתה רוצה להגדיר מאקרו שצריך להרחיב דרך אחת עבור קוד מובנה ולהרחיב בצורה אחרת עבור מודול.

    • עבור קובץ כותרת שצריך להדר בקטע קוד כאשר CONFIG_XXX ספציפי מוגדר למודול (ללא קשר אם קובץ המקור הכולל הוא מודול), קובץ הכותרת חייב להשתמש #ifdef CONFIG_XXX_MODULE .