Tedarikçi modülü yönergeleri

Tedarikçi modüllerinizin sağlamlığını ve güvenilirliğini artırmak için aşağıdaki yönergeleri kullanın. Birçok kurala uyulduğunda, doğru modül yükleme sırasını ve sürücülerin cihazları taraması gereken sırayı belirlemek kolaylaşabilir.

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 özel değildir. Kitaplık modüllerine örnek olarak AES şifreleme modülü, modül olarak derlenen remoteproc çerçevesi ve günlük arabelleği 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ü arayan veya bu cihaz türüne bağlanan sürücülerdir. Bu modüller donanıma özgüdür. 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 cihaz sistemde bulunduğunda etkinleştirilir.

    • Cihaz mevcut değilse çalışan tek modül kodu, sürücüyü sürücü çekirdek çerçevesine kaydeden module_init() kodudur.

    • Cihaz mevcutsa ve sürücü bu cihazı başarıyla araştırırsa veya ona bağlanırsa diğer modül kodu çalışabilir.

Modül başlatma ve çıkış işlevlerini doğru şekilde kullanma

Sürücü modülleri, module_init() ürününde bir sürücüyü kaydetmeli ve module_exit() ürününde bir sürücünün kaydını iptal etmelidir. Bu kısıtlamaları uygulamanın bir yolu, module_init(), *_initcall() veya module_exit() makrolarının doğrudan kullanımını önleyen sarmalayıcı makroları kullanmaktır.

  • Yükün kaldırılabileceği modüller için module_subsystem_driver() simgesini kullanın. Örnekler: module_platform_driver(), module_i2c_driver() ve module_pci_driver().

  • Boşaltılamayacak modüller için builtin_subsystem_driver() örnekleri kullanın: builtin_platform_driver(), builtin_i2c_driver() ve builtin_pci_driver().

Bazı sürücü modülleri, birden fazla sürücü kaydettikleri için module_init() ve module_exit() kullanır. Birden fazla sürücüyü kaydettirmek için module_init() ve module_exit() kullanan bir sürücü modülünde sürücüleri tek bir sürücüde birleştirmeyi deneyin. Örneğin, ayrı sürücüler kaydettirmek yerine compatible dizesini veya cihazın 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 veri yapıları, iş sıraları veya çekirdek iş parçacıkları oluşturmak için bu işlevlere ihtiyaç duyabileceğinden module_init() ve module_exit() ile ilgili kısıtlamalardan muaftır.

MODULE_DEVICE_TABLE makrosunu kullanma

Sürücü modülleri, kullanıcı alanının modülü yüklemeden önce sürücü modülü tarafından desteklenen cihazları belirlemesine olanak tanıyan MODULE_DEVICE_TABLE makrosunu içermelidir. Android, sistemde bulunmayan cihazların modüllerini yüklemekten kaçınmak gibi yöntemlerle modül yüklemeyi optimize etmek için bu verileri kullanabilir. Makroyu kullanmayla ilgili örnekler için yayın öncesi koda bakın.

Önceden tanımlanmış veri türleri nedeniyle CRC uyuşmazlıklarından kaçının

Önceden tanımlanmış veri türlerini görmek için üstbilgi dosyalarını eklemeyin. Bir başlık dosyasında (header-A.h) tanımlanan bazı yapıların, birliklerin ve diğer veri türlerinin, genellikle bu veri türlerine işaretçiler kullanan farklı bir başlık dosyasında (header-B.h) ileriye dönük olarak tanımlanması mümkündür. Bu kod kalıbı, çekirdeğin veri yapısını header-B.h kullanıcılarına karşı kasıtlı olarak gizli tutmaya çalıştığı anlamına gelir.

header-B.h kullanıcıları, önceden bildirilmiş bu veri yapılarının iç kısımlarına doğrudan erişmek için header-A.h içermemelidir. Bu işlem, farklı bir çekirdek (ör. GKI çekirdeği) modülü yüklemeye çalıştığında CONFIG_MODVERSIONS CRC uyuşmazlığı sorunlarına (ABI uyumluluğu sorunlarına neden olur) yol açar.

