forked from mirrors/linux
		
	kconfig: print more info when we see a recursive dependency
Consider following kconfig file: config TEST1 bool "test 1" depends on TEST2 config TEST2 bool "test 2" depends on TEST1 Previously kconfig would report: foo:6:error: found recursive dependency: TEST2 -> TEST1 -> TEST2 With the following patch kconfig reports: foo:5:error: recursive dependency detected! foo:5: symbol TEST2 depends on TEST1 foo:1: symbol TEST1 depends on TEST2 Note that we now report where the offending symbols are defined. This can be a great help for complex situations involving several files. Patch is originally from Roman Zippel with a few adjustments by Sam. Signed-off-by: Sam Ravnborg <sam@ravnborg.org> Cc: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Michal Marek <mmarek@suse.cz>
This commit is contained in:
		
							parent
							
								
									59e89e3ddf
								
							
						
					
					
						commit
						d595cea624
					
				
					 1 changed files with 127 additions and 15 deletions
				
			
		| 
						 | 
					@ -783,6 +783,110 @@ struct symbol **sym_re_search(const char *pattern)
 | 
				
			||||||
	return sym_arr;
 | 
						return sym_arr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * When we check for recursive dependencies we use a stack to save
 | 
				
			||||||
 | 
					 * current state so we can print out relevant info to user.
 | 
				
			||||||
 | 
					 * The entries are located on the call stack so no need to free memory.
 | 
				
			||||||
 | 
					 * Note inser() remove() must always match to properly clear the stack.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct dep_stack {
 | 
				
			||||||
 | 
						struct dep_stack *prev, *next;
 | 
				
			||||||
 | 
						struct symbol *sym;
 | 
				
			||||||
 | 
						struct property *prop;
 | 
				
			||||||
 | 
						struct expr *expr;
 | 
				
			||||||
 | 
					} *check_top;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						memset(stack, 0, sizeof(*stack));
 | 
				
			||||||
 | 
						if (check_top)
 | 
				
			||||||
 | 
							check_top->next = stack;
 | 
				
			||||||
 | 
						stack->prev = check_top;
 | 
				
			||||||
 | 
						stack->sym = sym;
 | 
				
			||||||
 | 
						check_top = stack;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dep_stack_remove(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						check_top = check_top->prev;
 | 
				
			||||||
 | 
						if (check_top)
 | 
				
			||||||
 | 
							check_top->next = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Called when we have detected a recursive dependency.
 | 
				
			||||||
 | 
					 * check_top point to the top of the stact so we use
 | 
				
			||||||
 | 
					 * the ->prev pointer to locate the bottom of the stack.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void sym_check_print_recursive(struct symbol *last_sym)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dep_stack *stack;
 | 
				
			||||||
 | 
						struct symbol *sym, *next_sym;
 | 
				
			||||||
 | 
						struct menu *menu = NULL;
 | 
				
			||||||
 | 
						struct property *prop;
 | 
				
			||||||
 | 
						struct dep_stack cv_stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (sym_is_choice_value(last_sym)) {
 | 
				
			||||||
 | 
							dep_stack_insert(&cv_stack, last_sym);
 | 
				
			||||||
 | 
							last_sym = prop_get_symbol(sym_get_choice_prop(last_sym));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (stack = check_top; stack != NULL; stack = stack->prev)
 | 
				
			||||||
 | 
							if (stack->sym == last_sym)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						if (!stack) {
 | 
				
			||||||
 | 
							fprintf(stderr, "unexpected recursive dependency error\n");
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (; stack; stack = stack->next) {
 | 
				
			||||||
 | 
							sym = stack->sym;
 | 
				
			||||||
 | 
							next_sym = stack->next ? stack->next->sym : last_sym;
 | 
				
			||||||
 | 
							prop = stack->prop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* for choice values find the menu entry (used below) */
 | 
				
			||||||
 | 
							if (sym_is_choice(sym) || sym_is_choice_value(sym)) {
 | 
				
			||||||
 | 
								for (prop = sym->prop; prop; prop = prop->next) {
 | 
				
			||||||
 | 
									menu = prop->menu;
 | 
				
			||||||
 | 
									if (prop->menu)
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (stack->sym == last_sym)
 | 
				
			||||||
 | 
								fprintf(stderr, "%s:%d:error: recursive dependency detected!\n",
 | 
				
			||||||
 | 
									prop->file->name, prop->lineno);
 | 
				
			||||||
 | 
							if (stack->expr) {
 | 
				
			||||||
 | 
								fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n",
 | 
				
			||||||
 | 
									prop->file->name, prop->lineno,
 | 
				
			||||||
 | 
									sym->name ? sym->name : "<choice>",
 | 
				
			||||||
 | 
									prop_get_type_name(prop->type),
 | 
				
			||||||
 | 
									next_sym->name ? next_sym->name : "<choice>");
 | 
				
			||||||
 | 
							} else if (stack->prop) {
 | 
				
			||||||
 | 
								fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n",
 | 
				
			||||||
 | 
									prop->file->name, prop->lineno,
 | 
				
			||||||
 | 
									sym->name ? sym->name : "<choice>",
 | 
				
			||||||
 | 
									next_sym->name ? next_sym->name : "<choice>");
 | 
				
			||||||
 | 
							} else if (sym_is_choice(sym)) {
 | 
				
			||||||
 | 
								fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n",
 | 
				
			||||||
 | 
									menu->file->name, menu->lineno,
 | 
				
			||||||
 | 
									sym->name ? sym->name : "<choice>",
 | 
				
			||||||
 | 
									next_sym->name ? next_sym->name : "<choice>");
 | 
				
			||||||
 | 
							} else if (sym_is_choice_value(sym)) {
 | 
				
			||||||
 | 
								fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n",
 | 
				
			||||||
 | 
									menu->file->name, menu->lineno,
 | 
				
			||||||
 | 
									sym->name ? sym->name : "<choice>",
 | 
				
			||||||
 | 
									next_sym->name ? next_sym->name : "<choice>");
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n",
 | 
				
			||||||
 | 
									prop->file->name, prop->lineno,
 | 
				
			||||||
 | 
									sym->name ? sym->name : "<choice>",
 | 
				
			||||||
 | 
									next_sym->name ? next_sym->name : "<choice>");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (check_top == &cv_stack)
 | 
				
			||||||
 | 
							dep_stack_remove();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct symbol *sym_check_expr_deps(struct expr *e)
 | 
					static struct symbol *sym_check_expr_deps(struct expr *e)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -819,24 +923,33 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct symbol *sym2;
 | 
						struct symbol *sym2;
 | 
				
			||||||
	struct property *prop;
 | 
						struct property *prop;
 | 
				
			||||||
 | 
						struct dep_stack stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dep_stack_insert(&stack, sym);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sym2 = sym_check_expr_deps(sym->rev_dep.expr);
 | 
						sym2 = sym_check_expr_deps(sym->rev_dep.expr);
 | 
				
			||||||
	if (sym2)
 | 
						if (sym2)
 | 
				
			||||||
		return sym2;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (prop = sym->prop; prop; prop = prop->next) {
 | 
						for (prop = sym->prop; prop; prop = prop->next) {
 | 
				
			||||||
		if (prop->type == P_CHOICE || prop->type == P_SELECT)
 | 
							if (prop->type == P_CHOICE || prop->type == P_SELECT)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
							stack.prop = prop;
 | 
				
			||||||
		sym2 = sym_check_expr_deps(prop->visible.expr);
 | 
							sym2 = sym_check_expr_deps(prop->visible.expr);
 | 
				
			||||||
		if (sym2)
 | 
							if (sym2)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if (prop->type != P_DEFAULT || sym_is_choice(sym))
 | 
							if (prop->type != P_DEFAULT || sym_is_choice(sym))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
							stack.expr = prop->expr;
 | 
				
			||||||
		sym2 = sym_check_expr_deps(prop->expr);
 | 
							sym2 = sym_check_expr_deps(prop->expr);
 | 
				
			||||||
		if (sym2)
 | 
							if (sym2)
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
							stack.expr = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						dep_stack_remove();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sym2;
 | 
						return sym2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -845,6 +958,9 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
 | 
				
			||||||
	struct symbol *sym, *sym2;
 | 
						struct symbol *sym, *sym2;
 | 
				
			||||||
	struct property *prop;
 | 
						struct property *prop;
 | 
				
			||||||
	struct expr *e;
 | 
						struct expr *e;
 | 
				
			||||||
 | 
						struct dep_stack stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dep_stack_insert(&stack, choice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	prop = sym_get_choice_prop(choice);
 | 
						prop = sym_get_choice_prop(choice);
 | 
				
			||||||
	expr_list_for_each_sym(prop->expr, e, sym)
 | 
						expr_list_for_each_sym(prop->expr, e, sym)
 | 
				
			||||||
| 
						 | 
					@ -858,11 +974,9 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	expr_list_for_each_sym(prop->expr, e, sym) {
 | 
						expr_list_for_each_sym(prop->expr, e, sym) {
 | 
				
			||||||
		sym2 = sym_check_sym_deps(sym);
 | 
							sym2 = sym_check_sym_deps(sym);
 | 
				
			||||||
		if (sym2) {
 | 
							if (sym2)
 | 
				
			||||||
			fprintf(stderr, " -> %s", sym->name);
 | 
					 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	expr_list_for_each_sym(prop->expr, e, sym)
 | 
						expr_list_for_each_sym(prop->expr, e, sym)
 | 
				
			||||||
		sym->flags &= ~SYMBOL_CHECK;
 | 
							sym->flags &= ~SYMBOL_CHECK;
 | 
				
			||||||
| 
						 | 
					@ -871,6 +985,8 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice)
 | 
				
			||||||
	    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
 | 
						    prop_get_symbol(sym_get_choice_prop(sym2)) == choice)
 | 
				
			||||||
		sym2 = choice;
 | 
							sym2 = choice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dep_stack_remove();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sym2;
 | 
						return sym2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -880,18 +996,20 @@ struct symbol *sym_check_deps(struct symbol *sym)
 | 
				
			||||||
	struct property *prop;
 | 
						struct property *prop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sym->flags & SYMBOL_CHECK) {
 | 
						if (sym->flags & SYMBOL_CHECK) {
 | 
				
			||||||
		fprintf(stderr, "%s:%d:error: found recursive dependency: %s",
 | 
							sym_check_print_recursive(sym);
 | 
				
			||||||
		        sym->prop->file->name, sym->prop->lineno,
 | 
					 | 
				
			||||||
			sym->name ? sym->name : "<choice>");
 | 
					 | 
				
			||||||
		return sym;
 | 
							return sym;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (sym->flags & SYMBOL_CHECKED)
 | 
						if (sym->flags & SYMBOL_CHECKED)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sym_is_choice_value(sym)) {
 | 
						if (sym_is_choice_value(sym)) {
 | 
				
			||||||
 | 
							struct dep_stack stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* for choice groups start the check with main choice symbol */
 | 
							/* for choice groups start the check with main choice symbol */
 | 
				
			||||||
 | 
							dep_stack_insert(&stack, sym);
 | 
				
			||||||
		prop = sym_get_choice_prop(sym);
 | 
							prop = sym_get_choice_prop(sym);
 | 
				
			||||||
		sym2 = sym_check_deps(prop_get_symbol(prop));
 | 
							sym2 = sym_check_deps(prop_get_symbol(prop));
 | 
				
			||||||
 | 
							dep_stack_remove();
 | 
				
			||||||
	} else if (sym_is_choice(sym)) {
 | 
						} else if (sym_is_choice(sym)) {
 | 
				
			||||||
		sym2 = sym_check_choice_deps(sym);
 | 
							sym2 = sym_check_choice_deps(sym);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
| 
						 | 
					@ -900,14 +1018,8 @@ struct symbol *sym_check_deps(struct symbol *sym)
 | 
				
			||||||
		sym->flags &= ~SYMBOL_CHECK;
 | 
							sym->flags &= ~SYMBOL_CHECK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sym2) {
 | 
						if (sym2 && sym2 == sym)
 | 
				
			||||||
		fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>");
 | 
					 | 
				
			||||||
		if (sym2 == sym) {
 | 
					 | 
				
			||||||
			fprintf(stderr, "\n");
 | 
					 | 
				
			||||||
			zconfnerrs++;
 | 
					 | 
				
			||||||
		sym2 = NULL;
 | 
							sym2 = NULL;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sym2;
 | 
						return sym2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue