[PATCH 1/2] linux/kconfig.h: generalize IS_ENABLED logic
From: Rasmus Villemoes
Date: Tue Oct 06 2015 - 17:06:26 EST
It's not hard to generalize the macro magic used to build the
IS_ENABLED macro and friends to produce a few other potentially useful
macros:
CHOOSE_EXPR(CONFIG_FOO, expr): if CONFIG_FOO is set expands to
expr, otherwise expands to nothing.
CHOOSE_EXPR(CONFIG_FOO, expr1, expr2): if CONFIG_FOO is set,
expands to expr1, otherwise expands to expr2.
While the latter is roughly the same as
__builtin_choose_expr(IS_ENABLED(CONFIG_FOO), expr1, expr2), the macro
version has the advantage that expr1 and expr2 may be string literals,
and they would preserve their ability to be concatenated with other
string literals. For example, this little snippet
#ifdef CONFIG_X86_64
" x86-tsc: TSC cycle counter\n"
#endif
from kernel/trace/trace.c (which is surrounded by other string
literals) could be written as
CHOOSE_EXPR(CONFIG_X86_64, " x86-tsc: TSC cycle counter\n")
We're also not really restricted to expressions in the C sense; the
only limitation I can see is that they cannot contain unparenthesized
commas. (Obviously, if one starts getting too creative, readability
will suffer rather than increase.)
Similarly, we can define helpers for conditional struct members and
their associated initializers. It would probably take some time to get
used to reading, to pick another random example,
struct task_struct {
...
COND_DECLARATION(CONFIG_KASAN, unsigned int kasan_depth)
...
}
#define INIT_KASAN(tsk) COND_INITIALIZER(CONFIG_KASAN, .kasan_depth = 1)
[and I'm certainly not proposing any mass conversion], but I think it
might be nice to avoid lots of short #ifdef/#else/#endif sections. The
above would replace 3 and 5 lines, respectively. Also, git grep'ing
for CONFIG_KASAN currently just reveals that _something_ in sched.h
and init_task.h depends on it; with the above, one could at least
deduce that it's guarding a certain member of some struct.
Namewise, I think CHOOSE_EXPR is appropriate because of its similarity
to __builtin_choose_expr, but I'm not sure about the COND_* ones. Feel
free to suggest better names, and/or to flame this idea to death.
Signed-off-by: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx>
---
include/linux/kconfig.h | 75 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/include/linux/kconfig.h b/include/linux/kconfig.h
index b33c7797eb57..ac209814b111 100644
--- a/include/linux/kconfig.h
+++ b/include/linux/kconfig.h
@@ -51,4 +51,79 @@
#define IS_ENABLED(option) \
(IS_BUILTIN(option) || IS_MODULE(option))
+/*
+ * CHOOSE_EXPR, COND_DECLARATION and COND_INITIALIZER only work for
+ * boolean config options.
+ *
+ * CHOOSE_EXPR(CONFIG_FOO, expr): if CONFIG_FOO is set expands to
+ * expr, otherwise expands to nothing.
+ *
+ * CHOOSE_EXPR(CONFIG_FOO, expr1, expr2): if CONFIG_FOO is set,
+ * expands to expr1, otherwise expands to expr2.
+ *
+ * COND_DECLARATION(CONFIG_FOO, decl): if CONFIG_FOO is set, expands to
+ *
+ * decl;
+ *
+ * (a semicolon should not be part of decl), otherwise expands to
+ * nothing.
+ *
+ * COND_INITIALIZER(CONFIG_FOO, init): if CONFIG_FOO is set, expands to
+ *
+ * init,
+ *
+ * otherwise expands to nothing.
+ *
+ * CHOOSE_EXPR(CONFIG_FOO, expr1, expr2) is roughly equivalent to
+ * __builtin_choose_expr(IS_ENABLED(CONFIG_FOO), expr1,
+ * expr2). However, since the expansion is done by the preprocessor,
+ * expr1 and expr2 can be string literals which can then participate
+ * in string concatenation. Also, we're not really limited to
+ * expressions, and can choose to expand to nothing (this is also used
+ * internally by the COND_* macros). The only limitation is that expr1
+ * and expr2 cannot contain unparenthesized commas.
+ *
+ * COND_DECLARATION can, for example, be used inside a struct
+ * declaration to eliminate a #ifdef/#endif pair. This would look
+ * something like
+ *
+ * struct foo {
+ * int a;
+ * COND_DECLARATION(CONFIG_FOO_DEBUG, int b)
+ * int c;
+ * };
+ *
+ * COND_INITIALIZER is the companion for initializing such
+ * conditionally defined members, again for eliminating the bracketing
+ * #ifdef/#endif pair.
+ *
+ * struct foo f = {
+ * .a = 1,
+ * COND_INITIALIZER(CONFIG_FOO_DEBUG, .b = 2)
+ * .c = 3
+ * };
+ *
+ * This is mostly useful when only a single or a few members would be
+ * protected by the #ifdef/#endif. One advantage of the COND_* macros
+ * is that git grep'ing for CONFIG_FOO_DEBUG reveals more information
+ * (above, we would see that it protects the "b" member of some
+ * struct).
+ */
+
+#define _COMMA ,
+#define _COND_PUNCTUATION_0(p)
+#define _COND_PUNCTUATION_1(p) p
+
+#define CHOOSE_EXPR(cfg, expr, ...) _CHOOSE_EXPR(cfg, expr, ##__VA_ARGS__, /* empty defalt arg */)
+#define _CHOOSE_EXPR(cfg, expr, def, ...) __CHOOSE_EXPR(__ARG_PLACEHOLDER_##cfg, expr, def)
+#define __CHOOSE_EXPR(arg1_or_junk, expr, def) ___CHOOSE_EXPR(arg1_or_junk expr, def)
+#define ___CHOOSE_EXPR(__ignored, expr, ...) expr
+
+#define COND_DECLARATION(cfg, decl) _COND_DECLARATION(cfg, decl, CHOOSE_EXPR(cfg, 1, 0))
+#define _COND_DECLARATION(cfg, decl, sfx) __COND_DECLARATION(cfg, decl, sfx)
+#define __COND_DECLARATION(cfg, decl, sfx) CHOOSE_EXPR(cfg, decl) _COND_PUNCTUATION_##sfx(;)
+#define COND_INITIALIZER(cfg, init) _COND_INITIALIZER(cfg, init, CHOOSE_EXPR(cfg, 1, 0))
+#define _COND_INITIALIZER(cfg, init, sfx) __COND_INITIALIZER(cfg, init, sfx)
+#define __COND_INITIALIZER(cfg, init, sfx) CHOOSE_EXPR(cfg, init) _COND_PUNCTUATION_##sfx(_COMMA)
+
#endif /* __LINUX_KCONFIG_H */
--
2.1.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/