#!/bin/bash set -e # The names and locations of the br2-external trees, once validated. declare -a BR2_EXT_NAMES declare -A BR2_EXT_PATHS declare -A BR2_EXT_DESCS # URL to manual for help in converting old br2-external trees. # Escape '#' so that make does not consider it a comment. MANUAL_URL='https://buildroot.org/manual.html\#br2-external-converting' main() { local OPT OPTARG local br2_ext ofile ofmt while getopts :hkmo: OPT; do case "${OPT}" in h) help; exit 0;; o) ofile="${OPTARG}";; k) ofmt="kconfig";; m) ofmt="mk";; :) error "option '%s' expects a mandatory argument\n" "${OPTARG}";; \?) error "unknown option '%s'\n" "${OPTARG}";; esac done # Forget options; keep only positional args shift $((OPTIND-1)) case "${ofmt}" in mk|kconfig) ;; *) error "no output format specified (-m/-k)\n";; esac if [ -z "${ofile}" ]; then error "no output file specified (-o)\n" fi exec >"${ofile}" do_validate ${@//:/ } do_${ofmt} } # Validates the br2-external trees passed as arguments. Makes each of # them canonical and store them in the global arrays BR2_EXT_NAMES # and BR2_EXT_PATHS. # # Note: since this script is always first called from Makefile context # to generate the Makefile fragment before it is called to generate the # Kconfig snippet, we're sure that any error in do_validate will be # interpreted in Makefile context. Going up to generating the Kconfig # snippet means that there were no error. # do_validate() { local br2_ext if [ ${#} -eq 0 ]; then # No br2-external tree is valid return fi for br2_ext in "${@}"; do do_validate_one "${br2_ext}" done } do_validate_one() { local br2_ext="${1}" local br2_name br2_desc n if [ ! -d "${br2_ext}" ]; then error "'%s': no such file or directory\n" "${br2_ext}" fi if [ ! -r "${br2_ext}" -o ! -x "${br2_ext}" ]; then error "'%s': permission denied\n" "${br2_ext}" fi if [ ! -f "${br2_ext}/external.desc" ]; then error "'%s': does not have a name (in 'external.desc'). See %s\n" \ "${br2_ext}" "${MANUAL_URL}" fi br2_name="$(sed -r -e '/^name: +(.*)$/!d; s//\1/' "${br2_ext}/external.desc")" if [ -z "${br2_name}" ]; then error "'%s/external.desc': does not define the name\n" "${br2_ext}" fi # Only ASCII chars in [A-Za-z0-9_] are permitted n="$(sed -r -e 's/[A-Za-z0-9_]//g' <<<"${br2_name}" )" if [ -n "${n}" ]; then # Escape '$' so that it gets printed error "'%s': name '%s' contains invalid chars: '%s'\n" \ "${br2_ext}" "${br2_name//\$/\$\$}" "${n//\$/\$\$}" fi if [ -n "${BR2_EXT_PATHS["${br2_name}"]}" ]; then error "'%s': name '%s' is already used in '%s'\n" \ "${br2_ext}" "${br2_name}" "${BR2_EXT_PATHS["${br2_name}"]}" fi br2_desc="$(sed -r -e '/^desc: +(.*)$/!d; s//\1/' "${br2_ext}/external.desc")" if [ ! -f "${br2_ext}/external.mk" ]; then error "'%s/external.mk': no such file or directory\n" "${br2_ext}" fi if [ ! -f "${br2_ext}/Config.in" ]; then error "'%s/Config.in': no such file or directory\n" "${br2_ext}" fi # Register this br2-external tree BR2_EXT_NAMES+=( "${br2_name}" ) BR2_EXT_PATHS["${br2_name}"]="${br2_ext}" BR2_EXT_DESCS["${br2_name}"]="${br2_desc:-${br2_name}}" } # Generate the .mk snippet that defines makefile variables # for the br2-external tree do_mk() { local br2_name br2_ext printf '#\n# Automatically generated file; DO NOT EDIT.\n#\n' printf '\n' # We can't use ${BR2_EXT_NAMES[@]} directly: it is not guaranteed # to be in the order paths were added (because it is an associative # array). So we need to iterate on BR2_EXT_NAMES, which is sorted # in the order names were added (because it is an indexed array). printf 'BR2_EXTERNAL ?=' for br2_name in "${BR2_EXT_NAMES[@]}"; do printf ' %s' "${BR2_EXT_PATHS["${br2_name}"]}" done printf '\n' printf 'BR2_EXTERNAL_NAMES = \n' printf 'BR2_EXTERNAL_DIRS = \n' printf 'BR2_EXTERNAL_MKS = \n' if [ ${#BR2_EXT_NAMES[@]} -eq 0 ]; then printf '\n' printf '# No br2-external tree defined.\n' return fi for br2_name in "${BR2_EXT_NAMES[@]}"; do br2_desc="${BR2_EXT_DESCS["${br2_name}"]}" br2_ext="${BR2_EXT_PATHS["${br2_name}"]}" printf '\n' printf 'BR2_EXTERNAL_NAMES += %s\n' "${br2_name}" printf 'BR2_EXTERNAL_DIRS += %s\n' "${br2_ext}" printf 'BR2_EXTERNAL_MKS += %s/external.mk\n' "${br2_ext}" printf 'export BR2_EXTERNAL_%s_PATH = %s\n' "${br2_name}" "${br2_ext}" printf 'export BR2_EXTERNAL_%s_DESC = %s\n' "${br2_name}" "${br2_desc}" done } # Generate the kconfig snippet for the br2-external tree. do_kconfig() { local br2_name br2_ext printf '#\n# Automatically generated file; DO NOT EDIT.\n#\n' printf '\n' if [ ${#BR2_EXT_NAMES[@]} -eq 0 ]; then printf '# No br2-external tree defined.\n' return fi printf 'menu "External options"\n' printf '\n' for br2_name in "${BR2_EXT_NAMES[@]}"; do br2_desc="${BR2_EXT_DESCS["${br2_name}"]}" br2_ext="${BR2_EXT_PATHS["${br2_name}"]}" if [ ${#BR2_EXT_NAMES[@]} -gt 1 ]; then printf 'menu "%s"\n' "${br2_desc}" fi printf 'comment "%s (in %s)"\n' "${br2_desc}" "${br2_ext}" printf 'config BR2_EXTERNAL_%s_PATH\n' "${br2_name}" printf '\tstring\n' printf '\tdefault "%s"\n' "${br2_ext}" printf 'source "%s/Config.in"\n' "${br2_ext}" if [ ${#BR2_EXT_NAMES[@]} -gt 1 ]; then printf 'endmenu # %s\n' "${br2_name}" fi printf '\n' done printf "endmenu # User-provided options\n" } help() { cat <<-_EOF_ Usage: ${my_name} <-m|-k> -o FILE PATH With -m, ${my_name} generates the makefile fragment that defines variables related to the br2-external trees passed as positional arguments. With -k, ${my_name} generates the kconfig snippet to include the configuration options specified in the br2-external trees passed as positional arguments. Using -k and -m together is not possible. The last one wins. Options: -m Generate the makefile fragment. -k Generate the kconfig snippet. -o FILE FILE in which to generate the kconfig snippet or makefile fragment. Returns: 0 If no error !0 If any error _EOF_ } error() { local fmt="${1}"; shift; printf "BR2_EXTERNAL_ERROR = ${fmt}" "${@}"; exit 1; } my_name="${0##*/}" main "${@}"