#!/usr/bin/env bash set -e # This script must be able to run with bash-3.1, so it can't use # associative arrays. Instead, it emulates them using 'eval'. It # can however use indexed arrays, supported since at least bash-3.0. # The names of the br2-external trees, once validated. declare -a BR2_EXT_NAMES # 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 outputdir while getopts :d: OPT; do case "${OPT}" in d) outputdir="${OPTARG}";; :) 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)) if [ -z "${outputdir}" ]; then error "no output directory specified (-d)\n" fi # Trap any unexpected error to generate a meaningful error message trap "error 'unexpected error while generating ${ofile}\n'" ERR mkdir -p "${outputdir}" do_validate "${outputdir}" ${@//:/ } do_mk "${outputdir}" do_kconfig "${outputdir}" } # 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 outputdir="${1}" local br2_ext shift if [ ${#} -eq 0 ]; then # No br2-external tree is valid return fi for br2_ext in "${@}"; do do_validate_one "${br2_ext}" done >"${outputdir}/.br2-external.mk" } do_validate_one() { local br2_ext="${1}" local br2_name br2_desc n d 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 an '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 eval d="\"\${BR2_EXT_PATHS_${br2_name}}\"" if [ -n "${d}" ]; then error "'%s': name '%s' is already used in '%s'\n" \ "${br2_ext}" "${br2_name}" "${d}" 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, use an absolute canonical path br2_ext="$( cd "${br2_ext}"; pwd )" BR2_EXT_NAMES+=( "${br2_name}" ) eval BR2_EXT_PATHS_${br2_name}="\"\${br2_ext}\"" eval 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 outputdir="${1}" local br2_name br2_desc br2_ext { printf '#\n# Automatically generated file; DO NOT EDIT.\n#\n' printf '\n' printf 'BR2_EXTERNAL ?=' for br2_name in "${BR2_EXT_NAMES[@]}"; do eval br2_ext="\"\${BR2_EXT_PATHS_${br2_name}}\"" printf ' %s' "${br2_ext}" 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 eval br2_desc="\"\${BR2_EXT_DESCS_${br2_name}}\"" eval 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 } >"${outputdir}/.br2-external.mk" } # Generate the kconfig snippets for the br2-external tree. do_kconfig() { local outputdir="${1}" local br2_name br2_desc br2_ext br2 local -a items items=( paths menus toolchains jpeg openssl skeleton init ) for br2 in "${items[@]}"; do { 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' fi } >"${outputdir}/.br2-external.in.${br2}" done if [ ${#BR2_EXT_NAMES[@]} -eq 0 ]; then return fi printf 'menu "External options"\n\n' >>"${outputdir}/.br2-external.in.menus" for br2_name in "${BR2_EXT_NAMES[@]}"; do eval br2_desc="\"\${BR2_EXT_DESCS_${br2_name}}\"" eval br2_ext="\"\${BR2_EXT_PATHS_${br2_name}}\"" { printf 'config BR2_EXTERNAL_%s_PATH\n' "${br2_name}" printf '\tstring\n' printf '\tdefault "%s"\n' "${br2_ext}" printf '\n' } >>"${outputdir}/.br2-external.in.paths" { 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 'source "%s/Config.in"\n' "${br2_ext}" if [ ${#BR2_EXT_NAMES[@]} -gt 1 ]; then printf 'endmenu # %s\n' "${br2_name}" fi printf '\n' } >>"${outputdir}/.br2-external.in.menus" if [ -f "${br2_ext}/provides/toolchains.in" ]; then printf 'comment "Toolchains from: %s"\n' "${br2_desc}" printf 'source "%s/provides/toolchains.in"\n' "${br2_ext}" printf '\n' else printf '# No toolchain from: %s\n\n' "${br2_desc}" fi >>"${outputdir}/.br2-external.in.toolchains" if [ -f "${br2_ext}/provides/jpeg.in" ]; then printf 'comment "jpeg from: %s"\n' "${br2_desc}" printf 'source "%s/provides/jpeg.in"\n' "${br2_ext}" printf '\n' else printf '# No jpeg from: %s\n\n' "${br2_desc}" fi >>"${outputdir}/.br2-external.in.jpeg" if [ -f "${br2_ext}/provides/openssl.in" ]; then printf 'comment "openssl from: %s"\n' "${br2_desc}" printf 'source "%s/provides/openssl.in"\n' "${br2_ext}" printf '\n' else printf '# No openssl from: %s\n\n' "${br2_desc}" fi >>"${outputdir}/.br2-external.in.openssl" if [ -f "${br2_ext}/provides/skeleton.in" ]; then printf 'comment "skeleton from: %s"\n' "${br2_desc}" printf 'source "%s/provides/skeleton.in"\n' "${br2_ext}" printf '\n' else printf '# No skeleton from: %s\n\n' "${br2_desc}" fi >>"${outputdir}/.br2-external.in.skeleton" if [ -f "${br2_ext}/provides/init.in" ]; then printf 'comment "init from: %s"\n' "${br2_desc}" printf 'source "%s/provides/init.in"\n' "${br2_ext}" printf '\n' else printf '# No init from: %s\n\n' "${br2_desc}" fi >>"${outputdir}/.br2-external.in.init" done printf 'endmenu\n' >>"${outputdir}/.br2-external.in.menus" } error() { local fmt="${1}"; shift; printf "BR2_EXTERNAL_ERROR = ${fmt}" "${@}"; exit 1; } my_name="${0##*/}" main "${@}"