Örneğin, struct fwnode_handle include/linux/fwnode.h içinde tanımlanır ancak çekirdek, struct fwnode_handle ayrıntılarını include/linux/device.h kullanıcılarından gizli tutmaya çalıştığı için include/linux/device.h içinde struct fwnode_handle; olarak ileriye dönük olarak bildirilir. Bu senaryoda, struct fwnode_handle üyelerine erişmek için 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ını gösterir.

Temel çekirdek yapılarına doğrudan erişmeyin

Çekirdek çekirdek veri yapılarına doğrudan erişmek veya bu yapıları değiştirmek, bellek sızıntısı, kilitlenme ve gelecekteki çekirdek sürümleriyle uyumluluğun bozulması gibi istenmeyen davranışlara neden olabilir. Aşağıdaki koşullardan herhangi birini karşılayan veri yapıları, temel çekirdek veri yapısıdır:

  • Veri yapısı KERNEL-DIR/include/ altında tanımlanır. Örneğin, struct device ve struct dev_links_info. include/linux/soc içinde tanımlanan veri yapıları bu kapsamda değildir.

  • Veri yapısı modül tarafından ayrılır veya başlatılır ancak çekirdek tarafından dışa aktarılan bir işleve giriş olarak dolaylı olarak (bir yapıdaki işaretçi aracılığıyla) veya doğrudan aktarılarak çekirdek tarafından görünür hale getirilir. Örneğin, bir cpufreq sürücü modülü struct cpufreq_driver öğesini başlatır ve ardından cpufreq_register_driver() cihazına giriş olarak iletir. Bu noktadan sonra cpufreq sürücü modülü, cpufreq_register_driver() çağrıldığında struct cpufreq_driver çekirdeğe görünür hale geldiği için struct cpufreq_driver'yi doğrudan değiştirmemelidir.

  • Veri yapısı, modülünüz tarafından başlatılmamıştır. Örneğin, regulator_register() tarafından döndürülen struct regulator_dev.

Temel çekirdek veri yapılarına yalnızca çekirdek tarafından dışa aktarılan işlevler veya tedarikçi 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'niz veya tedarikçi kancanız yoksa bu durum muhtemelen bilinçli olarak yapılmış demektir ve veri yapısını modüllerden değiştirmemeniz gerekir. Örneğin, struct device veya struct device.links içindeki alanları değiştirmeyin.

  • device.devres_head değerini değiştirmek için devm_clk_get(), devm_regulator_get() veya devm_kzalloc() gibi bir devm_*() işlevi kullanın.

  • struct device.links içindeki alanları değiştirmek için device_link_add() veya device_link_del() gibi bir cihaz bağlantısı API'si kullanın.

Uyumlu mülke sahip devicetree düğümlerini ayrıştırma

Bir cihaz ağacı (DT) düğümünde compatible mülkü varsa struct device otomatik olarak veya üst DT düğümünde of_platform_populate() çağrıldığında (genellikle üst cihazın cihaz sürücüsü tarafından) atanır. Varsayılan beklenti (planlayıcı için erken başlatılan bazı cihazlar hariç), compatible özelliğine sahip 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, yayın öncesi kod tarafından zaten ele alınmıştır.

Ayrıca fw_devlink (eski adıyla of_devlink), compatible mülküne sahip DT düğümlerini, bir sürücü tarafından taranan ayrılmış struct device içeren cihazlar olarak kabul eder. Bir DT düğümünde compatible mülkü varsa ancak ayrılan struct device taranmıyorsa fw_devlink, tüketici cihazlarının taranmasını veya tedarikçi cihazları için sync_state() çağrılarının yapılmasını engelleyebilir.

