Linux kernel中的IS_ENABLED
阿新 • • 發佈:2020-11-18
include/config# ls 64bit auto.conf build cpusets.h dql.h fair generic inet.h kasan memfd network paravirt.h preempt rwsem slub.h swiotlb.h trace virtio 64bit.h auto.conf.cmd buildtime crc16.h drm fanotify.h gro init kernel memory nf partition printk sbitmap.h smp.h syn tracing virtio.h 9p autofs cc crc32 dtc.h fhandle.h handle initramfs kernel.release message nlattr.h pci printk.h sched sock sys tree vm acpi autofs4 cfs crc32.h dummy fib harden inline kernfs.h migration.h nls pcieaspm proc scsi sparse sysctl tristate.conf vmap acpi.hbase cgroup crypto edac file hardirqs inotify libcrc32c.h mmu.h nls.h pcieaspm.h ptp scsi.h sparsemem sysctl.h tty.h vsockets.h advise bcma cgroups.h crypto.h efi fix has input.h libfdt.h modules no pcieportbus.h queued seccomp sparsemem.h sysfs ubsan vt aio.h binfmt clang dax efi.h font have io libnvdimm.h msdos nr pci.h randomize seccomp.h split sysfs.h ucs2 vt.h allow bitreverse.h clkdev dax.h elf force high ion.h llc.h multiuser.h nvdimm perf rational.h section srcu.h sysvipc unix xarray android blk clone dcache elfcore.h frame holes ip localversion.h mutex nvmem.h pgtable rcu security.h ssb sysvipc.h unix98 xfrm android.h block.h cmdline.h debug epoll.h freezer.h hotplug ipclock namespaces.h of phys rd select stackprotector tcp unix.h xfrm.h arch bpf common decompress ethernet.h fs hugetlb ipv6 lockdep nd of.h pid refcount serial stackprotector.h textsearch unmap xfs arm bpf.h compaction.hdefault eventfd.h fsnotify.h hugetlbfs.h ipv6.h log need optimize plugin relocatable.h sg stacktrace textsearch.h usb xps.h arm64 bql.h console dev exportfs fuse hvc irq lsm.h net overlay pnpacpi.h rfs sgl staging thread user xz arm64.h bridge context devtmpfs exportfs.h futex hw irqchip.h mandatory netdevices.h packet pnp.h rps.h shmem.h staging.h tick uts zlib ashmem.h bridge.h contig devtmpfs.h ext4 futex.h hz jbd2.h membarrier.h netfilter packet.h posix rseq.h signalfd.h stp.h timer veth.h zone asn1.h btt.h coredump.h dma extra fw hz.h kallsyms memcg netfilter.h page power rt skb strict timerfd.h vga audit bug.h cpu dnotify.h failover.h gcc illegal kallsyms.h memcg.h net.h panic pps.h rtc slub swap.h tmpfs.h virt
在kernel的程式碼中, 有時候會看見IS_ENABLED(CONFIG_XXXX)
來測試某個Kconfig選項是否開啟(即選中為y
或者m
). 如
if (IS_ENABLED(CONFIG_TIME_LOW_RES) && timer->is_rel)
rem -= hrtimer_resolution;
這裡當TIME_LOW_RES這個Kconfig選項配置為y
或m
, 並且timer->is_rel
不為0時呼叫rem -= hrtimer_resolution
.
那麼這個是怎樣實現的呢?
首先在Kconfig中選中某個選項為y
或m
時, 在.config
檔案中就會由一個CONFIG_XXXXX=y
或CONFIG_XXXXX=m
, 並且會自動生成一個頭檔案autoconfig.h
. 當選中為y
時, 標頭檔案中包含#define CONFIG_XXXXX 1
, 當選中為m
時, 標頭檔案中包含#define CONFIG_XXXXX_MODULE 1
, 當不選中是, 標頭檔案中不包含相關語句.IS_ENABLED
定義為
#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option))
IS_BUILTIN
,IS_MODULE
和__or
分別定義為
#define IS_BUILTIN(option) __is_defined(option)
#define IS_MODULE(option) __is_defined(option##_MODULE)
#define __or(x, y) ___or(x, y)
#define ___or(x, y) ____or(__ARG_PLACEHOLDER_##x, y)
#define ____or(arg1_or_junk, y) __take_second_arg(arg1_or_junk 1, y)
__is_defined
定義為
#define __is_defined(x) ___is_defined(x)
#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val)
#define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0)
在這之前定義了
#define __ARG_PLACEHOLDER_1 0,
#define __take_second_arg(__ignored, val, ...) val
當#define CONFIG_XXXXX 1
時__is_defined(1)
展開為____is_defined(0,)
, 即__take_second_arg(0, 1, 0)
, 最終為1
當CONFIG_XXXXX
沒有定義時__is_defined()
展開為____is_defined()
(因為沒有定義__ARG_PLACEHOLDER_), 即__take_second_arg(1, 0)
, 最終為0
同樣的方法可以理解__or
.
因此IS_ENABLED
主要是將沒有定義的CONFIG_XXXXX
對映到0.