1. 程式人生 > 實用技巧 >Linux kernel中的IS_ENABLED

Linux kernel中的IS_ENABLED

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選項配置為ym, 並且timer->is_rel不為0時呼叫rem -= hrtimer_resolution.
那麼這個是怎樣實現的呢?
首先在Kconfig中選中某個選項為ym時, 在.config檔案中就會由一個CONFIG_XXXXX=yCONFIG_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.