1*4882a593Smuzhiyun#!/usr/bin/env bash 2*4882a593Smuzhiyunset -e 3*4882a593Smuzhiyun 4*4882a593Smuzhiyun# This script must be able to run with bash-3.1, so it can't use 5*4882a593Smuzhiyun# associative arrays. Instead, it emulates them using 'eval'. It 6*4882a593Smuzhiyun# can however use indexed arrays, supported since at least bash-3.0. 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun# The names of the br2-external trees, once validated. 9*4882a593Smuzhiyundeclare -a BR2_EXT_NAMES 10*4882a593Smuzhiyun 11*4882a593Smuzhiyun# URL to manual for help in converting old br2-external trees. 12*4882a593Smuzhiyun# Escape '#' so that make does not consider it a comment. 13*4882a593SmuzhiyunMANUAL_URL='https://buildroot.org/manual.html\#br2-external-converting' 14*4882a593Smuzhiyun 15*4882a593Smuzhiyunmain() { 16*4882a593Smuzhiyun local OPT OPTARG 17*4882a593Smuzhiyun local br2_ext outputdir 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun while getopts :d: OPT; do 20*4882a593Smuzhiyun case "${OPT}" in 21*4882a593Smuzhiyun d) outputdir="${OPTARG}";; 22*4882a593Smuzhiyun :) error "option '%s' expects a mandatory argument\n" "${OPTARG}";; 23*4882a593Smuzhiyun \?) error "unknown option '%s'\n" "${OPTARG}";; 24*4882a593Smuzhiyun esac 25*4882a593Smuzhiyun done 26*4882a593Smuzhiyun # Forget options; keep only positional args 27*4882a593Smuzhiyun shift $((OPTIND-1)) 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun if [ -z "${outputdir}" ]; then 30*4882a593Smuzhiyun error "no output directory specified (-d)\n" 31*4882a593Smuzhiyun fi 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun # Trap any unexpected error to generate a meaningful error message 34*4882a593Smuzhiyun trap "error 'unexpected error while generating ${ofile}\n'" ERR 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun mkdir -p "${outputdir}" 37*4882a593Smuzhiyun do_validate "${outputdir}" ${@//:/ } 38*4882a593Smuzhiyun do_mk "${outputdir}" 39*4882a593Smuzhiyun do_kconfig "${outputdir}" 40*4882a593Smuzhiyun} 41*4882a593Smuzhiyun 42*4882a593Smuzhiyun# Validates the br2-external trees passed as arguments. Makes each of 43*4882a593Smuzhiyun# them canonical and store them in the global arrays BR2_EXT_NAMES 44*4882a593Smuzhiyun# and BR2_EXT_PATHS. 45*4882a593Smuzhiyun# 46*4882a593Smuzhiyun# Note: since this script is always first called from Makefile context 47*4882a593Smuzhiyun# to generate the Makefile fragment before it is called to generate the 48*4882a593Smuzhiyun# Kconfig snippet, we're sure that any error in do_validate will be 49*4882a593Smuzhiyun# interpreted in Makefile context. Going up to generating the Kconfig 50*4882a593Smuzhiyun# snippet means that there were no error. 51*4882a593Smuzhiyun# 52*4882a593Smuzhiyundo_validate() { 53*4882a593Smuzhiyun local outputdir="${1}" 54*4882a593Smuzhiyun local br2_ext 55*4882a593Smuzhiyun shift 56*4882a593Smuzhiyun 57*4882a593Smuzhiyun if [ ${#} -eq 0 ]; then 58*4882a593Smuzhiyun # No br2-external tree is valid 59*4882a593Smuzhiyun return 60*4882a593Smuzhiyun fi 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun for br2_ext in "${@}"; do 63*4882a593Smuzhiyun do_validate_one "${br2_ext}" 64*4882a593Smuzhiyun done >"${outputdir}/.br2-external.mk" 65*4882a593Smuzhiyun} 66*4882a593Smuzhiyun 67*4882a593Smuzhiyundo_validate_one() { 68*4882a593Smuzhiyun local br2_ext="${1}" 69*4882a593Smuzhiyun local br2_name br2_desc n d 70*4882a593Smuzhiyun 71*4882a593Smuzhiyun if [ ! -d "${br2_ext}" ]; then 72*4882a593Smuzhiyun error "'%s': no such file or directory\n" "${br2_ext}" 73*4882a593Smuzhiyun fi 74*4882a593Smuzhiyun if [ ! -r "${br2_ext}" -o ! -x "${br2_ext}" ]; then 75*4882a593Smuzhiyun error "'%s': permission denied\n" "${br2_ext}" 76*4882a593Smuzhiyun fi 77*4882a593Smuzhiyun if [ ! -f "${br2_ext}/external.desc" ]; then 78*4882a593Smuzhiyun error "'%s': does not have an 'external.desc'. See %s\n" \ 79*4882a593Smuzhiyun "${br2_ext}" "${MANUAL_URL}" 80*4882a593Smuzhiyun fi 81*4882a593Smuzhiyun br2_name="$(sed -r -e '/^name: +(.*)$/!d; s//\1/' "${br2_ext}/external.desc")" 82*4882a593Smuzhiyun if [ -z "${br2_name}" ]; then 83*4882a593Smuzhiyun error "'%s/external.desc': does not define the name\n" "${br2_ext}" 84*4882a593Smuzhiyun fi 85*4882a593Smuzhiyun # Only ASCII chars in [A-Za-z0-9_] are permitted 86*4882a593Smuzhiyun n="$(sed -r -e 's/[A-Za-z0-9_]//g' <<<"${br2_name}" )" 87*4882a593Smuzhiyun if [ -n "${n}" ]; then 88*4882a593Smuzhiyun # Escape '$' so that it gets printed 89*4882a593Smuzhiyun error "'%s': name '%s' contains invalid chars: '%s'\n" \ 90*4882a593Smuzhiyun "${br2_ext}" "${br2_name//\$/\$\$}" "${n//\$/\$\$}" 91*4882a593Smuzhiyun fi 92*4882a593Smuzhiyun eval d="\"\${BR2_EXT_PATHS_${br2_name}}\"" 93*4882a593Smuzhiyun if [ -n "${d}" ]; then 94*4882a593Smuzhiyun error "'%s': name '%s' is already used in '%s'\n" \ 95*4882a593Smuzhiyun "${br2_ext}" "${br2_name}" "${d}" 96*4882a593Smuzhiyun fi 97*4882a593Smuzhiyun br2_desc="$(sed -r -e '/^desc: +(.*)$/!d; s//\1/' "${br2_ext}/external.desc")" 98*4882a593Smuzhiyun if [ ! -f "${br2_ext}/external.mk" ]; then 99*4882a593Smuzhiyun error "'%s/external.mk': no such file or directory\n" "${br2_ext}" 100*4882a593Smuzhiyun fi 101*4882a593Smuzhiyun if [ ! -f "${br2_ext}/Config.in" ]; then 102*4882a593Smuzhiyun error "'%s/Config.in': no such file or directory\n" "${br2_ext}" 103*4882a593Smuzhiyun fi 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun # Register this br2-external tree, use an absolute canonical path 106*4882a593Smuzhiyun br2_ext="$( cd "${br2_ext}"; pwd )" 107*4882a593Smuzhiyun BR2_EXT_NAMES+=( "${br2_name}" ) 108*4882a593Smuzhiyun eval BR2_EXT_PATHS_${br2_name}="\"\${br2_ext}\"" 109*4882a593Smuzhiyun eval BR2_EXT_DESCS_${br2_name}="\"\${br2_desc:-\${br2_name}}\"" 110*4882a593Smuzhiyun} 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun# Generate the .mk snippet that defines makefile variables 113*4882a593Smuzhiyun# for the br2-external tree 114*4882a593Smuzhiyundo_mk() { 115*4882a593Smuzhiyun local outputdir="${1}" 116*4882a593Smuzhiyun local br2_name br2_desc br2_ext 117*4882a593Smuzhiyun 118*4882a593Smuzhiyun { 119*4882a593Smuzhiyun printf '#\n# Automatically generated file; DO NOT EDIT.\n#\n' 120*4882a593Smuzhiyun printf '\n' 121*4882a593Smuzhiyun 122*4882a593Smuzhiyun printf 'BR2_EXTERNAL ?=' 123*4882a593Smuzhiyun for br2_name in "${BR2_EXT_NAMES[@]}"; do 124*4882a593Smuzhiyun eval br2_ext="\"\${BR2_EXT_PATHS_${br2_name}}\"" 125*4882a593Smuzhiyun printf ' %s' "${br2_ext}" 126*4882a593Smuzhiyun done 127*4882a593Smuzhiyun printf '\n' 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun printf 'BR2_EXTERNAL_NAMES = \n' 130*4882a593Smuzhiyun printf 'BR2_EXTERNAL_DIRS = \n' 131*4882a593Smuzhiyun printf 'BR2_EXTERNAL_MKS = \n' 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun if [ ${#BR2_EXT_NAMES[@]} -eq 0 ]; then 134*4882a593Smuzhiyun printf '\n' 135*4882a593Smuzhiyun printf '# No br2-external tree defined.\n' 136*4882a593Smuzhiyun return 137*4882a593Smuzhiyun fi 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun for br2_name in "${BR2_EXT_NAMES[@]}"; do 140*4882a593Smuzhiyun eval br2_desc="\"\${BR2_EXT_DESCS_${br2_name}}\"" 141*4882a593Smuzhiyun eval br2_ext="\"\${BR2_EXT_PATHS_${br2_name}}\"" 142*4882a593Smuzhiyun printf '\n' 143*4882a593Smuzhiyun printf 'BR2_EXTERNAL_NAMES += %s\n' "${br2_name}" 144*4882a593Smuzhiyun printf 'BR2_EXTERNAL_DIRS += %s\n' "${br2_ext}" 145*4882a593Smuzhiyun printf 'BR2_EXTERNAL_MKS += %s/external.mk\n' "${br2_ext}" 146*4882a593Smuzhiyun printf 'export BR2_EXTERNAL_%s_PATH = %s\n' "${br2_name}" "${br2_ext}" 147*4882a593Smuzhiyun printf 'export BR2_EXTERNAL_%s_DESC = %s\n' "${br2_name}" "${br2_desc}" 148*4882a593Smuzhiyun done 149*4882a593Smuzhiyun } >"${outputdir}/.br2-external.mk" 150*4882a593Smuzhiyun} 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun# Generate the kconfig snippets for the br2-external tree. 153*4882a593Smuzhiyundo_kconfig() { 154*4882a593Smuzhiyun local outputdir="${1}" 155*4882a593Smuzhiyun local br2_name br2_desc br2_ext br2 156*4882a593Smuzhiyun local -a items 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun items=( 159*4882a593Smuzhiyun paths 160*4882a593Smuzhiyun menus 161*4882a593Smuzhiyun toolchains 162*4882a593Smuzhiyun jpeg 163*4882a593Smuzhiyun openssl 164*4882a593Smuzhiyun skeleton 165*4882a593Smuzhiyun init 166*4882a593Smuzhiyun linux 167*4882a593Smuzhiyun ) 168*4882a593Smuzhiyun 169*4882a593Smuzhiyun for br2 in "${items[@]}"; do 170*4882a593Smuzhiyun { 171*4882a593Smuzhiyun printf '#\n# Automatically generated file; DO NOT EDIT.\n#\n' 172*4882a593Smuzhiyun printf '\n' 173*4882a593Smuzhiyun if [ ${#BR2_EXT_NAMES[@]} -eq 0 ]; then 174*4882a593Smuzhiyun printf '# No br2-external tree defined.\n' 175*4882a593Smuzhiyun fi 176*4882a593Smuzhiyun } >"${outputdir}/.br2-external.in.${br2}" 177*4882a593Smuzhiyun done 178*4882a593Smuzhiyun if [ ${#BR2_EXT_NAMES[@]} -eq 0 ]; then 179*4882a593Smuzhiyun return 180*4882a593Smuzhiyun fi 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun printf 'menu "External options"\n\n' >>"${outputdir}/.br2-external.in.menus" 183*4882a593Smuzhiyun 184*4882a593Smuzhiyun for br2_name in "${BR2_EXT_NAMES[@]}"; do 185*4882a593Smuzhiyun eval br2_desc="\"\${BR2_EXT_DESCS_${br2_name}}\"" 186*4882a593Smuzhiyun eval br2_ext="\"\${BR2_EXT_PATHS_${br2_name}}\"" 187*4882a593Smuzhiyun 188*4882a593Smuzhiyun { 189*4882a593Smuzhiyun printf 'config BR2_EXTERNAL_%s_PATH\n' "${br2_name}" 190*4882a593Smuzhiyun printf '\tstring\n' 191*4882a593Smuzhiyun printf '\tdefault "%s"\n' "${br2_ext}" 192*4882a593Smuzhiyun printf '\n' 193*4882a593Smuzhiyun } >>"${outputdir}/.br2-external.in.paths" 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun { 196*4882a593Smuzhiyun if [ ${#BR2_EXT_NAMES[@]} -gt 1 ]; then 197*4882a593Smuzhiyun printf 'menu "%s"\n' "${br2_desc}" 198*4882a593Smuzhiyun fi 199*4882a593Smuzhiyun printf 'comment "%s (in %s)"\n' "${br2_desc}" "${br2_ext}" 200*4882a593Smuzhiyun printf 'source "%s/Config.in"\n' "${br2_ext}" 201*4882a593Smuzhiyun if [ ${#BR2_EXT_NAMES[@]} -gt 1 ]; then 202*4882a593Smuzhiyun printf 'endmenu # %s\n' "${br2_name}" 203*4882a593Smuzhiyun fi 204*4882a593Smuzhiyun printf '\n' 205*4882a593Smuzhiyun } >>"${outputdir}/.br2-external.in.menus" 206*4882a593Smuzhiyun 207*4882a593Smuzhiyun if [ -f "${br2_ext}/provides/toolchains.in" ]; then 208*4882a593Smuzhiyun printf 'comment "Toolchains from: %s"\n' "${br2_desc}" 209*4882a593Smuzhiyun printf 'source "%s/provides/toolchains.in"\n' "${br2_ext}" 210*4882a593Smuzhiyun printf '\n' 211*4882a593Smuzhiyun else 212*4882a593Smuzhiyun printf '# No toolchain from: %s\n\n' "${br2_desc}" 213*4882a593Smuzhiyun fi >>"${outputdir}/.br2-external.in.toolchains" 214*4882a593Smuzhiyun 215*4882a593Smuzhiyun if [ -f "${br2_ext}/provides/jpeg.in" ]; then 216*4882a593Smuzhiyun printf 'comment "jpeg from: %s"\n' "${br2_desc}" 217*4882a593Smuzhiyun printf 'source "%s/provides/jpeg.in"\n' "${br2_ext}" 218*4882a593Smuzhiyun printf '\n' 219*4882a593Smuzhiyun else 220*4882a593Smuzhiyun printf '# No jpeg from: %s\n\n' "${br2_desc}" 221*4882a593Smuzhiyun fi >>"${outputdir}/.br2-external.in.jpeg" 222*4882a593Smuzhiyun 223*4882a593Smuzhiyun if [ -f "${br2_ext}/provides/openssl.in" ]; then 224*4882a593Smuzhiyun printf 'comment "openssl from: %s"\n' "${br2_desc}" 225*4882a593Smuzhiyun printf 'source "%s/provides/openssl.in"\n' "${br2_ext}" 226*4882a593Smuzhiyun printf '\n' 227*4882a593Smuzhiyun else 228*4882a593Smuzhiyun printf '# No openssl from: %s\n\n' "${br2_desc}" 229*4882a593Smuzhiyun fi >>"${outputdir}/.br2-external.in.openssl" 230*4882a593Smuzhiyun 231*4882a593Smuzhiyun if [ -f "${br2_ext}/provides/skeleton.in" ]; then 232*4882a593Smuzhiyun printf 'comment "skeleton from: %s"\n' "${br2_desc}" 233*4882a593Smuzhiyun printf 'source "%s/provides/skeleton.in"\n' "${br2_ext}" 234*4882a593Smuzhiyun printf '\n' 235*4882a593Smuzhiyun else 236*4882a593Smuzhiyun printf '# No skeleton from: %s\n\n' "${br2_desc}" 237*4882a593Smuzhiyun fi >>"${outputdir}/.br2-external.in.skeleton" 238*4882a593Smuzhiyun 239*4882a593Smuzhiyun if [ -f "${br2_ext}/provides/init.in" ]; then 240*4882a593Smuzhiyun printf 'comment "init from: %s"\n' "${br2_desc}" 241*4882a593Smuzhiyun printf 'source "%s/provides/init.in"\n' "${br2_ext}" 242*4882a593Smuzhiyun printf '\n' 243*4882a593Smuzhiyun else 244*4882a593Smuzhiyun printf '# No init from: %s\n\n' "${br2_desc}" 245*4882a593Smuzhiyun fi >>"${outputdir}/.br2-external.in.init" 246*4882a593Smuzhiyun 247*4882a593Smuzhiyun if [ -f "${br2_ext}/linux/Config.ext.in" ]; then 248*4882a593Smuzhiyun printf 'comment "linux extension from: %s"\n' "${br2_desc}" 249*4882a593Smuzhiyun printf 'source "%s/linux/Config.ext.in"\n' "${br2_ext}" 250*4882a593Smuzhiyun printf '\n' 251*4882a593Smuzhiyun else 252*4882a593Smuzhiyun printf '# No linux extension from: %s\n\n' "${br2_desc}" 253*4882a593Smuzhiyun fi >>"${outputdir}/.br2-external.in.linux" 254*4882a593Smuzhiyun done 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun printf 'endmenu\n' >>"${outputdir}/.br2-external.in.menus" 257*4882a593Smuzhiyun} 258*4882a593Smuzhiyun 259*4882a593Smuzhiyunerror() { local fmt="${1}"; shift; printf "BR2_EXTERNAL_ERROR = ${fmt}" "${@}"; exit 1; } 260*4882a593Smuzhiyun 261*4882a593Smuzhiyunmy_name="${0##*/}" 262*4882a593Smuzhiyunmain "${@}" 263