• Masahiro Yamada's avatar
    kconfig: refactor choice value calculation · f79dc03f
    Masahiro Yamada authored
    Handling choices has always been in a PITA in Kconfig.
    
    For example, fixes and reverts were repeated for randconfig with
    KCONFIG_ALLCONFIG:
    
     - 422c809f ("kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG")
     - 23a5dfda ("Revert "kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG"")
     - 8357b485 ("kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG")
     - 490f1617 ("Revert "kconfig: fix randomising choice entries in presence of KCONFIG_ALLCONFIG"")
    
    As these commits pointed out, randconfig does not randomize choices when
    KCONFIG_ALLCONFIG is used. This issue still remains.
    
    [Test Case]
    
        choice
                prompt "choose"
    
        config A
                bool "A"
    
        config B
                bool "B"
    
        endchoice
    
        $ echo > all.config
        $ make KCONFIG_ALLCONFIG=1 randconfig
    
    The output is always as follows:
    
        CONFIG_A=y
        # CONFIG_B is not set
    
    Not only randconfig, but other all*config variants are also broken with
    KCONFIG_ALLCONFIG.
    
    With the same Kconfig,
    
        $ echo '# CONFIG_A is not set' > all.config
        $ make KCONFIG_ALLCONFIG=1 allyesconfig
    
    You will get this:
    
        CONFIG_A=y
        # CONFIG_B is not set
    
    This is incorrect because it does not respect all.config.
    
    The correct output should be:
    
        # CONFIG_A is not set
        CONFIG_B=y
    
    To handle user inputs more accurately, this commit refactors the code
    based on the following principles:
    
     - When a user value is given, Kconfig must set it immediately.
       Do not defer it by setting SYMBOL_NEED_SET_CHOICE_VALUES.
    
     - The SYMBOL_DEF_USER flag must not be cleared, unless a new config
       file is loaded. Kconfig must not forget user inputs.
    
    In addition, user values for choices must be managed with priority.
    If user inputs conflict within a choice block, the newest value wins.
    The values given by randconfig have lower priority than explicit user
    inputs.
    
    This commit implements it by using a linked list. Every time a choice
    block gets a new input, it is moved to the top of the list.
    
    Let me explain how it works.
    
    Let's say, we have a choice block that consists of five symbols:
    A, B, C, D, and E.
    
    Initially, the linked list looks like this:
    
        A(=?) --> B(=?) --> C(=?) --> D(=?) --> E(=?)
    
    Suppose randconfig is executed with the following KCONFIG_ALLCONFIG:
    
        CONFIG_C=y
        # CONFIG_A is not set
        CONFIG_D=y
    
    First, CONFIG_C=y is read. C is set to 'y' and moved to the top.
    
        C(=y) --> A(=?) --> B(=?) --> D(=?) --> E(=?)
    
    Next, '# CONFIG_A is not set' is read. A is set to 'n' and moved to
    the top.
    
        A(=n) --> C(=y) --> B(=?) --> D(=?) --> E(=?)
    
    Then, 'CONFIG_D=y' is read. D is set to 'y' and moved to the top.
    
        D(=y) --> A(=n) --> C(=y) --> B(=?) --> E(=?)
    
    Lastly, randconfig shuffles the order of the remaining symbols,
    resulting in:
    
        D(=y) --> A(=n) --> C(=y) --> B(=y) --> E(=y)
    or
        D(=y) --> A(=n) --> C(=y) --> E(=y) --> B(=y)
    
    When calculating the output, the linked list is traversed and the first
    visible symbol with 'y' is taken. In this case, it is D if visible.
    
    If D is hidden by 'depends on', the next node, A, is examined. Since
    it is already specified as 'n', it is skipped. Next, C is checked, and
    selected if it is visible.
    
    If C is also invisible, either B or E is chosen as a result of the
    randomization.
    
    If B and E are also invisible, the linked list is traversed in the
    reverse order, and the least prioritized 'n' symbol is chosen. It is
    A in this case.
    
    Now, Kconfig remembers all user values. This is a big difference from
    the previous implementation, where Kconfig would forget CONFIG_C=y when
    CONFIG_D=y appeared in the same input file.
    
    The new appaorch respects user-specified values as much as possible.
    Signed-off-by: default avatarMasahiro Yamada <masahiroy@kernel.org>
    f79dc03f
menu.c 19.6 KB