#!/bin/sh # merge_config.sh - Takes a list of config fragment values, and merges # them one by one. Provides warnings on overridden values, and specified # values that did not make it to the resulting .config file (due to missed # dependencies or config symbol removal). # # Portions reused from kconf_check and generate_cfg: # http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/kconf_check # http://git.yoctoproject.org/cgit/cgit.cgi/yocto-kernel-tools/tree/tools/generate_cfg # # Copyright (c) 2009-2010 Wind River Systems, Inc. # Copyright 2011 Linaro # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. proc clean_up { rm -f $TMP_FILE exit } trap clean_up HUP INT TERM proc usage { echo "Usage: $0 [OPTIONS] [CONFIG [...]]" echo " -h display this help text" echo " -m only merge the fragments, do not execute the make command" echo " -n use allnoconfig instead of alldefconfig" echo " -r list redundant entries when merging fragments" echo " -O dir to put generated output files. Consider setting \$KCONFIG_CONFIG instead." } global RUNMAKE := 'true' global ALLTARGET := 'alldefconfig' global WARNREDUN := 'false' global OUTPUT := '.' while true { matchstr $1 { "-n" { global ALLTARGET := 'allnoconfig' shift continue } "-m" { global RUNMAKE := 'false' shift continue } "-h" { usage exit } "-r" { global WARNREDUN := 'true' shift continue } "-O" { if test -d $2{ global OUTPUT := $[echo $2 | sed 's/\/*$//] } else { echo "output directory $2 does not exist" !1 > !2 exit 1 } shift 2 continue } * { break } } } if test "$Argc" -lt 1 { usage exit } if test -z $KCONFIG_CONFIG { if test $OUTPUT != . { global KCONFIG_CONFIG := $[readlink -m -- "$OUTPUT/.config] } else { global KCONFIG_CONFIG := '.config' } } global INITFILE := $1 shift; if test ! -r $INITFILE { echo "The base file '$INITFILE' does not exist. Exit." > !2 exit 1 } global MERGE_LIST := $ifsjoin(Argv) global SED_CONFIG_EXP := '"s/^\(# \)\{0,1\}\(CONFIG_[a-zA-Z0-9_]*\)[= ].*/\2/p'" global TMP_FILE := $[mktemp ./.tmp.config.XXXXXXXXXX] echo "Using $INITFILE as base" cat $INITFILE > $TMP_FILE # Merge files, printing warnings on overridden values for MERGE_FILE in [$MERGE_LIST] { echo "Merging $MERGE_FILE" if test ! -r $MERGE_FILE { echo "The merge file '$MERGE_FILE' does not exist. Exit." > !2 exit 1 } global CFG_LIST := $[sed -n $SED_CONFIG_EXP $MERGE_FILE] for CFG in [$CFG_LIST] { grep -q -w $CFG $TMP_FILE || continue global PREV_VAL := $[grep -w $CFG $TMP_FILE] global NEW_VAL := $[grep -w $CFG $MERGE_FILE] if test "x$PREV_VAL" != "x$NEW_VAL" { echo Value of $CFG is redefined by fragment $MERGE_FILE: echo Previous value: $PREV_VAL echo New value: $NEW_VAL echo } elif test $WARNREDUN = "true" { echo Value of $CFG is redundant by fragment $MERGE_FILE: } sed -i "/$CFG[ =]/d" $TMP_FILE } cat $MERGE_FILE >> $TMP_FILE } if test $RUNMAKE = "false" { cp -T -- $TMP_FILE $KCONFIG_CONFIG echo "#" echo "# merged configuration written to $KCONFIG_CONFIG (needs make)" echo "#" clean_up exit } # If we have an output dir, setup the O= argument, otherwise leave # it blank, since O=. will create an unnecessary ./source softlink global OUTPUT_ARG := ''"" if test $OUTPUT != "." { global OUTPUT_ARG := ""O=$OUTPUT"" } # Use the merged file as the starting point for: # alldefconfig: Fills in any missing symbols with Kconfig default # allnoconfig: Fills in any missing symbols with # CONFIG_* is not set make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET # Check all specified config values took (might have missed-dependency issues) for CFG in [$[sed -n $SED_CONFIG_EXP $TMP_FILE]] { global REQUESTED_VAL := $[grep -w -e $CFG $TMP_FILE] global ACTUAL_VAL := $[grep -w -e $CFG $KCONFIG_CONFIG] if test "x$REQUESTED_VAL" != "x$ACTUAL_VAL" { echo "Value requested for $CFG not in final .config" echo "Requested value: $REQUESTED_VAL" echo "Actual value: $ACTUAL_VAL" echo "" } } clean_up (CommandList children: [ (FuncDef name: clean_up body: (BraceGroup children: [(C {(rm)} {(-f)} {($ VSub_Name "$TMP_FILE")}) (C {(exit)})] spids: [68] ) spids: [64 67] ) (C {(trap)} {(clean_up)} {(HUP)} {(INT)} {(TERM)}) (FuncDef name: usage body: (BraceGroup children: [ (C {(echo)} {(DQ ("Usage: ") ($ VSub_Number "$0") (" [OPTIONS] [CONFIG [...]]"))}) (C {(echo)} {(DQ (" -h display this help text"))}) (C {(echo)} {(DQ (" -m only merge the fragments, do not execute the make command"))}) (C {(echo)} {(DQ (" -n use allnoconfig instead of alldefconfig"))}) (C {(echo)} {(DQ (" -r list redundant entries when merging fragments"))}) (C {(echo)} { (DQ (" -O dir to put generated output files. Consider setting ") (EscapedLiteralPart token:) ("KCONFIG_CONFIG instead.") ) } ) ] spids: [97] ) spids: [93 96] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:RUNMAKE) op:Equal rhs:{(true)} spids:[148])] spids: [148] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:ALLTARGET) op:Equal rhs:{(alldefconfig)} spids:[151])] spids: [151] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:WARNREDUN) op:Equal rhs:{(false)} spids:[154])] spids: [154] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:OUTPUT) op:Equal rhs:{(.)} spids:[157])] spids: [157] ) (While cond: [(Sentence child:(C {(true)}) terminator:)] body: (DoGroup children: [ (Case to_match: {($ VSub_Number "$1")} arms: [ (case_arm pat_list: [{(DQ (-n))}] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:ALLTARGET) op: Equal rhs: {(allnoconfig)} spids: [182] ) ] spids: [182] ) (C {(shift)}) (ControlFlow token:) ] spids: [177 179 192 -1] ) (case_arm pat_list: [{(DQ (-m))}] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:RUNMAKE) op: Equal rhs: {(false)} spids: [201] ) ] spids: [201] ) (C {(shift)}) (ControlFlow token:) ] spids: [196 198 211 -1] ) (case_arm pat_list: [{(DQ (-h))}] action: [(C {(usage)}) (C {(exit)})] spids: [215 217 226 -1] ) (case_arm pat_list: [{(DQ (-r))}] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:WARNREDUN) op: Equal rhs: {(true)} spids: [235] ) ] spids: [235] ) (C {(shift)}) (ControlFlow token:) ] spids: [230 232 245 -1] ) (case_arm pat_list: [{(DQ (-O))}] action: [ (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(-d)} {($ VSub_Number "$2")} {(Lit_Other "]")}) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:OUTPUT) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (Pipeline children: [ (C {(echo)} {($ VSub_Number "$2")}) (C {(sed)} {(SQ <"s/\\/*$//">)}) ] negated: False ) ] ) left_token: spids: [268 280] ) } spids: [267] ) ] spids: [267] ) ] spids: [-1 264] ) ] else_action: [ (SimpleCommand words: [ {(echo)} {(DQ ("output directory ") ($ VSub_Number "$2") (" does not exist"))} ] redirects: [(Redir op_id:Redir_GreatAnd fd:1 arg_word:{(2)} spids:[294])] ) (C {(exit)} {(1)}) ] spids: [283 303] ) (C {(shift)} {(2)}) (ControlFlow token:) ] spids: [249 251 314 -1] ) (case_arm pat_list: [{(Lit_Other "*")}] action: [(ControlFlow token:)] spids: [317 318 324 -1] ) ] spids: [169 173 327] ) ] spids: [166 329] ) ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Pound "$#"))} {(-lt)} {(1)} {(Lit_Other "]")}) terminator: ) ] action: [(C {(usage)}) (C {(exit)})] spids: [-1 348] ) ] spids: [-1 356] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(-z)} {(DQ ($ VSub_Name "$KCONFIG_CONFIG"))} {(Lit_Other "]")}) terminator: ) ] action: [ (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$OUTPUT"))} {(KW_Bang "!") (Lit_Other "=")} {(.)} {(Lit_Other "]")} ) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:KCONFIG_CONFIG) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(readlink)} {(-m)} {(--)} {(DQ ($ VSub_Name "$OUTPUT") (/.config))} ) ] ) left_token: spids: [395 406] ) } spids: [394] ) ] spids: [394] ) ] spids: [-1 391] ) ] else_action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:KCONFIG_CONFIG) op: Equal rhs: {(.config)} spids: [412] ) ] spids: [412] ) ] spids: [409 416] ) ] spids: [-1 372] ) ] spids: [-1 418] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:INITFILE) op: Equal rhs: {($ VSub_Number "$1")} spids: [421] ) ] spids: [421] ) (Sentence child:(C {(shift)}) terminator:) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(KW_Bang "!")} {(-r)} {(DQ ($ VSub_Name "$INITFILE"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (SimpleCommand words: [ {(echo)} {(DQ ("The base file '") ($ VSub_Name "$INITFILE") ("' does not exist. Exit."))} ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[454])] ) (C {(exit)} {(1)}) ] spids: [-1 443] ) ] spids: [-1 462] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:MERGE_LIST) op: Equal rhs: {($ VSub_Star "$*")} spids: [465] ) ] spids: [465] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:SED_CONFIG_EXP) op: Equal rhs: { (DQ ("s/^") (EscapedLiteralPart token:) ("# ") (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("0,1") (EscapedLiteralPart token:) (EscapedLiteralPart token:) ("CONFIG_[a-zA-Z0-9_]*") (EscapedLiteralPart token:) ("[= ].*/") (EscapedLiteralPart token:) (/p) ) } spids: [468] ) ] spids: [468] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:TMP_FILE) op: Equal rhs: { (CommandSubPart command_list: (CommandList children:[(C {(mktemp)} {(./.tmp.config.XXXXXXXXXX)})]) left_token: spids: [486 490] ) } spids: [485] ) ] spids: [485] ) (C {(echo)} {(DQ ("Using ") ($ VSub_Name "$INITFILE") (" as base"))}) (SimpleCommand words: [{(cat)} {($ VSub_Name "$INITFILE")}] redirects: [(Redir op_id:Redir_Great fd:-1 arg_word:{($ VSub_Name "$TMP_FILE")} spids:[505])] ) (ForEach iter_name: MERGE_FILE iter_words: [{($ VSub_Name "$MERGE_LIST")}] do_arg_iter: False body: (DoGroup children: [ (C {(echo)} {(DQ ("Merging ") ($ VSub_Name "$MERGE_FILE"))}) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(KW_Bang "!")} {(-r)} {(DQ ($ VSub_Name "$MERGE_FILE"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (SimpleCommand words: [ {(echo)} { (DQ ("The merge file '") ($ VSub_Name "$MERGE_FILE") ("' does not exist. Exit.") ) } ] redirects: [(Redir op_id:Redir_GreatAnd fd:-1 arg_word:{(2)} spids:[560])] ) (C {(exit)} {(1)}) ] spids: [-1 549] ) ] spids: [-1 569] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:CFG_LIST) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(sed)} {(-n)} {(DQ ($ VSub_Name "$SED_CONFIG_EXP"))} {($ VSub_Name "$MERGE_FILE")} ) ] ) left_token: spids: [573 583] ) } spids: [572] ) ] spids: [572] ) (ForEach iter_name: CFG iter_words: [{($ VSub_Name "$CFG_LIST")}] do_arg_iter: False body: (DoGroup children: [ (AndOr children: [ (C {(grep)} {(-q)} {(-w)} {($ VSub_Name "$CFG")} {($ VSub_Name "$TMP_FILE")}) (ControlFlow token:) ] op_id: Op_DPipe ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:PREV_VAL) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(grep)} {(-w)} {($ VSub_Name "$CFG")} {($ VSub_Name "$TMP_FILE")} ) ] ) left_token: spids: [616 624] ) } spids: [615] ) ] spids: [615] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:NEW_VAL) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(grep)} {(-w)} {($ VSub_Name "$CFG")} {($ VSub_Name "$MERGE_FILE")} ) ] ) left_token: spids: [628 636] ) } spids: [627] ) ] spids: [627] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ (x) ($ VSub_Name "$PREV_VAL"))} {(KW_Bang "!") (Lit_Other "=")} {(DQ (x) ($ VSub_Name "$NEW_VAL"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (C {(echo)} {(Value)} {(of)} {($ VSub_Name "$CFG")} {(is)} {(redefined)} {(by)} {(fragment)} {($ VSub_Name "$MERGE_FILE") (Lit_Other ":")} ) (C {(echo)} {(Previous)} {(value) (Lit_Other ":")} {($ VSub_Name "$PREV_VAL")} ) (C {(echo)} {(New)} {(value) (Lit_Other ":")} {($ VSub_Name "$NEW_VAL")}) (C {(echo)}) ] spids: [-1 660] ) (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$WARNREDUN"))} {(Lit_Other "=")} {(DQ (true))} {(Lit_Other "]")} ) terminator: ) ] action: [ (C {(echo)} {(Value)} {(of)} {($ VSub_Name "$CFG")} {(is)} {(redundant)} {(by)} {(fragment)} {($ VSub_Name "$MERGE_FILE") (Lit_Other ":")} ) ] spids: [706 723] ) ] spids: [-1 746] ) (C {(sed)} {(-i)} {(DQ (/) ($ VSub_Name "$CFG") ("[ =]/d"))} {($ VSub_Name "$TMP_FILE")} ) ] spids: [597 762] ) spids: [592 595] ) (SimpleCommand words: [{(cat)} {($ VSub_Name "$MERGE_FILE")}] redirects: [ (Redir op_id: Redir_DGreat fd: -1 arg_word: {($ VSub_Name "$TMP_FILE")} spids: [769] ) ] ) ] spids: [523 773] ) spids: [518 521] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$RUNMAKE"))} {(Lit_Other "=")} {(DQ (false))} {(Lit_Other "]")} ) terminator: ) ] action: [ (C {(cp)} {(-T)} {(--)} {(DQ ($ VSub_Name "$TMP_FILE"))} {(DQ ($ VSub_Name "$KCONFIG_CONFIG"))}) (C {(echo)} {(DQ ("#"))}) (C {(echo)} { (DQ ("# merged configuration written to ") ($ VSub_Name "$KCONFIG_CONFIG") (" (needs make)") ) } ) (C {(echo)} {(DQ ("#"))}) (C {(clean_up)}) (C {(exit)}) ] spids: [-1 793] ) ] spids: [-1 839] ) (Assignment keyword: Assign_None pairs: [(assign_pair lhs:(LhsName name:OUTPUT_ARG) op:Equal rhs:{(DQ )} spids:[848])] spids: [848] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ ($ VSub_Name "$OUTPUT"))} {(KW_Bang "!") (Lit_Other "=")} {(DQ (.))} {(Lit_Other "]")} ) terminator: ) ] action: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:OUTPUT_ARG) op: Equal rhs: {(DQ ("O=") ($ VSub_Name "$OUTPUT"))} spids: [874] ) ] spids: [874] ) ] spids: [-1 871] ) ] spids: [-1 880] ) (C {(make)} {(Lit_VarLike "KCONFIG_ALLCONFIG=") ($ VSub_Name "$TMP_FILE")} {($ VSub_Name "$OUTPUT_ARG")} {($ VSub_Name "$ALLTARGET")} ) (ForEach iter_name: CFG iter_words: [ { (CommandSubPart command_list: (CommandList children: [ (C {(sed)} {(-n)} {(DQ ($ VSub_Name "$SED_CONFIG_EXP"))} {($ VSub_Name "$TMP_FILE")}) ] ) left_token: spids: [913 923] ) } ] do_arg_iter: False body: (DoGroup children: [ (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:REQUESTED_VAL) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(grep)} {(-w)} {(-e)} {(DQ ($ VSub_Name "$CFG"))} {($ VSub_Name "$TMP_FILE")} ) ] ) left_token: spids: [931 943] ) } spids: [930] ) ] spids: [930] ) (Assignment keyword: Assign_None pairs: [ (assign_pair lhs: (LhsName name:ACTUAL_VAL) op: Equal rhs: { (CommandSubPart command_list: (CommandList children: [ (C {(grep)} {(-w)} {(-e)} {(DQ ($ VSub_Name "$CFG"))} {(DQ ($ VSub_Name "$KCONFIG_CONFIG"))} ) ] ) left_token: spids: [947 961] ) } spids: [946] ) ] spids: [946] ) (If arms: [ (if_arm cond: [ (Sentence child: (C {(Lit_Other "[")} {(DQ (x) ($ VSub_Name "$REQUESTED_VAL"))} {(KW_Bang "!") (Lit_Other "=")} {(DQ (x) ($ VSub_Name "$ACTUAL_VAL"))} {(Lit_Other "]")} ) terminator: ) ] action: [ (C {(echo)} {(DQ ("Value requested for ") ($ VSub_Name "$CFG") (" not in final .config"))} ) (C {(echo)} {(DQ ("Requested value: ") ($ VSub_Name "$REQUESTED_VAL"))}) (C {(echo)} {(DQ ("Actual value: ") ($ VSub_Name "$ACTUAL_VAL"))}) (C {(echo)} {(DQ )}) ] spids: [-1 985] ) ] spids: [-1 1019] ) ] spids: [926 1021] ) spids: [912 924] ) (C {(clean_up)}) ] )