Sürücünüzde, compatible mülkü olan bir DT düğümünü doğrudan bulup ardından bu DT düğümünü ayrıştırmak için bir of_find_*() işlevi (of_find_node_by_name() veya of_find_compatible_node() gibi) kullanılıyorsa cihazı kontrol edebilecek veya compatible mülkünü kaldırabilecek (yalnızca yayına aktarılmamışsa mümkündür) bir cihaz sürücüsü yazarak modülü düzeltin. Alternatifleri görüşmek için kernel-team@android.com adresinden Android Çekirdek Ekibi ile iletişime geçin ve kullanım alanlarınızı gerekçelendirmeye hazır olun.

Tedarikçi firmaları aramak için DT phandle'lerini kullanma

Mümkün olduğunda DT'de bir phandle (DT düğümüne referans veya işaretçi) kullanarak tedarikçiye referans verin. Tedarikçilere referans vermek için standart DT bağlamaları ve p elleri kullanmak, fw_devlink (eski adıyla of_devlink), DT'yi çalışma zamanında ayrıştırarak cihazlar arası bağımlılıkları otomatik olarak belirlemesini sağlar. Böylece çekirdek, modül yükleme sırası veya MODULE_SOFTDEP()'ye gerek kalmadan cihazları otomatik olarak doğru sırada tarayabilir.

Eski senaryo (ARM çekirdeğinde DT desteği yok)

Daha önce, DT desteği ARM çekirdeklerine eklenmeden önce dokunmatik cihazlar gibi tüketiciler, dünya genelinde benzersiz dizeler kullanarak düzenleyiciler gibi tedarikçileri aradı. Örneğin, ACME PMIC sürücüsü birden fazla regülatörü (acme-pmic-ldo1 ila acme-pmic-ldo10 gibi) kaydedebilir veya tanıtabilir ve bir dokunmatik sürücü regulator_get(dev, "acme-pmic-ldo10") kullanarak bir regülatörü arayabilir. Ancak farklı bir kartta LDO8, dokunmatik cihazı besleyebilir. Bu durumda, aynı dokunmatik sürücünün, dokunmatik cihazın kullanıldığı her kart için regülatöre ait doğru arama dizesini belirlemesi gereken hantal bir sistem oluşturulur.

Mevcut senaryo (ARM çekirdeğinde DT desteği)

DT desteği ARM çekirdeklerine 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ğın adını tedarik edene göre değil, kaynağın ne için kullanıldığına göre de adlandırabilir. Örneğin, önceki örnekteki dokunmatik sürücü, dokunmatik cihazın çekirdeğini ve sensörünü destekleyen tedarikçileri almak için regulator_get(dev, "core") ve regulator_get(dev, "sensor") kullanabilir. Bu tür bir cihaz için 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 {
        ...
    };
};

İkisi için de en kötü senaryo

Eski çekirdeklerden aktarılan bazı sürücülerde, eski şemanın en kötü bölümünü alıp işleri kolaylaştırmak amacıyla yeni şemaya zorlayan eski davranış DT'de yer alır. Bu tür sürücülerde, tüketici sürücüsü cihaza özgü bir DT mülkünü kullanarak arama için kullanılacak dizeyi okur, tedarikçi tedarikçi kaynağını kaydettirmek için kullanılacak adı tanımlamak üzere başka bir tedarikçiye özgü mülkü kullanır, ardından tüketici ve tedarikçi, tedarikçiyi aramak için dizeleri kullanmaya devam eder. Her iki dünyanın da en kötüsünü içeren bu senaryoda:

  • Dokunmatik sürücü, 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 yoklama yapmaya çalıştığını ancak şu anda olmadığını ve çekirdeğin yoklamayı daha sonra tekrar denemesi gerektiğini belirten hata döndürme değeri olarak -EPROBE_DEFER döndürür. Bu gibi durumlarda cihazınızın .probe() işlevinin beklendiği gibi çalışmaması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 değerinin atlanmasına ve cihazınızın hiçbir zaman taranmasına neden olabilir.

