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