When the options "prefix" or "configfile" are given to a "menu" entry then the childs of that menu are given an independent namspace with its own config data file. Signed-off-by: Konrad Eisele <konrad@xxxxxxxxxxx> --- Documentation/kbuild/kconfig-language.txt | 21 ++++++++++- scripts/kconfig/confdata.c | 24 ++++++------ scripts/kconfig/expr.h | 5 +++ scripts/kconfig/lkc_proto.h | 8 +++- scripts/kconfig/menu.c | 48 ++++++++++++++++++++++++- scripts/kconfig/symbol.c | 26 +++++++++++-- scripts/kconfig/zconf.gperf | 2 + scripts/kconfig/zconf.y | 56 +++++++++++++++++++++++----- 8 files changed, 159 insertions(+), 31 deletions(-) diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt index 44e2649..ae57d86 100644 --- a/Documentation/kbuild/kconfig-language.txt +++ b/Documentation/kbuild/kconfig-language.txt @@ -240,6 +240,23 @@ MODULES is different from 'n'. The comment on the other hand is always visible when MODULES is visible (the (empty) dependency of MODULES is also part of the comment dependencies). +Subtree Menus +------------- + +It is possible to add other configuration trees as independent subtrees. To do so +you have to specify the "prefix" or "configfile" options to a "menu" entry. This will +create a independent namespace for the menu's childs, with its own config data file. + +menu "SPARC subtree" + prefix "CONFIG_" + configfile "CONFIG_" + +source "arch/sparc/Kconfig" + +endmenu + +The "prefix" option specifies the prefix when writing/reading a config data file. +The "configfile" option specifies the default config data file to use for the subtree. Kconfig syntax -------------- @@ -310,8 +327,8 @@ menu: "endmenu" This defines a menu block, see "Menu structure" above for more -information. The only possible options are dependencies and "visible" -attributes. +information. The possible options are dependencies, "visible" +attributes and subtree definition. if: diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 25c29c8..3446dc4 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -253,7 +253,7 @@ load: if (line[0] == '#') { if (memcmp(line + 2, l->conf_prefix, strlen(l->conf_prefix))) continue; - p = strchr(line + 2 + strlen(CONFIG_), ' '); + p = strchr(line + 2 + strlen(l->conf_prefix), ' '); if (!p) continue; *p++ = 0; @@ -283,7 +283,7 @@ load: ; } } else if (memcmp(line, l->conf_prefix, strlen(l->conf_prefix)) == 0) { - p = strchr(line + strlen(CONFIG_), '='); + p = strchr(line + strlen(l->conf_prefix), '='); if (!p) continue; *p++ = 0; @@ -455,7 +455,7 @@ kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) if (!skip_unset) fprintf(fp, "# %s%s is not set\n", - CONFIG_, sym->name); + sym->level->conf_prefix, sym->name); return; } break; @@ -463,7 +463,7 @@ kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) break; } - fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); + fprintf(fp, "%s%s=%s\n", sym->level->conf_prefix, sym->name, value); } static void @@ -514,7 +514,7 @@ header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) /* fall through */ default: fprintf(fp, "#define %s%s%s 1\n", - CONFIG_, sym->name, suffix); + sym->level->conf_prefix, sym->name, suffix); } break; } @@ -524,13 +524,13 @@ header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) prefix = "0x"; fprintf(fp, "#define %s%s %s%s\n", - CONFIG_, sym->name, prefix, value); + sym->level->conf_prefix, sym->name, prefix, value); break; } case S_STRING: case S_INT: fprintf(fp, "#define %s%s %s\n", - CONFIG_, sym->name, value); + sym->level->conf_prefix, sym->name, value); break; default: break; @@ -578,9 +578,9 @@ header_print__enabled_symbol(FILE *fp, struct symbol *sym, const char *value, vo switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: { - fprintf(fp, "#define __enabled_" CONFIG_ "%s %d\n", + fprintf(fp, "#define __enabled_%s%s %d\n", sym->level->conf_prefix, sym->name, (*value == 'y')); - fprintf(fp, "#define __enabled_" CONFIG_ "%s_MODULE %d\n", + fprintf(fp, "#define __enabled_%s%s_MODULE %d\n", sym->level->conf_prefix, sym->name, (*value == 'm')); break; } @@ -605,7 +605,7 @@ tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg { if (sym->type == S_TRISTATE && *value != 'n') - fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); + fprintf(fp, "%s%s=%c\n", sym->level->conf_prefix, sym->name, (char)toupper(*value)); } static struct conf_printer tristate_printer_cb = @@ -775,7 +775,7 @@ int conf_write(const char *name, struct conf_level *l) if (!conf_get_changed()) sym_clear_all_valid(l); - menu = rootmenu.list; + menu = l->rootmenu->list; while (menu) { sym = menu->sym; if (!sym) { @@ -796,7 +796,7 @@ int conf_write(const char *name, struct conf_level *l) } next: - if (menu->list) { + if (menu->list && menu->list->level == l) { menu = menu->list; continue; } diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 12ac5bc..7d38fc0 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -172,10 +172,12 @@ struct menu { struct file *file; int lineno; void *data; + struct conf_level *level; }; #define MENU_CHANGED 0x0001 #define MENU_ROOT 0x0002 +#define MENU_SUBTREE 0x0004 struct conf_level { struct conf_level *n; @@ -188,9 +190,12 @@ struct conf_level { tristate modules_val; struct symbol *sym_defconfig_list; struct expr *sym_env_list; + struct menu *rootmenu; }; extern struct conf_level rootlevel; +extern char *default_prefix; + extern struct file *file_list; extern struct file *current_file; struct file *lookup_file(const char *name); diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index 749d78a..ffea171 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -26,6 +26,8 @@ P(menu_get_help,const char *,(struct menu *menu)); P(get_symbol_str, void, (struct gstr *r, struct symbol *sym)); P(get_relations_str, struct gstr, (struct symbol **sym_arr)); P(menu_get_ext_help,void,(struct menu *menu, struct gstr *help)); +P(menu_prepare_level_prefix,void,(int ismainmenu, char *prefix)); +P(menu_prepare_level_conffile,void,(int ismainmenu, char *file)); /* symbol.c */ P(symbol_hash,struct symbol *,[SYMBOL_HASHSIZE]); @@ -50,9 +52,11 @@ P(sym_get_default_prop,struct property *,(struct symbol *sym)); P(sym_get_string_value,const char *,(struct symbol *sym)); P(prop_get_type_name,const char *,(enum prop_type type)); -P(sym_level_open,void,(struct conf_level *l)); +P(sym_level_open,void,(struct conf_level *l, struct menu *m)); P(sym_level_close,void,(struct conf_level *l)); - +P(sym_open_namespace,struct conf_level *,(struct menu *m)); +P(sym_level_default,void,(struct conf_level *l)); + /* expr.c */ P(expr_compare_type,int,(enum expr_type t1, enum expr_type t2)); P(expr_print,void,(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken)); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 9977819..880dc08 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -42,6 +42,8 @@ void _menu_init(void) { current_entry = current_menu = &rootmenu; last_entry_ptr = &rootmenu.list; + rootmenu.flags = MENU_SUBTREE; + rootmenu.level = current_conf_level; } void menu_add_entry(struct symbol *sym) @@ -54,6 +56,7 @@ void menu_add_entry(struct symbol *sym) menu->parent = current_menu; menu->file = current_file; menu->lineno = zconf_lineno(); + menu->level = current_conf_level; *last_entry_ptr = menu; last_entry_ptr = &menu->next; @@ -62,6 +65,40 @@ void menu_add_entry(struct symbol *sym) menu_add_symbol(P_SYMBOL, sym, NULL); } +struct conf_level *menu_prepare_level(int ismainmenu) +{ + if (!ismainmenu + && (!(current_entry->flags & MENU_SUBTREE)) + && current_entry->level == current_conf_level) { + struct conf_level *l; + l = (struct conf_level*) malloc(sizeof(struct conf_level)); + sym_level_default(l); + current_entry->level = l; + current_entry->flags |= MENU_SUBTREE; + } + return current_entry->level; +} + +void menu_prepare_level_prefix(int ismainmenu, char *prefix) +{ + struct conf_level *l; + l = menu_prepare_level(ismainmenu); + /* override mainmenu options if this is a subtree and prefix has already been given */ + if (!(ismainmenu && l->conf_prefix == default_prefix)) { + l->conf_prefix = prefix; + } +} + +void menu_prepare_level_conffile(int ismainmenu, char *file) +{ + struct conf_level *l; + l = menu_prepare_level(ismainmenu); + /* override mainmenu options if this is a subtree and configfile has already been given */ + if (!(ismainmenu && !l->conf)) { + l->conf = file; + } +} + void menu_end_entry(void) { } @@ -70,11 +107,17 @@ struct menu *menu_add_menu(void) { menu_end_entry(); last_entry_ptr = ¤t_entry->list; + if (current_entry->flags & MENU_SUBTREE) { + sym_open_namespace(current_entry); + } return current_menu = current_entry; } void menu_end_menu(void) { + if (current_menu->flags & MENU_SUBTREE) { + sym_level_close(current_conf_level); + } last_entry_ptr = ¤t_menu->next; current_menu = current_menu->parent; } @@ -290,7 +333,10 @@ void menu_finalize(struct menu *parent) parentdep = parent->prompt->visible.expr; else parentdep = parent->dep; - + /* break dependency chain for subtrees */ + if (parent->flags & MENU_SUBTREE) + parentdep = NULL; + for (menu = parent->list; menu; menu = menu->next) { basedep = expr_transform(menu->dep); basedep = expr_alloc_and(expr_copy(parentdep), basedep); diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index 6999c8d..f9ee6a1 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -31,6 +31,7 @@ struct symbol symbol_yes = { tristate modules_val; struct conf_level rootlevel; +char *default_prefix = CONFIG_; static void sym_add_default(struct symbol *sym, const char *def) { @@ -1306,10 +1307,15 @@ static void prop_add_env(const char *env) menu_warn(current_entry, "environment variable %s undefined", env); } -void sym_level_open(struct conf_level *l) +void sym_level_default(struct conf_level *l) { - struct conf_level **lp; memset(l, 0, sizeof(*l)); + l->conf_prefix = default_prefix; +} + +void sym_level_open(struct conf_level *l, struct menu *m) +{ + struct conf_level **lp; for (lp = &conf_levels; *lp; lp = &(*lp)->n) ; *lp = l; @@ -1319,8 +1325,8 @@ void sym_level_open(struct conf_level *l) l->modules_sym = sym_lookup(NULL, 0, current_conf_level); l->modules_sym->type = S_BOOLEAN; l->modules_sym->flags |= SYMBOL_AUTO; - l->conf_prefix = CONFIG_; - + l->rootmenu = m; + sym_init(current_conf_level); } @@ -1333,3 +1339,15 @@ void sym_level_close(struct conf_level *l) } current_conf_level = l->parent; } + +struct conf_level *sym_open_namespace(struct menu *m) +{ + struct conf_level *l = m->level; + if (current_conf_level == l) { + l = (struct conf_level*) malloc(sizeof(struct conf_level)); + sym_level_default(l); + } + sym_level_open(l, m); + return l; +} + diff --git a/scripts/kconfig/zconf.gperf b/scripts/kconfig/zconf.gperf index f14ab41..714fad4 100644 --- a/scripts/kconfig/zconf.gperf +++ b/scripts/kconfig/zconf.gperf @@ -39,6 +39,8 @@ string, T_TYPE, TF_COMMAND, S_STRING select, T_SELECT, TF_COMMAND range, T_RANGE, TF_COMMAND visible, T_VISIBLE, TF_COMMAND +prefix, T_PREFIX, TF_COMMAND +configfile, T_CONFIGFILE, TF_COMMAND option, T_OPTION, TF_COMMAND on, T_ON, TF_PARAM modules, T_OPT_MODULES, TF_OPTION diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index c6e923f..edb6ba7 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -29,6 +29,7 @@ static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtok static struct menu *current_menu, *current_entry; struct conf_level *current_conf_level = 0; struct conf_level *conf_levels = 0; +int ismainmenu = 0; %} %expect 30 @@ -64,6 +65,8 @@ struct conf_level *conf_levels = 0; %token <id>T_SELECT %token <id>T_RANGE %token <id>T_VISIBLE +%token <id>T_PREFIX +%token <id>T_CONFIGFILE %token <id>T_OPTION %token <id>T_ON %token <string> T_WORD @@ -102,13 +105,14 @@ struct conf_level *conf_levels = 0; %% input: nl start | start; -start: mainmenu_stmt stmt_list | stmt_list; +start: stmt_list; stmt_list: /* empty */ | stmt_list common_stmt | stmt_list choice_stmt | stmt_list menu_stmt + | stmt_list mainmenu_stmt | stmt_list end { zconf_error("unexpected end statement"); } | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } | stmt_list option_name error T_EOL @@ -341,11 +345,22 @@ if_block: /* mainmenu entry */ -mainmenu_stmt: T_MAINMENU prompt nl +mainmenu: T_MAINMENU prompt nl { menu_add_prompt(P_MENU, $2, NULL); }; +mainmenu_stmt: mainmenu { ismainmenu = 1; } mainmenu_options { ismainmenu = 0; } +{ +}; + +mainmenu_options: + /* empty */ + | mainmenu_options subtree_options + | mainmenu_options T_EOL +; + + /* menu entry */ menu: T_MENU prompt T_EOL @@ -355,7 +370,7 @@ menu: T_MENU prompt T_EOL printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); }; -menu_entry: menu visibility_list depends_list +menu_entry: menu menu_options { $$ = menu_add_menu(); }; @@ -368,6 +383,15 @@ menu_end: end } }; +menu_options: + /* empty */ + | menu_options visible + | menu_options depends + | menu_options T_EOL + | menu_options subtree_options + | menu_options option_error +; + menu_stmt: menu_entry menu_block menu_end ; @@ -428,17 +452,26 @@ depends: T_DEPENDS T_ON expr T_EOL /* visibility option */ -visibility_list: - /* empty */ - | visibility_list visible - | visibility_list T_EOL -; - visible: T_VISIBLE if_expr { menu_add_visibility($2); }; +/* subtree menu options */ + +subtree_options: + subtree_prefix + | subtree_configfile +; + +subtree_prefix: + T_PREFIX prompt { menu_prepare_level_prefix(ismainmenu, $2); } +; + +subtree_configfile: + T_CONFIGFILE prompt { menu_prepare_level_conffile(ismainmenu, $2); } +; + /* prompt statement */ prompt_stmt_opt: @@ -490,7 +523,8 @@ void conf_parse(const char *name) struct conf_level *l; int i; - sym_level_open(&rootlevel); + sym_level_default(&rootlevel); + sym_level_open(&rootlevel, &rootmenu); zconf_initscan(name); @@ -535,6 +569,8 @@ static const char *zconf_tokenname(int token) case T_ENDIF: return "endif"; case T_DEPENDS: return "depends"; case T_VISIBLE: return "visible"; + case T_PREFIX: return "prefix"; + case T_CONFIGFILE: return "configfile"; } return "<token>"; } -- 1.6.4.1 -- To unsubscribe from this list: send the line "unsubscribe linux-config" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html