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.h base 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 ipc lock 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.h default 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.