| #!/bin/bash |
| # Parses Kconfig lines like |
| # CONFIG_DEBUG=y >=6.1 |
| # # CONFIG_DEBUG is not set <6.1 |
| # and only adds them to the build if the kernel is 6.1 or greater |
| # Regular lines are unchanged |
| version="$1" |
| shift |
| declare -A plats |
| for plat in $1; do |
| plats["$plat"]=1 |
| done |
| shift |
| files=("$@") |
| # Disallow "x.y" versions as they don't sort correctly |
| is_xy_ver() { |
| [[ "$1" =~ ^[0-9]+[.][0-9]+$ ]] |
| } |
| if is_xy_ver "$version"; then |
| echo "Linux version is unsupported $version" >&2 |
| exit 1 |
| fi |
| declare -A config=() |
| fail= |
| for file in "${files[@]}"; do |
| echo "Trimming $file to $version" >&2 |
| fdone=0 |
| while (( fdone == 0 )); do |
| read -r line || fdone=$? |
| if [[ $line =~ ^'# '(CONFIG_[_A-Za-z0-9]*)' is not set'( (.*))?$ ]]; then |
| # Match options that unset configuration options equivalent to CONFIG_*=n |
| # - # CONFIG_I2C_MUX_PCA9541 is not set |
| # - # CONFIG_DEVPORT is not set |
| key="${BASH_REMATCH[1]}" |
| op='=' |
| val='n' |
| larr=(${BASH_REMATCH[3]}) |
| elif [[ $line =~ ^(CONFIG_[_A-Za-z0-9]*)(=|'+=')('"'.*'"'|[^ ]*)(' '(.*))? ]]; then |
| # Match options that set configuration options equivalent to CONFIG_*=<val> |
| # - CONFIG_I2C_MUX_PCA954x=y |
| # - CONFIG_DEVMEM=y armv7,armv8 |
| # |
| # Also match append operations (can only be used on strings) |
| # - CONFIG_CMDLINE+=" opt1" |
| # - CONFIG_CMDLINE+=" opt2" armv8 |
| key="${BASH_REMATCH[1]}" |
| op="${BASH_REMATCH[2]}" |
| val="${BASH_REMATCH[3]}" |
| larr=(${BASH_REMATCH[5]}) |
| elif [[ $line =~ ^' '*(#.*)?$ ]]; then |
| continue |
| else |
| echo "Unrecognized line: $line" >&2 |
| fail=1 |
| fi |
| skip= |
| for const in "${larr[@]}"; do |
| if [[ "${const:0:1}" == '#' ]]; then |
| break |
| elif [[ ${const:0:2} == '>=' ]]; then |
| if is_xy_ver "${const:2}"; then |
| echo "Constraint version is unsupported ${const:2}: $line" >&2 |
| fail=1 |
| fi |
| expected="${const:2}"$'\n'"$version" |
| if [[ $expected != $(echo "$expected" | sort -V) ]]; then |
| skip=1 |
| break |
| fi |
| elif [[ ${const:0:1} == '>' ]]; then |
| if is_xy_ver "${const:1}"; then |
| echo "Constraint version is unsupported ${const:1}: $line" >&2 |
| fail=1 |
| fi |
| expected="${const:1}"$'\n'"$version" |
| if [[ ${const:1} == $version || $expected != $(echo "$expected" | sort -V) ]]; then |
| skip=1 |
| break |
| fi |
| elif [[ ${const:0:2} == '<=' ]]; then |
| if is_xy_ver "${const:2}"; then |
| echo "Constraint version is unsupported ${const:2}: $line" >&2 |
| fail=1 |
| fi |
| expected="$version"$'\n'"${const:2}" |
| if [[ $expected != $(echo "$expected" | sort -V) ]]; then |
| skip=1 |
| break |
| fi |
| elif [[ ${const:0:1} == '<' ]]; then |
| if is_xy_ver "${const:1}"; then |
| echo "Constraint version is unsupported ${const:1}: $line" >&2 |
| fail=1 |
| fi |
| expected="$version"$'\n'"${const:1}" |
| if [[ ${const:1} == $version || $expected != $(echo "$expected" | sort -V) ]]; then |
| skip=1 |
| break |
| fi |
| elif [[ $const =~ ^[a-zA-Z0-9] ]]; then |
| OLDIFS="$IFS" |
| IFS=',' |
| match= |
| for plat in $const; do |
| if [[ -v plats["$plat"] ]]; then |
| match=1 |
| break |
| fi |
| done |
| IFS="$OLDIFS" |
| if [[ -z "$match" ]]; then |
| skip=1 |
| break |
| fi |
| else |
| echo "Unexpected constraint '$const' at line: $line" >&2 |
| fail=1 |
| fi |
| done |
| if [[ -z $skip ]]; then |
| if [[ $op == '=' ]]; then |
| config["$key"]="$val" |
| elif [[ $op == '+=' ]]; then |
| if [[ ${val:0:1} != '"' || "${val: -1}" != '"' ]]; then |
| echo "Only know how to append strings: $line" |
| fail=1 |
| fi |
| oldval="${config["$key"]}" |
| if [[ -z "$oldval" ]]; then |
| config["$key"]="$val" |
| else |
| config["$key"]="${oldval:0:-1}${val:1}" |
| fi |
| else |
| echo "Unrecognized operator '$op': $line" >&2 |
| fi |
| fi |
| done <"$file" |
| done |
| if [[ -n "$fail" ]]; then |
| exit 1 |
| fi |
| written= |
| for file in "${files[@]}"; do |
| exec {nfile}<>"$file.tmp" |
| # Only write to the first file in the list of files, so that our merged |
| # values definitely only take effect once. We leave empty tombstones for |
| # the old files, so that any build structure depending on them still works. |
| if [[ -z "$written" ]]; then |
| echo "Writing fuill config to $file" >&2 |
| for key in "${!config[@]}"; do |
| echo "$key=${config["$key"]}" >&$nfile |
| done |
| written=1 |
| fi |
| exec {nfile}>&- |
| mv "$file.tmp" "$file" |
| done |