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.
Showing the changes to scripts (1 of 1 file). Show all
Unified · Split
| @@ -783,6 +783,110 @@ struct symbol **sym_re_search(const char *pattern) · 782 unmodified lines | ||
| 783 | 783 | return sym_arr; |
| 784 | 784 | } |
| 785 | 785 | |
| 786 | +/* | |
| 787 | + * When we check for recursive dependencies we use a stack to save | |
| 788 | + * current state so we can print out relevant info to user. | |
| 789 | + * The entries are located on the call stack so no need to free memory. | |
| 790 | + * Note inser() remove() must always match to properly clear the stack. | |
| 791 | + */ | |
| 792 | +static struct dep_stack { | |
| 793 | + struct dep_stack *prev, *next; | |
| 794 | + struct symbol *sym; | |
| 795 | + struct property *prop; | |
| 796 | + struct expr *expr; | |
| 797 | +} *check_top; | |
| 798 | + | |
| 799 | +static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) | |
| 800 | +{ | |
| 801 | + memset(stack, 0, sizeof(*stack)); | |
| 802 | + if (check_top) | |
| 803 | + check_top->next = stack; | |
| 804 | + stack->prev = check_top; | |
| 805 | + stack->sym = sym; | |
| 806 | + check_top = stack; | |
| 807 | +} | |
| 808 | + | |
| 809 | +static void dep_stack_remove(void) | |
| 810 | +{ | |
| 811 | + check_top = check_top->prev; | |
| 812 | + if (check_top) | |
| 813 | + check_top->next = NULL; | |
| 814 | +} | |
| 815 | + | |
| 816 | +/* | |
| 817 | + * Called when we have detected a recursive dependency. | |
| 818 | + * check_top point to the top of the stact so we use | |
| 819 | + * the ->prev pointer to locate the bottom of the stack. | |
| 820 | + */ | |
| 821 | +static void sym_check_print_recursive(struct symbol *last_sym) | |
| 822 | +{ | |
| 823 | + struct dep_stack *stack; | |
| 824 | + struct symbol *sym, *next_sym; | |
| 825 | + struct menu *menu = NULL; | |
| 826 | + struct property *prop; | |
| 827 | + struct dep_stack cv_stack; | |
| 828 | + | |
| 829 | + if (sym_is_choice_value(last_sym)) { | |
| 830 | + dep_stack_insert(&cv_stack, last_sym); | |
| 831 | + last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); | |
| 832 | + } | |
| 833 | + | |
| 834 | + for (stack = check_top; stack != NULL; stack = stack->prev) | |
| 835 | + if (stack->sym == last_sym) | |
| 836 | + break; | |
| 837 | + if (!stack) { | |
| 838 | + fprintf(stderr, "unexpected recursive dependency error\n"); | |
| 839 | + return; | |
| 840 | + } | |
| 841 | + | |
| 842 | + for (; stack; stack = stack->next) { | |
| 843 | + sym = stack->sym; | |
| 844 | + next_sym = stack->next ? stack->next->sym : last_sym; | |
| 845 | + prop = stack->prop; | |
| 846 | + | |
| 847 | + /* for choice values find the menu entry (used below) */ | |
| 848 | + if (sym_is_choice(sym) || sym_is_choice_value(sym)) { | |
| 849 | + for (prop = sym->prop; prop; prop = prop->next) { | |
| 850 | + menu = prop->menu; | |
| 851 | + if (prop->menu) | |
| 852 | + break; | |
| 853 | + } | |
| 854 | + } | |
| 855 | + if (stack->sym == last_sym) | |
| 856 | + fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", | |
| 857 | + prop->file->name, prop->lineno); | |
| 858 | + if (stack->expr) { | |
| 859 | + fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", | |
| 860 | + prop->file->name, prop->lineno, | |
| 861 | + sym->name ? sym->name : "<choice>", | |
| 862 | + prop_get_type_name(prop->type), | |
| 863 | + next_sym->name ? next_sym->name : "<choice>"); | |
| 864 | + } else if (stack->prop) { | |
| 865 | + fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", | |
| 866 | + prop->file->name, prop->lineno, | |
| 867 | + sym->name ? sym->name : "<choice>", | |
| 868 | + next_sym->name ? next_sym->name : "<choice>"); | |
| 869 | + } else if (sym_is_choice(sym)) { | |
| 870 | + fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", | |
| 871 | + menu->file->name, menu->lineno, | |
| 872 | + sym->name ? sym->name : "<choice>", | |
| 873 | + next_sym->name ? next_sym->name : "<choice>"); | |
| 874 | + } else if (sym_is_choice_value(sym)) { | |
| 875 | + fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", | |
| 876 | + menu->file->name, menu->lineno, | |
| 877 | + sym->name ? sym->name : "<choice>", | |
| 878 | + next_sym->name ? next_sym->name : "<choice>"); | |
| 879 | + } else { | |
| 880 | + fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", | |
| 881 | + prop->file->name, prop->lineno, | |
| 882 | + sym->name ? sym->name : "<choice>", | |
| 883 | + next_sym->name ? next_sym->name : "<choice>"); | |
| 884 | + } | |
| 885 | + } | |
| 886 | + | |
| 887 | + if (check_top == &cv_stack) | |
| 888 | + dep_stack_remove(); | |
| 889 | +} | |
| 786 | 890 | |
| 787 | 891 | static struct symbol *sym_check_expr_deps(struct expr *e) |
| 788 | 892 | { |
| @@ -819,24 +923,33 @@ static struct symbol *sym_check_sym_deps(struct symbol *sym) · 30 unmodified lines | ||
| 819 | 923 | { |
| 820 | 924 | struct symbol *sym2; |
| 821 | 925 | struct property *prop; |
| 926 | + struct dep_stack stack; | |
| 927 | + | |
| 928 | + dep_stack_insert(&stack, sym); | |
| 822 | 929 | |
| 823 | 930 | sym2 = sym_check_expr_deps(sym->rev_dep.expr); |
| 824 | 931 | if (sym2) |
| 825 | − return sym2; | |
| 932 | + goto out; | |
| 826 | 933 | |
| 827 | 934 | for (prop = sym->prop; prop; prop = prop->next) { |
| 828 | 935 | if (prop->type == P_CHOICE || prop->type == P_SELECT) |
| 829 | 936 | continue; |
| 937 | + stack.prop = prop; | |
| 830 | 938 | sym2 = sym_check_expr_deps(prop->visible.expr); |
| 831 | 939 | if (sym2) |
| 832 | 940 | break; |
| 833 | 941 | if (prop->type != P_DEFAULT || sym_is_choice(sym)) |
| 834 | 942 | continue; |
| 943 | + stack.expr = prop->expr; | |
| 835 | 944 | sym2 = sym_check_expr_deps(prop->expr); |
| 836 | 945 | if (sym2) |
| 837 | 946 | break; |
| 947 | + stack.expr = NULL; | |
| 838 | 948 | } |
| 839 | 949 | |
| 950 | +out: | |
| 951 | + dep_stack_remove(); | |
| 952 | + | |
| 840 | 953 | return sym2; |
| 841 | 954 | } |
| 842 | 955 | |
| @@ -845,6 +958,9 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice) · 2 unmodified lines | ||
| 845 | 958 | struct symbol *sym, *sym2; |
| 846 | 959 | struct property *prop; |
| 847 | 960 | struct expr *e; |
| 961 | + struct dep_stack stack; | |
| 962 | + | |
| 963 | + dep_stack_insert(&stack, choice); | |
| 848 | 964 | |
| 849 | 965 | prop = sym_get_choice_prop(choice); |
| 850 | 966 | expr_list_for_each_sym(prop->expr, e, sym) |
| @@ -858,10 +974,8 @@ static struct symbol *sym_check_choice_deps(struct symbol *choice) · 7 unmodified lines | ||
| 858 | 974 | |
| 859 | 975 | expr_list_for_each_sym(prop->expr, e, sym) { |
| 860 | 976 | sym2 = sym_check_sym_deps(sym); |
| 861 | − if (sym2) { | |
| 862 | − fprintf(stderr, " -> %s", sym->name); | |
| 977 | + if (sym2) | |
| 863 | 978 | break; |
| 864 | − } | |
| 865 | 979 | } |
| 866 | 980 | out: |
| 867 | 981 | expr_list_for_each_sym(prop->expr, e, sym) |
| @@ -871,6 +985,8 @@ out: · 3 unmodified lines | ||
| 871 | 985 | prop_get_symbol(sym_get_choice_prop(sym2)) == choice) |
| 872 | 986 | sym2 = choice; |
| 873 | 987 | |
| 988 | + dep_stack_remove(); | |
| 989 | + | |
| 874 | 990 | return sym2; |
| 875 | 991 | } |
| 876 | 992 | |
| @@ -880,18 +996,20 @@ struct symbol *sym_check_deps(struct symbol *sym) · 3 unmodified lines | ||
| 880 | 996 | struct property *prop; |
| 881 | 997 | |
| 882 | 998 | if (sym->flags & SYMBOL_CHECK) { |
| 883 | − fprintf(stderr, "%s:%d:error: found recursive dependency: %s", | |
| 884 | − sym->prop->file->name, sym->prop->lineno, | |
| 885 | − sym->name ? sym->name : "<choice>"); | |
| 999 | + sym_check_print_recursive(sym); | |
| 886 | 1000 | return sym; |
| 887 | 1001 | } |
| 888 | 1002 | if (sym->flags & SYMBOL_CHECKED) |
| 889 | 1003 | return NULL; |
| 890 | 1004 | |
| 891 | 1005 | if (sym_is_choice_value(sym)) { |
| 1006 | + struct dep_stack stack; | |
| 1007 | + | |
| 892 | 1008 | /* for choice groups start the check with main choice symbol */ |
| 1009 | + dep_stack_insert(&stack, sym); | |
| 893 | 1010 | prop = sym_get_choice_prop(sym); |
| 894 | 1011 | sym2 = sym_check_deps(prop_get_symbol(prop)); |
| 1012 | + dep_stack_remove(); | |
| 895 | 1013 | } else if (sym_is_choice(sym)) { |
| 896 | 1014 | sym2 = sym_check_choice_deps(sym); |
| 897 | 1015 | } else { |
| @@ -900,14 +1018,8 @@ struct symbol *sym_check_deps(struct symbol *sym) · 2 unmodified lines | ||
| 900 | 1018 | sym->flags &= ~SYMBOL_CHECK; |
| 901 | 1019 | } |
| 902 | 1020 | |
| 903 | − if (sym2) { | |
| 904 | − fprintf(stderr, " -> %s", sym->name ? sym->name : "<choice>"); | |
| 905 | − if (sym2 == sym) { | |
| 906 | − fprintf(stderr, "\n"); | |
| 907 | − zconfnerrs++; | |
| 908 | − sym2 = NULL; | |
| 909 | − } | |
| 910 | − } | |
| 1021 | + if (sym2 && sym2 == sym) | |
| 1022 | + sym2 = NULL; | |
| 911 | 1023 | |
| 912 | 1024 | return sym2; |
| 913 | 1025 | } |