devm_*() API varyantlarını kullanma

Cihaz bir devm_*() API'yi kullanarak kaynak edindiğinde, cihaz sondalama işlemini yapamazsa veya başarılı bir şekilde sondalama yapar ve daha sonra bağ bağlama işlemi iptal edilirse kaynak çekirdek tarafından otomatik olarak serbest bırakılır. Bu özellik, devm_*() tarafından edinilen kaynakları serbest bırakmak için goto atlamaları gerektirmediğinden ve sürücü bağlama işlemlerini basitleştirdiğinden probe() işlevindeki hata işleme kodunu daha temiz hale getirir.

Cihaz sürücüsünün bağlantısını kaldırma işlemini yönetme

Cihaz sürücülerinin bağlamasını kaldırma konusunda dikkatli olun ve bağlama kaldırma işlemini tanımlı olmayan olarak bırakmayın. Tanımlı olmayan, izin verilmediği anlamına gelmez. Cihaz-sürücü bağlantısını kaldırmayı tam olarak uygulamanız veya cihaz sürücüsü bağlantısını kaldırmayı açıkça devre dışı bırakmanız gerekir.

Cihaz sürücüsünün bağlantısını kaldırma işlemini uygulama

Cihaz sürücüsünün bağlantısını kaldırma özelliğini tam olarak uygulamayı seçtiğinizde, bellek veya kaynak sızıntıları ve güvenlik sorunlarını önlemek için cihaz sürücülerinin bağlantısını temiz bir şekilde kaldırın. Bir sürücünün probe() işlevini çağırarak cihazı sürücüye bağlayabilir ve sürücünün remove() işlevini çağırarak cihazın sürücüyle olan bağlantısını kaldırabilirsiniz. remove() işlevi yoksa çekirdek yine de cihazın bağlamasını kaldırabilir. Sürücü çekirdeği, sürücü cihazla bağlantısını kaldırırken temizleme çalışması gerekmediğini varsayar. Bir cihazdan ayrılan sürücünün, aşağıdakilerin her ikisi de doğru olduğunda herhangi bir temizleme çalışması yapması gerekmez:

  • Sürücülerin probe() işlevi tarafından edinilen tüm kaynaklar devm_*() API'leri aracılığıyla elde edilir.

  • Donanım cihazının kapatılması veya bekleme durumuna geçirilmesi gerekmez.

Bu durumda, sürücü çekirdeği devm_*() API'leri aracılığıyla edinilen tüm kaynakların serbest bırakılmasını yönetir. Yukarıdaki ifadelerden herhangi biri doğru değilse sürücünün, bir cihazla bağlantısını kaldırırken temizleme işlemi yapması (kaynakları serbest bırakma ve donanımı kapatma veya beklemeye alma) gerekir. Bir cihazın sürücü modülünün bağlamasını düzgün bir şekilde kaldırabilmesini sağlamak için aşağıdaki seçeneklerden birini kullanın:

  • Donanımın kapatılması veya bekleme durumuna geçirilmesi gerekmiyorsa cihaz modülünü, devm_*() API'lerini kullanarak kaynak edinecek şekilde değiştirin.

  • remove() sürücü işlemini probe() işleviyle aynı yapıda uygulayın, ardından remove() işlevini kullanarak temizleme adımlarını uygulayın.

Cihaz-sürücü bağlantısını kaldırmayı açık bir şekilde devre dışı bırakın (önerilmez)

Cihaz-sürücü bağlantısını kaldırma özelliğini açık bir şekilde devre dışı bırakmayı seçtiğinizde, bağlantı kaldırma işlemine izin vermemeniz ve modül kaldırma işlemine izin vermemeniz gerekir.

  • Bağlantıyı kaldırmaya izin vermemek için sürücünün struct device_driver dosyasında suppress_bind_attrs işaretini true olarak ayarlayın. Bu ayar, bind ve unbind dosyalarının sürücünün sysfs dizininde gösterilmesini engeller. unbind dosyası, kullanıcı alanının bir sürücünün cihazıyla olan bağlamasını kaldırmayı tetiklemesine olanak tanır.

  • Modül kaldırılmasına izin vermemek için modülün lsmod içinde [permanent] bulunduğundan emin olun. module_exit() veya module_XXX_driver() kullanılmadığında modül [permanent] olarak işaretlenir.

Donanım yazılımını yoklama işlevi içinden yüklemeyin

Sürücü, flaş veya kalıcı depolama tabanlı dosya sistemi monte edilmeden önce durum kontrolü yaparsa donanım yazılımına erişemeyebilir. Bu nedenle sürücü, .probe() işlevi içinden donanım yazılımını yüklememelidir. Bu tür durumlarda request_firmware*() API uzun süre engelleme yapıp daha sonra başarısız olabilir. Bu da başlatma işlemini gereksiz biçimde yavaşlatabilir. Bunun yerine, donanım yazılımının yüklenmesini istemcinin cihazı kullanmaya başlayacağı zamana erteleyin. Örneğin, ekran sürücüsü, donanım yazılımını ekran cihazı açıldığında yükleyebilir.

Donanım yazılımının çalışması için donanım yazılımına ihtiyacı olan ancak cihazın kullanıcı alanına maruz kalmadığı bir saat sürücüsünde olduğu gibi bazı durumlarda donanım yazılımını yüklemek için .probe() kullanılması uygun olabilir. Uygun diğer kullanım alanları da mümkündür.

Eşzamansız araştırmayı uygulama

Gelecekteki sürümlerde Android'e eklenebilecek paralel modül yükleme veya cihazı tarama gibi gelecekteki geliştirmelerden yararlanmak için asenkron tarama özelliğini destekleyin ve kullanın. Bu sayede, önyükleme süresini kısaltabilirsiniz. Asenkron problama kullanmayan sürücü modülleri, bu tür optimizasyonların etkinliğini azaltabilir.

Bir sürücüyü, asenkron problamayı desteklediği ve tercih ettiği şekilde işaretlemek için sürücünün struct device_driver üyesindeki probe_type alanını ayarlayın. Aşağıdaki örnekte, platform sürücüsü için bu tür desteğin 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 problamayla çalışmasını sağlamak için özel kod gerekmez. Ancak, asenkron problama desteği eklerken aşağıdakileri göz önünde bulundurun.

  • Daha önce taranan bağımlılıklarla ilgili varsayımda bulunmayın. Bir veya daha fazla tedarikçi henüz hazır değilse doğrudan veya dolaylı olarak (çoğu çerçeve çağrısı) kontrol edin ve -EPROBE_DEFER döndürün.

  • Ebeveyn cihazının yoklama işlevine çocuk cihazları eklerseniz alt cihazların hemen kontrol edileceğini varsaymayın.

  • Bir kontrol başarısız olursa hata işlemeyi uygun şekilde gerçekleştirin ve hataları temizleyin (devm_*() API varyantlarını kullanma bölümüne bakın).

Cihaz problarını sipariş etmek için MODULE_SOFTDEP kullanmayın

MODULE_SOFTDEP() işlevi, cihaz probları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.

  • Ertelenen kontrol. Bir modül yüklenirken cihaz yoklamasının tedarikçilerinden biri hazır olmadığı için cihaz yoklaması ertelenebilir. Bu durum, modül yükleme sırası ile cihaz probu sırası arasında uyuşmazlığa neden olabilir.

  • Tek bir 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 prob siparişi koşulu varsa modül yükleme sırasını kullanarak bu koşullara uyamazsınız.

  • Eşzamansız durum kontrolü. Asenkron problama gerçekleştiren sürücü modülleri, modül yüklendiğinde cihazı hemen taramamaktadır. Bunun yerine, cihaz problaması paralel bir iş parçacığı tarafından yönetilir. Bu da modül yükleme sırası ile cihaz problama sırası arasında uyuşmazlığa neden olabilir. Örneğin, bir I2C ana sürücü modülü asenkron problama gerçekleştirdiğinde ve bir dokunmatik sürücü modülü I2C veriyolundaki PMIC'ye bağlı olduğunda, dokunmatik sürücü ve PMIC sürücüsü doğru sırada yüklenirse bile dokunmatik sürücünün problaması PMIC sürücü problamasından önce denenebilir.

MODULE_SOFTDEP() işlevini kullanan sürücü modülleriniz varsa bunları kullanmamaları için düzeltin. Size yardımcı olmak için Android ekibi, çekirdeğin MODULE_SOFTDEP() kullanmadan sipariş sorunlarını ele almasını sağlayan değişiklikler yayınladı. Özellikle, durum kontrolü sağlamak için fw_devlink kullanabilir ve (cihazın tüm tüketicileri kontrol edildikten sonra) gerekli görevleri gerçekleştirmek için sync_state() geri çağırma özelliğinden yararlanabilirsiniz.

Yapılandırmalar için #ifdef yerine #if IS_ENABLED() kullanın

Gelecekte yapılandırma üç değerli bir yapılandırmaya değişirse #if bloğundaki kodun derlenmeye devam etmesini sağlamak için #ifdef CONFIG_XXX yerine #if IS_ENABLED(CONFIG_XXX) kullanın. Farklar aşağıda belirtilmiştir:

  • CONFIG_XXX modül (=m) veya yerleşik (=y) olarak ayarlandığında #if IS_ENABLED(CONFIG_XXX) true değerini alır.

  • CONFIG_XXX yerleşik (=y) olarak ayarlandığında #ifdef CONFIG_XXX true değerini alır ancak CONFIG_XXX modül (=m) olarak ayarlandığında bu değere ulaşmaz. Bu işlevi yalnızca yapılandırma modül olarak ayarlandığında veya devre dışı bırakıldığında aynı işlemi yapmak istediğinizden emin olduğunuzda kullanın.

Koşullu derlemeler için doğru makroyu kullanın

Bir CONFIG_XXX modül (=m) olarak ayarlanırsa derleme sistemi CONFIG_XXX_MODULE'yi 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 dosyada) #ifdef CONFIG_XXX_MODULE kullanmayın. Bu, gereksiz yere kısıtlayıcıdır ve yapılandırma CONFIG_XYZ olarak yeniden adlandırılırsa çalışmaz. Bir modüle derlenen başlık olmayan tüm kaynak dosyalar için derleme sistemi, söz konusu dosyanın kapsamı için MODULE değerini otomatik olarak tanımlar. Bu nedenle, bir C dosyasının (veya başlık dışı herhangi bir kaynak dosyanın) modülün parçası olarak derlenip derlenmediğini kontrol etmek için #ifdef MODULE (CONFIG_ öneki olmadan) işlevini kullanın.

  • Başlık dosyaları doğrudan ikili program dosyası olarak derlenmediğinden, bu tür dosyalarda aynı kontrolü yapmak daha zordur. Başlık dosyaları, C dosyası (veya diğer kaynak dosyalar) kapsamında derlenir. Başlık dosyaları için aşağıdaki kuralları kullanın:

    • #ifdef MODULE kullanan bir başlık dosyası için sonuç, hangi kaynak dosyanın bunu 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 derlenmiş olabileceği anlamına gelir (modül ve yerleşik veya devre dışı). Bu, yerleşik kod için bir şekilde, modül için farklı bir şekilde genişletilmesi gereken bir makro tanımlamak istediğinizde yararlı olabilir.

    • Belirli bir CONFIG_XXX modül olarak ayarlandığında bir kod parçasında derlenmesi gereken bir üstbilgi dosyası için (bu üstbilgiyi içeren kaynak dosyanın modül olup olmadığına bakılmaksızın), üstbilgi dosyası #ifdef CONFIG_XXX_MODULE kullanmalıdır.