Commit d595cea62403db4e65b98a8bb96ff2b5205c7b82
Committed by
Michal Marek
1 parent
59e89e3ddf
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>
Showing 1 changed file with 127 additions and 15 deletions Side-by-side Diff
scripts/kconfig/symbol.c
... | ... | @@ -783,7 +783,111 @@ |
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; | |
786 | 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 | +} | |
890 | + | |
787 | 891 | static struct symbol *sym_check_expr_deps(struct expr *e) |
788 | 892 | { |
789 | 893 | struct symbol *sym; |
790 | 894 | |
791 | 895 | |
792 | 896 | |
793 | 897 | |
794 | 898 | |
795 | 899 | |
... | ... | @@ -819,24 +923,33 @@ |
819 | 923 | { |
820 | 924 | struct symbol *sym2; |
821 | 925 | struct property *prop; |
926 | + struct dep_stack stack; | |
822 | 927 | |
928 | + dep_stack_insert(&stack, sym); | |
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 | |
843 | 956 | |
... | ... | @@ -845,7 +958,10 @@ |
845 | 958 | struct symbol *sym, *sym2; |
846 | 959 | struct property *prop; |
847 | 960 | struct expr *e; |
961 | + struct dep_stack stack; | |
848 | 962 | |
963 | + dep_stack_insert(&stack, choice); | |
964 | + | |
849 | 965 | prop = sym_get_choice_prop(choice); |
850 | 966 | expr_list_for_each_sym(prop->expr, e, sym) |
851 | 967 | sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); |
852 | 968 | |
... | ... | @@ -858,10 +974,8 @@ |
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 @@ |
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 | |
877 | 993 | |
878 | 994 | |
879 | 995 | |
... | ... | @@ -880,18 +996,20 @@ |
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 @@ |
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 | } |