Tedarikçi modüllerinizin sağlamlığını ve güvenilirliğini artırmak için aşağıdaki yönergeleri kullanın. Birçok yönerge, uygulandığında doğru modül yükleme sırasını ve sürücülerin cihazları yoklaması gereken sırayı belirlemeyi kolaylaştırabilir.
Modül, kitaplık veya sürücü olabilir.
Kitaplık modülleri, diğer modüllerin kullanması için API'ler sağlayan kitaplıklardır. Bu tür modüller genellikle donanıma özgü değildir. Kitaplık modüllerine örnek olarak AES şifreleme modülü, modül olarak derlenen
remoteprocçerçevesi ve logbuffer modülü verilebilir.module_init()içindeki modül kodu, veri yapılarını ayarlamak için çalışır ancak harici bir modül tarafından tetiklenmediği sürece başka kod çalışmaz.Sürücü modülleri, belirli bir cihaz türünü araştıran veya bu türe bağlanan sürücülerdir. Bu tür modüller donanıma özeldir. Sürücü modüllerine örnek olarak UART, PCIe ve video kodlayıcı donanımı verilebilir. Sürücü modülleri yalnızca ilişkili cihazları sistemde mevcut olduğunda etkinleşir.
Cihaz yoksa yalnızca sürücüyü sürücü çekirdeği çerçevesine kaydeden
module_init()kodu çalışır.Cihaz mevcutsa ve sürücü bu cihazı başarıyla yoklarsa veya cihaza bağlanırsa başka modül kodu çalışabilir.
Modül başlatma ve çıkışını doğru şekilde kullanma
Sürücü modülleri, module_init() içinde sürücü kaydetmeli ve module_exit() içinde sürücü kaydını silmelidir. Bu kısıtlamaları zorunlu kılmanın bir yolu, module_init(), *_initcall() veya module_exit() makrolarının doğrudan kullanılmasını önleyen sarmalayıcı makroları kullanmaktır.
Kaldırılabilen modüller için
module_subsystem_driver()kullanın. Örnekler:module_platform_driver(),module_i2c_driver()vemodule_pci_driver().Kaldırılamayan modüller için
builtin_subsystem_driver()örneklerini kullanın:builtin_platform_driver(),builtin_i2c_driver()vebuiltin_pci_driver().
Bazı sürücü modülleri birden fazla sürücü kaydettiği için module_init() ve module_exit() kullanır. Birden fazla sürücüyü kaydetmek için module_init() ve module_exit() kullanan bir sürücü modülü için sürücüleri tek bir sürücüde birleştirmeyi deneyin. Örneğin, ayrı sürücüler kaydetmek yerine cihazın compatible
dizesini veya yardımcı verilerini kullanarak farklılaştırabilirsiniz.
Alternatif olarak, sürücü modülünü iki modüle bölebilirsiniz.
Başlatma ve çıkış işlevi istisnaları
Kitaplık modülleri sürücüleri kaydetmez ve module_init() ile module_exit() üzerindeki kısıtlamalardan muaftır. Bunun nedeni, veri yapılarını, iş kuyruklarını veya çekirdek iş parçacıklarını ayarlamak için bu işlevlere ihtiyaç duyabilmeleridir.
MODULE_DEVICE_TABLE makrosunu kullanma
Sürücü modülleri, kullanıcı alanının modülü yüklemeden önce bir sürücü modülü tarafından desteklenen cihazları belirlemesine olanak tanıyan MODULE_DEVICE_TABLE makrosunu içermelidir. Android, bu verileri modül yüklemeyi optimize etmek için kullanabilir. Örneğin, sistemde bulunmayan cihazlar için modül yüklemeyi önleyebilir. Makronun kullanımıyla ilgili örnekler için yukarı akış koduna bakın.
Önceden tanımlanmış veri türleri nedeniyle CRC uyuşmazlıklarını önleme
İleriye dönük olarak tanımlanmış veri türlerini görmek için üstbilgi dosyalarını eklemeyin.
Bir başlık dosyasında tanımlanan bazı yapılar, birleşimler ve diğer veri türleri
(header-A.h), genellikle bu veri türlerine yönelik işaretçiler kullanan farklı bir başlık dosyasında (header-B.h) önceden bildirilebilir. Bu kod kalıbı, çekirdeğin veri yapısını header-B.h kullanıcılarına özel tutmaya çalıştığı anlamına gelir.
header-B.h kullanıcıları, önceden tanımlanmış bu veri yapılarının iç kısımlarına doğrudan erişmek için header-A.h eklememelidir. Bunu yaptığınızda, farklı bir çekirdek (ör. GKI çekirdeği) modülü yüklemeye çalıştığında CONFIG_MODVERSIONS CRC
uyuşmazlığı sorunları (ABI uyumluluğu sorunlarına neden olur) oluşur.
Örneğin, struct fwnode_handle, include/linux/fwnode.h içinde tanımlanır ancak çekirdek, struct fwnode_handle ile ilgili ayrıntıları include/linux/device.h kullanıcılarından gizli tutmaya çalıştığı için include/linux/device.h içinde struct fwnode_handle; olarak önceden tanımlanır. Bu senaryoda, struct fwnode_handle üyelerine erişmek için bir modüle #include <linux/fwnode.h> eklemeyin. Bu tür üstbilgi dosyalarını eklemeniz gereken tüm tasarımlar kötü bir tasarım kalıbı olduğunu gösterir.
Çekirdek çekirdek yapılarına doğrudan erişmeyin
Temel çekirdek veri yapılarına doğrudan erişmek veya bunları değiştirmek, bellek sızıntıları, kilitlenmeler ve gelecekteki çekirdek sürümleriyle uyumsuzluk gibi istenmeyen davranışlara yol açabilir. Bir veri yapısı, aşağıdaki koşullardan herhangi birini karşıladığında temel çekirdek veri yapısıdır:
Veri yapısı,
KERNEL-DIR/include/altında tanımlanır. Örneğin,struct devicevestruct dev_links_info.include/linux/sociçinde tanımlanan veri yapıları muaftır.Veri yapısı, modül tarafından ayrılır veya başlatılır ancak dolaylı olarak (bir yapıdaki işaretçi aracılığıyla) ya da doğrudan çekirdek tarafından dışa aktarılan bir işlevde giriş olarak geçirilerek çekirdeğe görünür hale getirilir. Örneğin, bir
cpufreqsürücü modülüstruct cpufreq_driveröğesini başlatır ve ardından bunucpufreq_register_driver()öğesine giriş olarak iletir. Bu noktadan sonra,cpufreqsürücü modülüstruct cpufreq_driveröğesini doğrudan değiştirmemelidir. Çünkücpufreq_register_driver()işlevinin çağrılmasıstruct cpufreq_driveröğesini çekirdeğe görünür hale getirir.Veri yapısı, modülünüz tarafından başlatılmamıştır. Örneğin,
regulator_register()tarafından döndürülenstruct regulator_dev.
Temel çekirdek veri yapılarına yalnızca çekirdek tarafından dışa aktarılan işlevler veya satıcı kancalarına giriş olarak açıkça iletilen parametreler aracılığıyla erişin. Temel çekirdek veri yapısının bölümlerini değiştirmek için bir API veya sağlayıcı kancanız yoksa bu durum muhtemelen kasıtlıdır ve veri yapısını modüllerden değiştirmemelisiniz. Örneğin, struct device veya struct device.links içindeki alanları değiştirmeyin.
device.devres_headdeğerini değiştirmek içindevm_clk_get(),devm_regulator_get()veyadevm_kzalloc()gibi birdevm_*()işlevi kullanın.struct device.linksiçindeki alanları değiştirmek içindevice_link_add()veyadevice_link_del()gibi bir cihaz bağlantısı API'si kullanın.
Uyumlu özelliği olan devicetree düğümlerini ayrıştırmayın
Bir cihaz ağacı (DT) düğümünde compatible özelliği varsa üst DT düğümünde of_platform_populate() çağrıldığında (genellikle üst cihazın cihaz sürücüsü tarafından) otomatik olarak struct device ayrılır. Varsayılan beklenti (zamanlayıcı için erken başlatılan bazı cihazlar hariç) compatible özelliği olan bir DT düğümünün struct device ve eşleşen bir cihaz sürücüsüne sahip olmasıdır. Diğer tüm istisnalar, yukarı akış kodu tarafından zaten işlenmektedir.
Ayrıca fw_devlink (eski adıyla of_devlink), compatible özelliği olan DT düğümlerini, sürücü tarafından araştırılan struct device ayrılmış cihazlar olarak kabul eder. Bir DT düğümünde compatible özelliği varsa ancak ayrılan struct device sorgulanmıyorsa fw_devlink, tüketici cihazlarının sorgulamasını engelleyebilir veya tedarikçi cihazları için sync_state() çağrılarının yapılmasını engelleyebilir.
Sürücünüz, of_find_*() işlevini (ör. of_find_node_by_name() veya of_find_compatible_node()) kullanarak compatible özelliği olan bir DT düğümünü doğrudan bulup bu DT düğümünü ayrıştırıyorsa cihazı yoklayabilen bir cihaz sürücüsü yazarak veya compatible özelliğini kaldırarak (yalnızca yukarı akışa aktarılmamışsa mümkündür) modülü düzeltin. Alternatifleri görüşmek için kernel-team@android.com adresinden Android Kernel Ekibi'ne ulaşın ve kullanım alanlarınızı gerekçelendirmeye hazır olun.
Tedarikçileri aramak için DT tanıtıcılarını kullanma
Mümkün olduğunda DT'de bir tedarikçiye phandle (bir DT düğümüne referans veya işaretçi) kullanarak atıfta bulunun. Tedarikçilere başvurmak için standart DT bağlamalarını ve işleyicilerini kullanmak, fw_devlink'nın (eski adıyla of_devlink) çalışma zamanında DT'yi ayrıştırarak cihazlar arası bağımlılıkları otomatik olarak belirlemesini sağlar. Daha sonra çekirdek, cihazları doğru sırada otomatik olarak yoklayabilir. Bu sayede modül yükleme sırası veya MODULE_SOFTDEP() gerekmez.
Eski senaryo (ARM çekirdeğinde DT desteği yok)
Daha önce, ARM çekirdeklerine DT desteği eklenmeden önce, dokunmatik cihazlar gibi tüketiciler, küresel olarak benzersiz dizeleri kullanarak regülatörler gibi tedarikçileri arıyordu.
Örneğin, ACME PMIC sürücüsü birden fazla regülatörü (ör. acme-pmic-ldo1 - acme-pmic-ldo10) kaydedebilir veya bunların reklamını yapabilir. Dokunma sürücüsü ise regulator_get(dev, "acme-pmic-ldo10") kullanarak bir regülatörü arayabilir.
Ancak farklı bir kartta LDO8, dokunmatik cihaza güç sağlayabilir. Bu durumda, dokunmatik cihazın kullanıldığı her kart için aynı dokunmatik sürücünün, regülatörün doğru arama dizesini belirlemesi gerekir. Bu da hantal bir sisteme yol açar.
Mevcut senaryo (ARM çekirdeğinde DT desteği)
ARM çekirdeklerine DT desteği eklendikten sonra tüketiciler, phandle kullanarak tedarikçinin cihaz ağacı düğümüne başvurarak DT'deki tedarikçileri tanımlayabilir.
Tüketiciler, kaynağı kimin sağladığına göre değil, ne için kullanıldığına göre de adlandırabilir. Örneğin, önceki örnekteki dokunma sürücüsü, dokunma cihazının çekirdeğine ve sensörüne güç sağlayan tedarikçileri almak için regulator_get(dev, "core") ve regulator_get(dev, "sensor") kullanabilir. Bu tür bir cihazla ilişkili DT, aşağıdaki kod örneğine benzer:
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 {
...
};
};
Her iki dünyanın da en kötü senaryosu
Eski çekirdeklerden taşınan bazı sürücüler, DT'de eski şemanın en kötü kısmını alıp işleri kolaylaştırmak için tasarlanan yeni şemaya zorlayan eski davranışları içerir. Bu tür sürücülerde, tüketici sürücüsü cihaza özel bir DT özelliği kullanarak arama için kullanılacak dizeyi okur, tedarikçi tedarikçi kaynağını kaydetmek için kullanılacak adı tanımlamak üzere tedarikçiye özel başka bir özellik kullanır, ardından tüketici ve tedarikçi, tedarikçiyi aramak için dizeleri kullanma konusundaki aynı eski şemayı kullanmaya devam eder. Bu iki dünyanın en kötüsü senaryosunda:
Dokunma sürücüsü, aşağıdaki koda benzer bir kod kullanır:
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, aşağıdakine benzer bir kod kullanır:
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" }; };
Çerçeve API hatalarını değiştirmeyin
regulator, clocks, irq, gpio, phys ve extcon gibi çerçeve API'leri, bir cihazın şu anda yoklama yapmaya çalıştığını ancak yapamadığını belirtmek için hata dönüş değeri olarak -EPROBE_DEFER değerini döndürür. Bu durumda çekirdek, yoklamayı daha sonra tekrar denemelidir. Bu gibi durumlarda cihazınızın .probe() işlevinin beklendiği gibi başarısız olmasını sağlamak için hata değerini değiştirmeyin veya yeniden eşlemeyin.
Hata değerinin değiştirilmesi veya yeniden eşlenmesi, -EPROBE_DEFER'nın bırakılmasına neden olabilir
ve cihazınızın hiçbir zaman araştırılmamasına yol açabilir.
devm_*() API varyantlarını kullanma
Cihaz, devm_*() API'sini kullanarak bir kaynak edindiğinde cihaz yoklamada başarısız olursa veya başarılı bir şekilde yoklayıp daha sonra bağlantısı kaldırılırsa kaynak çekirdek tarafından otomatik olarak serbest bırakılır. Bu özellik, probe() işlevindeki hata işleme kodunu daha temiz hale getirir. Çünkü devm_*() tarafından edinilen kaynakların serbest bırakılması için goto atlamaları gerekmez ve sürücü bağlantısını kaldırma işlemlerini basitleştirir.
Cihaz sürücüsünün bağlantısını kaldırma işlemini gerçekleştirme
Cihaz sürücülerinin bağlantısını kaldırma konusunda dikkatli olun ve bağlantıyı kaldırma işlemini tanımlanmamış olarak bırakmayın. Tanımlanmamış, izin verilmediği anlamına gelmez. Cihaz sürücüsü bağlantısını kaldırma özelliğini tamamen uygulamanız veya açıkça devre dışı bırakmanız gerekir.
Cihaz sürücüsü bağlantısını kaldırma işlemini uygulama
Cihaz sürücüsü bağlantısını tamamen kaldırmayı seçtiğinizde, bellek veya kaynak sızıntılarını ve güvenlik sorunlarını önlemek için cihaz sürücülerinin bağlantısını temiz bir şekilde kaldırın. Sürücünün probe() işlevini çağırarak bir cihazı sürücüye bağlayabilir, sürücünün remove() işlevini çağırarak da cihazın bağlantısını kaldırabilirsiniz. remove() işlevi yoksa çekirdek yine de cihazın bağlantısını kaldırabilir. Sürücü çekirdeği, cihazın bağlantısı kaldırıldığında sürücü tarafından herhangi bir temizleme çalışması yapılması gerekmediğini varsayar. Bir cihazdan ayrılan sürücünün, aşağıdaki koşulların her ikisi de geçerliyse açıkça temizleme işlemi yapması gerekmez:
Bir sürücünün
probe()işlevi tarafından edinilen tüm kaynaklardevm_*()API'leri aracılığıyla alınır.Donanım cihazının kapatma veya sessize alma sırasına ihtiyacı yoktur.
Bu durumda, sürücü çekirdeği devm_*() API'leri aracılığıyla edinilen tüm kaynakların serbest bırakılmasını sağlar. Yukarıdaki ifadelerden biri doğru değilse sürücünün bir cihazdan bağlantısı kaldırıldığında temizleme işlemi (kaynakları serbest bırakma ve donanımı kapatma veya sessize alma) yapması gerekir. Bir cihazın sürücü modülünü sorunsuz bir şekilde kaldırabilmesi için aşağıdaki seçeneklerden birini kullanın:
Donanımın kapatma veya sessize alma sırasına ihtiyacı yoksa
devm_*()API'lerini kullanarak kaynak elde etmek için cihaz modülünü değiştirin.remove()işleviniprobe()işleviyle aynı yapıda uygulayın, ardındanremove()işlevini kullanarak temizleme adımlarını gerçekleştirin.
Cihaz sürücüsünün bağlantısını açıkça devre dışı bırakma (önerilmez)
Cihaz sürücüsü bağlantısının kaldırılmasını açıkça devre dışı bırakmayı seçtiğinizde, bağlantının kaldırılmasına ve modülün kaldırılmasına izin vermemeniz gerekir.
Bağlantının kaldırılmasına izin vermemek için sürücünün
struct device_driverbölümündesuppress_bind_attrsişaretinitrueolarak ayarlayın. Bu ayar,bindveunbinddosyalarının sürücününsysfsdizininde gösterilmesini engeller.unbinddosyası, kullanıcı alanının bir sürücünün cihazından bağlantısının kaldırılmasını tetiklemesine olanak tanır.Modülün kaldırılmasına izin vermemek için modülün
lsmodiçinde[permanent]olduğundan emin olun.module_exit()veyamodule_XXX_driver()kullanılmadığında modül[permanent]olarak işaretlenir.
Donanım yazılımını prob işlevi içinden yüklemeyin
Sürücü, .probe() işlevi içinden donanım yazılımı yüklememelidir. Aksi takdirde, sürücü, flash veya kalıcı depolama alanına dayalı dosya sistemi bağlanmadan önce yoklama yaparsa donanım yazılımına erişemeyebilir. Bu gibi durumlarda, request_firmware*() API'si uzun süre engellenebilir ve ardından başarısız olabilir. Bu da başlatma sürecini gereksiz yere yavaşlatabilir. Bunun yerine, donanım yazılımının yüklenmesini istemci cihazı kullanmaya başlayana kadar erteleyin. Örneğin, bir ekran sürücüsü, ekran cihazı açıldığında donanım yazılımını yükleyebilir.
.probe()'ı kullanarak donanım yazılımı yüklemek, bazı durumlarda (ör. çalışmak için donanım yazılımına ihtiyaç duyan ancak cihazın kullanıcı alanına maruz kalmadığı bir saat sürücüsünde) uygun olabilir. Başka uygun kullanım alanları da olabilir.
Eşzamansız yoklamayı uygulama
Gelecekteki iyileştirmelerden (ör. paralel modül yükleme veya başlatma süresini hızlandırmak için cihaz yoklama) yararlanmak için eşzamansız yoklamayı destekleyin ve kullanın. Bu iyileştirmeler, gelecekteki sürümlerde Android'e eklenebilir. Asenkron yoklama kullanmayan sürücü modülleri, bu tür optimizasyonların etkinliğini azaltabilir.
Bir sürücüyü destekleyici ve eşzamansız yoklamayı tercih eden olarak işaretlemek için sürücünün struct device_driver üyesindeki probe_type alanını ayarlayın. Aşağıdaki örnekte, bir platform sürücüsü için bu tür bir desteğin nasıl etkinleştirildiği gösterilmektedir:
static struct platform_driver acme_driver = {
.probe = acme_probe,
...
.driver = {
.name = "acme",
...
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
Bir sürücünün zaman uyumsuz yoklamayla çalışması için özel kod gerekmez. Ancak, eşzamansız yoklama desteği eklerken aşağıdakileri göz önünde bulundurun.
Daha önce araştırılmış bağımlılıklarla ilgili varsayımlarda bulunmayın. Doğrudan veya dolaylı olarak (çoğu çerçeve çağrısı) kontrol edin ve bir veya daha fazla tedarikçi henüz hazır değilse
-EPROBE_DEFERdeğerini döndürün.Ebeveyn cihazının yoklama işlevine çocuk cihazları eklerseniz çocuk cihazlarının hemen yoklandığını varsaymayın.
Bir yoklama başarısız olursa uygun hata işlemeyi gerçekleştirin ve temizleyin (bkz. devm_*() API varyantlarını kullanma).
Cihaz incelemeleri sipariş etmek için MODULE_SOFTDEP kullanmayın
MODULE_SOFTDEP() işlevi, cihaz yoklamalarının sırasını garanti etmek için güvenilir bir çözüm değildir ve aşağıdaki nedenlerle kullanılmamalıdır.
Ertelenmiş yoklama. Bir modül yüklendiğinde, tedarikçilerinden biri hazır olmadığı için cihaz yoklaması ertelenebilir. Bu durum, modül yükleme sırası ile cihaz yoklama sırası arasında uyuşmazlığa yol açabilir.
Tek sürücü, birçok cihaz. Sürücü modülü, belirli bir cihaz türünü yönetebilir. Sistemde bir cihaz türünün birden fazla örneği varsa ve bu cihazların her birinin farklı bir yoklama sırası gereksinimi varsa modül yükleme sırasını kullanarak bu gereksinimleri karşılayamazsınız.
Eşzamansız yoklama. Asenkron yoklama gerçekleştiren sürücü modülleri, modül yüklendiğinde cihazı hemen yoklamaz. Bunun yerine, cihaz yoklaması paralel bir iş parçacığı tarafından gerçekleştirilir. Bu da modül yükleme sırası ile cihaz yoklama sırası arasında uyuşmazlığa yol açabilir. Örneğin, bir I2C ana sürücü modülü eşzamansız yoklama gerçekleştirdiğinde ve bir dokunmatik sürücü modülü I2C veri yolundaki PMIC'ye bağlı olduğunda, dokunmatik sürücü ve PMIC sürücüsü doğru sırada yüklense bile dokunmatik sürücünün yoklaması, PMIC sürücüsünün yoklamasından önce denenmiş olabilir.
MODULE_SOFTDEP() işlevini kullanan sürücü modülleriniz varsa bunları düzeltin. Android ekibi, çekirdeğin MODULE_SOFTDEP() kullanmadan sıralama sorunlarını işlemesini sağlayan değişiklikler yaptı. Özellikle, yoklama sıralamasını sağlamak için fw_devlink öğesini kullanabilir ve (bir cihazın tüm tüketicileri yoklamayı tamamladıktan sonra) gerekli görevleri gerçekleştirmek için sync_state() geri çağırmasını kullanabilirsiniz.
Yapılandırmalar için #ifdef yerine #if IS_ENABLED() kullanın.
#if IS_ENABLED(CONFIG_XXX) yerine #ifdef CONFIG_XXX kullanın. Böylece, yapılandırma gelecekte üç durumlu yapılandırmaya dönüşse bile #if bloğundaki kod derlenmeye devam eder. Farklar şunlardır:
#if IS_ENABLED(CONFIG_XXX),CONFIG_XXXmodül (=m) veya yerleşik (=y) olarak ayarlandığındatrueolarak değerlendirilir.#ifdef CONFIG_XXX,CONFIG_XXXyerleşik (=y) olarak ayarlandığındatrueolarak değerlendirilir ancakCONFIG_XXXmodül (=m) olarak ayarlandığında değerlendirilmez. Bunu yalnızca yapılandırma modül olarak ayarlandığında veya devre dışı bırakıldığında aynı şeyi yapmak istediğinizden eminseniz kullanın.
Koşullu derlemeler için doğru makroyu kullanma
Bir CONFIG_XXX modüle (=m) ayarlanırsa derleme sistemi CONFIG_XXX_MODULE değerini otomatik olarak tanımlar. Sürücünüz CONFIG_XXX tarafından kontrol ediliyorsa ve sürücünüzün modül olarak derlenip derlenmediğini kontrol etmek istiyorsanız aşağıdaki yönergeleri uygulayın:
Sürücünüzün C dosyasında (veya üstbilgi dosyası olmayan herhangi bir kaynak dosyasında), gereksiz yere kısıtlayıcı olduğu ve yapılandırma
CONFIG_XYZolarak yeniden adlandırılırsa bozulacağı için#ifdef CONFIG_XXX_MODULEkullanmayın. Bir modülde derlenen tüm başlık olmayan kaynak dosyalar için derleme sistemi, bu dosyanın kapsamı için otomatik olarakMODULEtanımlar. Bu nedenle, bir C dosyasının (veya herhangi bir üstbilgi olmayan kaynak dosyanın) bir modülün parçası olarak derlenip derlenmediğini kontrol etmek için#ifdef MODULE(CONFIG_öneki olmadan) kullanın.Başlık dosyaları doğrudan ikili programa derlenmediği, bunun yerine bir C dosyasının (veya diğer kaynak dosyaların) parçası olarak derlendiği için başlık dosyalarında aynı kontrol daha zordur. Başlık dosyaları için aşağıdaki kuralları kullanın:
#ifdef MODULEkullanan bir üstbilgi dosyası için sonuç, hangi kaynak dosyanın kullandığına bağlı olarak değişir. Bu, aynı derlemedeki aynı başlık dosyasının kodunun farklı bölümlerinin farklı kaynak dosyalar için (modül ve yerleşik veya devre dışı) derlenebileceği anlamına gelir. Bu, yerleşik kod için bir şekilde genişlemesi ve bir modül için farklı bir şekilde genişlemesi gereken bir makro tanımlamak istediğinizde yararlı olabilir.Belirli bir
CONFIG_XXXmodül olarak ayarlandığında (kaynak dosya modül olup olmadığına bakılmaksızın) bir kod parçasında derlenmesi gereken bir üstbilgi dosyası için üstbilgi dosyası#ifdef CONFIG_XXX_MODULEkullanmalıdır.