451 lines · 11.0 KB · Text
RawDownload
# SPDX-License-Identifier: GPL-2.0-only# bash completion for GNU make with kbuild extension       -*- shell-script -*- # Load the default completion script for make. It is typically located at# /usr/share/bash-completion/completions/make, but we do not rely on it.__kbuild_load_default_make_completion(){	local -a dirs=("${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions")	local ifs=$IFS IFS=: dir compfile this_dir 	for dir in ${XDG_DATA_DIRS:-/usr/local/share:/usr/share}; do	        dirs+=("$dir"/bash-completion/completions)	done	IFS=$ifs 	this_dir="$(realpath "$(dirname "${BASH_SOURCE[0]}")")" 	for dir in "${dirs[@]}"; do		if [[ ! -d ${dir} || ${dir} = "${this_dir}" ]]; then			continue		fi 		for compfile in make make.bash _make; do			compfile=$dir/$compfile			# Avoid trying to source dirs; https://bugzilla.redhat.com/903540			if [[ -f ${compfile} ]] && . "${compfile}" &>/dev/null; then 				__kbuild_default_make_completion=$(					# shellcheck disable=SC2046 # word splitting is the point here					set -- $(complete -p make) 					while [[ $# -gt 1 && "$1" != -F ]]; do						shift					done 					if [[ "$1" = -F ]]; then						echo "$2"					fi				) 				return			fi		done	done} __kbuild_load_default_make_completion __kbuild_handle_variable(){	local var=${1%%=*}	local cur=${cur#"${var}"=}	local srctree=$2	local keywords=() 	case $var in	ARCH)		# sub-directories under arch/		keywords+=($(find "${srctree}/arch" -mindepth 1 -maxdepth 1 -type d -printf '%P\n'))		# architectures hard-coded in the top Makefile		keywords+=(i386 x86_64 sparc32 sparc64 parisc64)		;;	CROSS_COMPILE)		# toolchains with a full path		local cross_compile=()		local c c2		_filedir 		for c in "${COMPREPLY[@]}"; do			# eval for tilde expansion			# suppress error, as this fails when it contains a space			eval "c2=${c}" 2>/dev/null || continue			if [[ ${c} == *-elfedit && ! -d ${c2} && -x ${c2} ]]; then				cross_compile+=("${c%elfedit}")			fi		done 		# toolchains in the PATH environment		while read -r c; do			if [[ ${c} == *-elfedit ]]; then				keywords+=("${c%elfedit}")			fi		done < <(compgen -c) 		COMPREPLY=()		_filedir -d 		# Add cross_compile directly without passing it to compgen.		# Otherwise, toolchain paths with a tilde do not work.		# e.g.)		#   CROSS_COMPILE=~/0day/gcc-14.2.0-nolibc/aarch64-linux/bin/aarch64-linux-		COMPREPLY+=("${cross_compile[@]}")		;;	LLVM)		# LLVM=1 uses the default 'clang' etc.		keywords+=(1) 		# suffix for a particular version. LLVM=-18 uses 'clang-18' etc.		while read -r c; do			if [[ ${c} == clang-[0-9]* ]]; then				keywords+=("${c#clang}")			fi		done < <(compgen -c) 		# directory path to LLVM toolchains		_filedir -d		;;	KCONFIG_ALLCONFIG)		# KCONFIG_ALLCONFIG=1 selects the default fragment		keywords+=(1)		# or the path to a fragment file		_filedir		;;	C | KBUILD_CHECKSRC)		keywords+=(1 2)		;;	V | KBUILD_VERBOSE)		keywords+=({,1}{,2})		;;	W | KBUILD_EXTRA_WARN)		keywords+=({,1}{,2}{,3}{,c}{,e})		;;	KBUILD_ABS_SRCTREE | KBUILD_MODPOST_NOFINAL | KBUILD_MODPOST_WARN | \		CLIPPY | KBUILD_CLIPPY | KCONFIG_NOSILENTUPDATE | \		KCONFIG_OVERWRITECONFIG | KCONFIG_WARN_UNKNOWN_SYMBOL | \		KCONFIG_WERROR )		keywords+=(1)		;;	INSTALL_MOD_STRIP)		keywords+=(1 --strip-debug --strip-unneeded)		;;	O | KBUILD_OUTPUT | M | KBUILD_EXTMOD | MO | KBUILD_EXTMOD_OUTPUT | *_PATH)		# variables that take a directory.		_filedir -d		return		;;	KBUILD_EXTRA_SYMBOL | KBUILD_KCONFIG | KCONFIG_CONFIG)		# variables that take a file.		_filedir		return	esac 	COMPREPLY+=($(compgen -W "${keywords[*]}" -- "${cur}"))} # Check the -C, -f options and 'source' symlink. Return the source tree we are# working in.__kbuild_get_srctree(){	local words=("$@")	local cwd makef_dir 	# see if a path was specified with -C/--directory	for ((i = 1; i < ${#words[@]}; i++)); do		if [[ ${words[i]} == -@(C|-directory) ]]; then			# eval for tilde expansion.			# suppress error, as this fails when it contains a space			eval "cwd=${words[i + 1]}" 2>/dev/null			break		fi	done 	if [[ -z ${cwd} ]]; then		cwd=.	fi 	# see if a Makefile was specified with -f/--file/--makefile	for ((i = 1; i < ${#words[@]}; i++)); do		if [[ ${words[i]} == -@(f|-?(make)file) ]]; then			# eval for tilde expansion			# suppress error, as this fails when it contains a space			eval "makef_dir=${words[i + 1]%/*}" 2>/dev/null			break		fi	done 	if [ -z "${makef_dir}" ]; then		makef_dir=${cwd}	elif [[ ${makef_dir} != /* ]]; then		makef_dir=${cwd}/${makef_dir}	fi 	# If ${makef_dir} is a build directory created by the O= option, there	# is a symbolic link 'source', which points to the kernel source tree.	if [[ -L ${makef_dir}/source ]]; then		makef_dir=$(readlink "${makef_dir}/source")	fi 	echo "${makef_dir}"} # Get SRCARCH to do a little more clever things__kbuild_get_srcarch(){	local words=("$@")	local arch srcarch uname_m 	# see if ARCH= is explicitly specified	for ((i = 1; i < ${#words[@]}; i++)); do		if [[ ${words[i]} == ARCH=* ]]; then			arch=${words[i]#ARCH=}			break		fi	done 	# If ARCH= is not specified, check the build marchine's architecture	if [[ -z ${arch} ]]; then		uname_m=$(uname -m) 		# shellcheck disable=SC2209 # 'sh' is SuperH, not a shell command		case ${uname_m} in		arm64 | aarch64*) arch=arm64 ;;		arm* | sa110)     arch=arm ;;		i?86 | x86_64)    arch=x86 ;;		loongarch*)       arch=loongarch ;;		mips*)            arch=mips ;;		ppc*)             arch=powerpc ;;		riscv*)           arch=riscv ;;		s390x)            arch=s390 ;;		sh[234]*)         arch=sh ;;		sun4u)            arch=sparc64 ;;		*)                arch=${uname_m} ;;		esac	fi 	case ${arch} in		parisc64)          srcarch=parisc ;;		sparc32 | sparc64) srcarch=sparc ;;		i386 | x86_64)     srcarch=x86 ;;		*)                 srcarch=${arch} ;;	esac 	echo "$srcarch"} # small Makefile to parse obj-* syntax__kbuild_tmp_makefile(){cat <<'EOF'.PHONY: __default__default:	$(foreach m,$(obj-y) $(obj-m) $(obj-),$(foreach s, -objs -y -m -,$($(m:%.o=%$s))) $(m))EOFecho "include ${1}"} _make_for_kbuild (){	# shellcheck disable=SC2034 # these are set by _init_completion	local cur prev words cword split	_init_completion -s || return 	local srctree	srctree=$(__kbuild_get_srctree "${words[@]}") 	# If 'kernel' and 'Documentation' directories are found, we assume this	# is a kernel tree. Otherwise, we fall back to the generic rule provided	# by the bash-completion project.	if [[ ! -d ${srctree}/kernel || ! -d ${srctree}/Documentation ]]; then		if [ -n "${__kbuild_default_make_completion}" ]; then			"${__kbuild_default_make_completion}" "$@"		fi		return	fi 	# make options with a parameter (copied from the bash-completion project)	case ${prev} in	--file | --makefile | --old-file | --assume-old | --what-if | --new-file | \		--assume-new | -!(-*)[foW])		_filedir		return		;;	--include-dir | --directory | -!(-*)[ICm])		_filedir -d		return		;;	-!(-*)E)		COMPREPLY=($(compgen -v -- "$cur"))		return		;;	--eval | -!(-*)[DVx])		return		;;	--jobs | -!(-*)j)		COMPREPLY=($(compgen -W "{1..$(($(_ncpus) * 2))}" -- "$cur"))		return		;;	esac 	local keywords=() 	case ${cur} in	-*)		# make options (copied from the bash-completion project)		local opts		opts="$(_parse_help "$1")"		COMPREPLY=($(compgen -W "${opts:-$(_parse_usage "$1")}" -- "$cur"))		if [[ ${COMPREPLY-} == *= ]]; then			compopt -o nospace		fi		return		;;	*=*)		__kbuild_handle_variable "${cur}" "${srctree}"		return		;;	KBUILD_*)		# There are many variables prefixed with 'KBUILD_'.		# Display them only when 'KBUILD_' is entered.		# shellcheck disable=SC2191 # '=' is appended for variables		keywords+=(			KBUILD_{CHECKSRC,EXTMOD,EXTMOD_OUTPUT,OUTPUT,VERBOSE,EXTRA_WARN,CLIPPY}=			KBUILD_BUILD_{USER,HOST,TIMESTAMP}=			KBUILD_MODPOST_{NOFINAL,WARN}=			KBUILD_{ABS_SRCTREE,EXTRA_SYMBOLS,KCONFIG}=		)		;;	KCONFIG_*)		# There are many variables prefixed with 'KCONFIG_'.		# Display them only when 'KCONFIG_' is entered.		# shellcheck disable=SC2191 # '=' is appended for variables		keywords+=(			KCONFIG_{CONFIG,ALLCONFIG,NOSILENTUPDATE,OVERWRITECONFIG}=			KCONFIG_{SEED,PROBABILITY}=			KCONFIG_WARN_UNKNOWN_SYMBOL=			KCONFIG_WERROR=		)		;;	*)		# By default, hide KBUILD_* and KCONFIG_* variables.		# Instead, display only the prefix parts.		keywords+=(KBUILD_ KCONFIG_)		;;	esac 	if [[ ${cur} != /* && ${cur} != *//* ]]; then		local dir srcarch kbuild_file tmp		srcarch=$(__kbuild_get_srcarch "${words[@]}") 		# single build		dir=${cur}		while true; do			if [[ ${dir} == */* ]]; then				dir=${dir%/*}			else				dir=.			fi 			# Search for 'Kbuild' or 'Makefile' in the parent			# directories (may not be a direct parent)			if [[ -f ${srctree}/${dir}/Kbuild ]]; then				kbuild_file=${srctree}/${dir}/Kbuild				break			fi			if [[ -f ${srctree}/${dir}/Makefile ]]; then				kbuild_file=${srctree}/${dir}/Makefile				break			fi 			if [[ ${dir} == . ]]; then				break			fi		done 		if [[ -n ${kbuild_file} ]]; then			tmp=($(__kbuild_tmp_makefile "${kbuild_file}" |			       SRCARCH=${srcarch} obj=${dir} src=${srctree}/${dir} \			       "${1}" -n -f - 2>/dev/null)) 			# Add $(obj)/ prefix			if [[ ${dir} != . ]]; then				tmp=("${tmp[@]/#/${dir}\/}")			fi 			keywords+=("${tmp[@]}")		fi 		# *_defconfig and *.config files. These might be grouped into		# subdirectories, e.g., arch/powerpc/configs/*/*_defconfig.		if [[ ${cur} == */* ]]; then			dir=${cur%/*}		else			dir=.		fi 		tmp=($(find "${srctree}/arch/${srcarch}/configs/${dir}" \		       "${srctree}/kernel/configs/${dir}" \		       -mindepth 1 -maxdepth 1 -type d -printf '%P/\n' \		       -o -printf '%P\n' 2>/dev/null)) 		if [[ ${dir} != . ]]; then			tmp=("${tmp[@]/#/${dir}\/}")		fi 		keywords+=("${tmp[@]}")	fi 	# shellcheck disable=SC2191 # '=' is appended for variables	keywords+=(		#		# variables (append =)		#		ARCH=		CROSS_COMPILE=		LLVM=		C= M= MO= O= V= W=		INSTALL{,_MOD,_HDR,_DTBS}_PATH=		KERNELRELEASE= 		#		# targets		#		all help		clean mrproper distclean		clang-{tidy,analyzer} compile_commands.json		coccicheck		dtbs{,_check,_install} dt_binding_{check,schemas}		headers{,_install}		vmlinux install		modules{,_prepare,_install,_sign}		vdso_install		tags TAGS cscope gtags		rust{available,fmt,fmtcheck}		kernel{version,release} image_name		kselftest{,-all,-install,-clean,-merge} 		# configuration		{,old,olddef,sync,def,savedef,rand,listnew,helpnew,test,tiny}config		{,build_}{menu,n,g,x}config		local{mod,yes}config		all{no,yes,mod,def}config		{yes2mod,mod2yes,mod2no}config 		# docs		{html,textinfo,info,latex,pdf,epub,xml,linkcheck,refcheck,clean}docs 		# package		{,bin,src}{rpm,deb}-pkg		{pacman,dir,tar}-pkg		tar{,gz,bz2,xz,zst}-pkg		perf-tar{,gz,bz2,xz,zst}-src-pkg	) 	COMPREPLY=($(compgen -W "${keywords[*]}" -- "${cur}")) 	# Do not append a space for variables, subdirs, "KBUILD_", "KCONFIG_".	if [[ ${COMPREPLY-} == *[=/] || ${COMPREPLY-} =~ ^(KBUILD|KCONFIG)_$ ]]; then		compopt -o nospace	fi } && complete -F _make_for_kbuild make