diff mbox series

[v2] kbuild: check the minimum compiler version in Kconfig

Message ID 20210114042420.229524-1-masahiroy@kernel.org (mailing list archive)
State New
Headers show
Series [v2] kbuild: check the minimum compiler version in Kconfig | expand

Commit Message

Masahiro Yamada Jan. 14, 2021, 4:24 a.m. UTC
Paul Gortmaker reported a regression in the GCC version check [1].
If you use GCC 4.8, the build breaks before showing the error message
"error Sorry, your version of GCC is too old - please use 4.9 or newer."

I do not want to apply his fix-up since it implies we would not be able
to remove any cc-option test. Anyway, I admit checking the GCC version
in <linux/compiler-gcc.h> is too late.

Almost at the same time, Linus also suggested to move the compiler
version error to Kconfig time. [2]

I unified the similar two scripts, gcc-version.sh and clang-version.sh
into the new cc-version.sh. The old scripts invoked the compiler multiple
times (3 times for gcc-version.sh, 4 times for clang-version.sh). I
refactored the code so the new one invokes the compiler just once, and
also tried my best to use shell-builtin commands where possible.

The new script runs faster.

  $ time ./scripts/clang-version.sh clang
  120000

  real    0m0.029s
  user    0m0.012s
  sys     0m0.021s

  $ time ./scripts/cc-version.sh clang
  Clang 120000

  real    0m0.009s
  user    0m0.006s
  sys     0m0.004s

The cc-version.sh also shows the error if the compiler is old:

  $ make defconfig CC=clang-9
  *** Default configuration is based on 'x86_64_defconfig'
  ***
  *** Compiler is too old.
  ***   Your Clang version:    9.0.1
  ***   Minimum Clang version: 10.0.1
  ***
  scripts/Kconfig.include:46: Sorry, this compiler is unsupported.
  make[1]: *** [scripts/kconfig/Makefile:81: defconfig] Error 1
  make: *** [Makefile:602: defconfig] Error 2

I removed the clang version check from <linux/compiler-clang.h>

For now, I did not touch <linux/compiler-gcc.h> in order to avoid
merge conflict with [3], which has been queued up in the arm64 tree.
We will be able to clean it up later.

I put the stub for ICC because I see <linux/compiler-intel.h> although
I am not sure if building the kernel with ICC is well-supported.

[1] https://lkml.org/lkml/2021/1/10/250
[2] https://lkml.org/lkml/2021/1/12/1708
[3] https://lkml.org/lkml/2021/1/12/1533

Fixes: 87de84c9140e ("kbuild: remove cc-option test of -Werror=date-time")
Reported-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
---

Changes in v2:
  - fix the function name

 include/linux/compiler-clang.h | 10 -----
 init/Kconfig                   |  9 +++--
 scripts/Kconfig.include        |  6 +++
 scripts/cc-version.sh          | 69 ++++++++++++++++++++++++++++++++++
 scripts/clang-version.sh       | 19 ----------
 scripts/gcc-version.sh         | 20 ----------
 6 files changed, 80 insertions(+), 53 deletions(-)
 create mode 100755 scripts/cc-version.sh
 delete mode 100755 scripts/clang-version.sh
 delete mode 100755 scripts/gcc-version.sh

Comments

Ilie Halip Jan. 14, 2021, 7:54 a.m. UTC | #1
Hi Masahiro,

> +       #elif defined(__INTEL_COMPILER)
> +       /* How to get the version of intel compiler? */
> +       ICC     0               0               0

According to Intel documentation[1], this should do the trick:

    ICC     __INTEL_COMPILER  __INTEL_COMPILER_UPDATE
__INTEL_COMPILER_BUILD_DATE

I don't have the compiler installed, but I tested this on godbolt[2] and
looks fine to me. What do you think?

[1] https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/macros/additional-predefined-macros.html
[2] https://godbolt.org/z/E5PE6f

I.H.
Sedat Dilek Jan. 14, 2021, 8:09 a.m. UTC | #2
On Thu, Jan 14, 2021 at 8:55 AM Ilie Halip <ilie.halip@gmail.com> wrote:
>
> Hi Masahiro,
>
> > +       #elif defined(__INTEL_COMPILER)
> > +       /* How to get the version of intel compiler? */
> > +       ICC     0               0               0
>
> According to Intel documentation[1], this should do the trick:
>
>     ICC     __INTEL_COMPILER  __INTEL_COMPILER_UPDATE
> __INTEL_COMPILER_BUILD_DATE
>
> I don't have the compiler installed, but I tested this on godbolt[2] and
> looks fine to me. What do you think?
>

I remember at university I used ICC successfully with building a Linux-kernel.
Anyone has used ICC recently?

I cannot remember to have seen any bug-reports regarding ICC to
linux-kernel or linux-kbuild mailing-lists.

- Sedat -

> [1] https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/macros/additional-predefined-macros.html
> [2] https://godbolt.org/z/E5PE6f
>
> I.H.
>
> --
> You received this message because you are subscribed to the Google Groups "Clang Built Linux" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to clang-built-linux+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/clang-built-linux/CAHFW8PRr6kjEE%3D7BSzWo7itSZgAhy_dhmnSe1yq5wMfDwEyJ9g%40mail.gmail.com.
Masahiro Yamada Jan. 14, 2021, 9:20 a.m. UTC | #3
On Thu, Jan 14, 2021 at 4:55 PM Ilie Halip <ilie.halip@gmail.com> wrote:
>
> Hi Masahiro,
>
> > +       #elif defined(__INTEL_COMPILER)
> > +       /* How to get the version of intel compiler? */
> > +       ICC     0               0               0
>
> According to Intel documentation[1], this should do the trick:
>
>     ICC     __INTEL_COMPILER  __INTEL_COMPILER_UPDATE
> __INTEL_COMPILER_BUILD_DATE
>
> I don't have the compiler installed, but I tested this on godbolt[2] and
> looks fine to me. What do you think?
>
> [1] https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/macros/additional-predefined-macros.html
> [2] https://godbolt.org/z/E5PE6f
>
> I.H.

Thanks.

The following is the result from godbolt
(except the beta releases of 21.1.*)


version    __INTEL_COMPILER  __INTEL_COMPILER_UPDATE
13.0.1     1300               (unsupported)
16.0.3     1600               3
17.0.0     1700               0
18.0.0     1800               0
19.0.0     1900               0
19.0.1     1900               0



Presumably, the version string xx.yy.zz corresponds to
__INTEL_COMPILER=xxyy
__INTEL_COMPILER_UPDATE=zz

The output from 19.0.1 does not make sense, though.



BTW, when I tried ICC a few years ago,
I could not build the kernel with it.
Nathan Chancellor Jan. 14, 2021, 4:49 p.m. UTC | #4
On Thu, Jan 14, 2021 at 06:20:15PM +0900, Masahiro Yamada wrote:
> BTW, when I tried ICC a few years ago,
> I could not build the kernel with it.

Looking at the history behind include/linux/compiler-intel.h, the last
time I see a change that actually references building a kernel with icc
was 503cf95c061a ("x86, build, icc: Remove uninitialized_var() from
compiler-intel.h"), all the way back in 2013. Since then, there do not
appear to be any meaningful changes; every change is basically doing
something for clang or gcc and not wanting to leave icc behind. It might
be worth considering tearing it out.

Cheers,
Nathan
Nathan Chancellor Jan. 14, 2021, 5:07 p.m. UTC | #5
On Thu, Jan 14, 2021 at 01:24:19PM +0900, Masahiro Yamada wrote:
> Paul Gortmaker reported a regression in the GCC version check [1].
> If you use GCC 4.8, the build breaks before showing the error message
> "error Sorry, your version of GCC is too old - please use 4.9 or newer."
> 
> I do not want to apply his fix-up since it implies we would not be able
> to remove any cc-option test. Anyway, I admit checking the GCC version
> in <linux/compiler-gcc.h> is too late.
> 
> Almost at the same time, Linus also suggested to move the compiler
> version error to Kconfig time. [2]
> 
> I unified the similar two scripts, gcc-version.sh and clang-version.sh
> into the new cc-version.sh. The old scripts invoked the compiler multiple
> times (3 times for gcc-version.sh, 4 times for clang-version.sh). I
> refactored the code so the new one invokes the compiler just once, and
> also tried my best to use shell-builtin commands where possible.
> 
> The new script runs faster.
> 
>   $ time ./scripts/clang-version.sh clang
>   120000
> 
>   real    0m0.029s
>   user    0m0.012s
>   sys     0m0.021s
> 
>   $ time ./scripts/cc-version.sh clang
>   Clang 120000
> 
>   real    0m0.009s
>   user    0m0.006s
>   sys     0m0.004s
> 
> The cc-version.sh also shows the error if the compiler is old:
> 
>   $ make defconfig CC=clang-9
>   *** Default configuration is based on 'x86_64_defconfig'
>   ***
>   *** Compiler is too old.
>   ***   Your Clang version:    9.0.1
>   ***   Minimum Clang version: 10.0.1
>   ***
>   scripts/Kconfig.include:46: Sorry, this compiler is unsupported.
>   make[1]: *** [scripts/kconfig/Makefile:81: defconfig] Error 1
>   make: *** [Makefile:602: defconfig] Error 2
> 
> I removed the clang version check from <linux/compiler-clang.h>
> 
> For now, I did not touch <linux/compiler-gcc.h> in order to avoid
> merge conflict with [3], which has been queued up in the arm64 tree.
> We will be able to clean it up later.
> 
> I put the stub for ICC because I see <linux/compiler-intel.h> although
> I am not sure if building the kernel with ICC is well-supported.
> 
> [1] https://lkml.org/lkml/2021/1/10/250
> [2] https://lkml.org/lkml/2021/1/12/1708
> [3] https://lkml.org/lkml/2021/1/12/1533

I would recommend the lore version of these links:

[1]: https://lore.kernel.org/r/20210110190807.134996-1-paul.gortmaker@windriver.com
[2]: https://lore.kernel.org/r/CAHk-=wh-+TMHPTFo1qs-MYyK7tZh-OQovA=pP3=e06aCVp6_kA@mail.gmail.com
[3]: https://lore.kernel.org/r/20210112224832.10980-1-will@kernel.org

> Fixes: 87de84c9140e ("kbuild: remove cc-option test of -Werror=date-time")
> Reported-by: Paul Gortmaker <paul.gortmaker@windriver.com>
> Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
> Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>

I like this a lot, I think that erroring as early as possible when
something is misconfigured is a good user experience.

Reviewed-by: Nathan Chancellor <natechancellor@gmail.com>
Tested-by: Nathan Chancellor <natechancellor@gmail.com>

> ---
> 
> Changes in v2:
>   - fix the function name
> 
>  include/linux/compiler-clang.h | 10 -----
>  init/Kconfig                   |  9 +++--
>  scripts/Kconfig.include        |  6 +++
>  scripts/cc-version.sh          | 69 ++++++++++++++++++++++++++++++++++
>  scripts/clang-version.sh       | 19 ----------
>  scripts/gcc-version.sh         | 20 ----------
>  6 files changed, 80 insertions(+), 53 deletions(-)
>  create mode 100755 scripts/cc-version.sh
>  delete mode 100755 scripts/clang-version.sh
>  delete mode 100755 scripts/gcc-version.sh
> 
> diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h
> index 98cff1b4b088..04c0a5a717f7 100644
> --- a/include/linux/compiler-clang.h
> +++ b/include/linux/compiler-clang.h
> @@ -3,16 +3,6 @@
>  #error "Please don't include <linux/compiler-clang.h> directly, include <linux/compiler.h> instead."
>  #endif
>  
> -#define CLANG_VERSION (__clang_major__ * 10000	\
> -		     + __clang_minor__ * 100	\
> -		     + __clang_patchlevel__)
> -
> -#if CLANG_VERSION < 100001
> -#ifndef __BPF_TRACING__
> -# error Sorry, your version of Clang is too old - please use 10.0.1 or newer.
> -#endif
> -#endif
> -
>  /* Compiler specific definitions for Clang compiler */
>  
>  /* same as gcc, this was present in clang-2.6 so we can assume it works
> diff --git a/init/Kconfig b/init/Kconfig
> index b77c60f8b963..01108dd1318b 100644
> --- a/init/Kconfig
> +++ b/init/Kconfig
> @@ -26,11 +26,11 @@ config CC_VERSION_TEXT
>  	    and then every file will be rebuilt.
>  
>  config CC_IS_GCC
> -	def_bool $(success,echo "$(CC_VERSION_TEXT)" | grep -q gcc)
> +	def_bool $(success,test $(cc-name) = GCC)
>  
>  config GCC_VERSION
>  	int
> -	default $(shell,$(srctree)/scripts/gcc-version.sh $(CC)) if CC_IS_GCC
> +	default $(cc-version) if CC_IS_GCC
>  	default 0
>  
>  config LD_VERSION
> @@ -38,14 +38,15 @@ config LD_VERSION
>  	default $(shell,$(LD) --version | $(srctree)/scripts/ld-version.sh)
>  
>  config CC_IS_CLANG
> -	def_bool $(success,echo "$(CC_VERSION_TEXT)" | grep -q clang)
> +	def_bool $(success,test $(cc-name) = Clang)
>  
>  config LD_IS_LLD
>  	def_bool $(success,$(LD) -v | head -n 1 | grep -q LLD)
>  
>  config CLANG_VERSION
>  	int
> -	default $(shell,$(srctree)/scripts/clang-version.sh $(CC))
> +	default $(cc-version) if CC_IS_CLANG
> +	default 0
>  
>  config LLD_VERSION
>  	int
> diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include
> index a5fe72c504ff..cdc8726d2904 100644
> --- a/scripts/Kconfig.include
> +++ b/scripts/Kconfig.include
> @@ -39,6 +39,12 @@ as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler
>  $(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found)
>  $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found)
>  
> +# Get the compiler name, version, and error out if it is unsupported.
> +cc-info := $(shell,scripts/cc-version.sh $(CC))
> +$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this compiler is unsupported.)
> +cc-name := $(shell,set -- $(cc-info); echo $1)
> +cc-version := $(shell,set -- $(cc-info); echo $2)
> +
>  # Fail if the linker is gold as it's not capable of linking the kernel proper
>  $(error-if,$(success, $(LD) -v | grep -q gold), gold linker '$(LD)' not supported)
>  
> diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh
> new file mode 100755
> index 000000000000..9c17c1de401c
> --- /dev/null
> +++ b/scripts/cc-version.sh
> @@ -0,0 +1,69 @@
> +#!/bin/sh
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Print the compiler name and its version in a 5 or 6-digit form.
> +# Also, perform the minimum version check.
> +
> +set -e
> +
> +# When you raise the compiler version, please update
> +# Documentation/process/changes.rst as well.
> +gcc_min_version=4.9.0
> +clang_min_version=10.0.1
> +
> +# print the compiler name, major version, minor version, patchlevel version
> +get_compiler_info()
> +{
> +	cat <<- EOF | "$@" -E -P -x c - 2>/dev/null
> +	#if defined(__clang__)
> +	Clang	__clang_major__	__clang_minor__	__clang_patchlevel__
> +	#elif defined(__INTEL_COMPILER)
> +	/* How to get the version of intel compiler? */
> +	ICC	0		0		0
> +	#elif defined(__GNUC__)
> +	GCC	__GNUC__	__GNUC_MINOR__	__GNUC_PATCHLEVEL__
> +	#else
> +	unsupported	0		0		0
> +	#endif
> +	EOF
> +}
> +
> +# convert the version to a canonical 5 or 6-digit form for numerical comparison
> +get_canonical_version()
> +{
> +	IFS=.
> +	set -- $1
> +	echo $((10000 * $1 + 100 * $2 + $3))
> +}
> +
> +# $@ instead of $1 because multiple words might be given e.g. CC="ccache gcc"
> +orig_args="$@"
> +set -- $(get_compiler_info "$@")
> +
> +name=$1
> +version=$2.$3.$4
> +
> +case "$name" in
> +GCC) min_version=$gcc_min_version;;
> +Clang) min_version=$clang_min_version;;
> +ICC) ;; # ICC min version undefined?
> +*) echo "$orig_args: unknown compiler" >&2; exit 1;;
> +esac
> +
> +cversion=$(get_canonical_version $version)
> +
> +if [ -n "$min_version" ]; then
> +
> +	min_cversion=$(get_canonical_version $min_version)
> +
> +	if [ "$cversion" -lt "$min_cversion" ]; then
> +		echo >&2 "***"
> +		echo >&2 "*** Compiler is too old."
> +		echo >&2 "***   Your $name version:    $version"
> +		echo >&2 "***   Minimum $name version: $min_version"
> +		echo >&2 "***"
> +		exit 1
> +	fi
> +fi
> +
> +echo $name $cversion
> diff --git a/scripts/clang-version.sh b/scripts/clang-version.sh
> deleted file mode 100755
> index 6fabf0695761..000000000000
> --- a/scripts/clang-version.sh
> +++ /dev/null
> @@ -1,19 +0,0 @@
> -#!/bin/sh
> -# SPDX-License-Identifier: GPL-2.0
> -#
> -# clang-version clang-command
> -#
> -# Print the compiler version of `clang-command' in a 5 or 6-digit form
> -# such as `50001' for clang-5.0.1 etc.
> -
> -compiler="$*"
> -
> -if ! ( $compiler --version | grep -q clang) ; then
> -	echo 0
> -	exit 1
> -fi
> -
> -MAJOR=$(echo __clang_major__ | $compiler -E -x c - | tail -n 1)
> -MINOR=$(echo __clang_minor__ | $compiler -E -x c - | tail -n 1)
> -PATCHLEVEL=$(echo __clang_patchlevel__ | $compiler -E -x c - | tail -n 1)
> -printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
> diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh
> deleted file mode 100755
> index ae353432539b..000000000000
> --- a/scripts/gcc-version.sh
> +++ /dev/null
> @@ -1,20 +0,0 @@
> -#!/bin/sh
> -# SPDX-License-Identifier: GPL-2.0
> -#
> -# gcc-version gcc-command
> -#
> -# Print the gcc version of `gcc-command' in a 5 or 6-digit form
> -# such as `29503' for gcc-2.95.3, `30301' for gcc-3.3.1, etc.
> -
> -compiler="$*"
> -
> -if [ ${#compiler} -eq 0 ]; then
> -	echo "Error: No compiler specified." >&2
> -	printf "Usage:\n\t$0 <gcc-command>\n" >&2
> -	exit 1
> -fi
> -
> -MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1)
> -MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1)
> -PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1)
> -printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
> -- 
> 2.27.0
>
Miguel Ojeda Jan. 14, 2021, 6:14 p.m. UTC | #6
On Thu, Jan 14, 2021 at 5:25 AM Masahiro Yamada <masahiroy@kernel.org> wrote:
>
> The cc-version.sh also shows the error if the compiler is old:
>
>   $ make defconfig CC=clang-9
>   *** Default configuration is based on 'x86_64_defconfig'
>   ***
>   *** Compiler is too old.
>   ***   Your Clang version:    9.0.1
>   ***   Minimum Clang version: 10.0.1
>   ***
>   scripts/Kconfig.include:46: Sorry, this compiler is unsupported.

That looks nice. Hopefully we can do the same approach for other tools too!

> I put the stub for ICC because I see <linux/compiler-intel.h> although
> I am not sure if building the kernel with ICC is well-supported.

I doubt it, and there seems to be no maintainer listed either. I think
it could be considered for removal in an RFC.

Cheers,
Miguel
Masahiro Yamada Jan. 15, 2021, 10:54 p.m. UTC | #7
On Fri, Jan 15, 2021 at 3:15 AM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Thu, Jan 14, 2021 at 5:25 AM Masahiro Yamada <masahiroy@kernel.org> wrote:
> >
> > The cc-version.sh also shows the error if the compiler is old:
> >
> >   $ make defconfig CC=clang-9
> >   *** Default configuration is based on 'x86_64_defconfig'
> >   ***
> >   *** Compiler is too old.
> >   ***   Your Clang version:    9.0.1
> >   ***   Minimum Clang version: 10.0.1
> >   ***
> >   scripts/Kconfig.include:46: Sorry, this compiler is unsupported.
>
> That looks nice. Hopefully we can do the same approach for other tools too!


Yes, I plan to merge scripts/ld-version.sh and scripts/lld-version.sh
in a similar way, and move the version check as well
once the following cleanups land in the upstream:

https://patchwork.kernel.org/project/linux-kbuild/patch/20201212165431.150750-1-masahiroy@kernel.org/
https://patchwork.kernel.org/project/linux-kbuild/patch/20201212165431.150750-2-masahiroy@kernel.org/


> > I put the stub for ICC because I see <linux/compiler-intel.h> although
> > I am not sure if building the kernel with ICC is well-supported.
>
> I doubt it, and there seems to be no maintainer listed either. I think
> it could be considered for removal in an RFC.


Yes, but that would require higher level acks,
and consult x86 and intel folks.

Please let this patch land first,
then we will discuss whether ICC is still used or not.




> Cheers,
> Miguel
Miguel Ojeda Jan. 16, 2021, 1:33 a.m. UTC | #8
On Fri, Jan 15, 2021 at 11:55 PM Masahiro Yamada <masahiroy@kernel.org> wrote:
>
> Yes, I plan to merge scripts/ld-version.sh and scripts/lld-version.sh
> in a similar way, and move the version check as well
> once the following cleanups land in the upstream:
>
> https://patchwork.kernel.org/project/linux-kbuild/patch/20201212165431.150750-1-masahiroy@kernel.org/
> https://patchwork.kernel.org/project/linux-kbuild/patch/20201212165431.150750-2-masahiroy@kernel.org/

Nice!

> Yes, but that would require higher level acks,
> and consult x86 and intel folks.
>
> Please let this patch land first,
> then we will discuss whether ICC is still used or not.

I was not implying to delay this patch -- rather to start an
independent RFC to discuss it. This patch should go in regardless of
that, of course :-)

Cheers,
Miguel
diff mbox series

Patch

diff --git a/include/linux/compiler-clang.h b/include/linux/compiler-clang.h
index 98cff1b4b088..04c0a5a717f7 100644
--- a/include/linux/compiler-clang.h
+++ b/include/linux/compiler-clang.h
@@ -3,16 +3,6 @@ 
 #error "Please don't include <linux/compiler-clang.h> directly, include <linux/compiler.h> instead."
 #endif
 
-#define CLANG_VERSION (__clang_major__ * 10000	\
-		     + __clang_minor__ * 100	\
-		     + __clang_patchlevel__)
-
-#if CLANG_VERSION < 100001
-#ifndef __BPF_TRACING__
-# error Sorry, your version of Clang is too old - please use 10.0.1 or newer.
-#endif
-#endif
-
 /* Compiler specific definitions for Clang compiler */
 
 /* same as gcc, this was present in clang-2.6 so we can assume it works
diff --git a/init/Kconfig b/init/Kconfig
index b77c60f8b963..01108dd1318b 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -26,11 +26,11 @@  config CC_VERSION_TEXT
 	    and then every file will be rebuilt.
 
 config CC_IS_GCC
-	def_bool $(success,echo "$(CC_VERSION_TEXT)" | grep -q gcc)
+	def_bool $(success,test $(cc-name) = GCC)
 
 config GCC_VERSION
 	int
-	default $(shell,$(srctree)/scripts/gcc-version.sh $(CC)) if CC_IS_GCC
+	default $(cc-version) if CC_IS_GCC
 	default 0
 
 config LD_VERSION
@@ -38,14 +38,15 @@  config LD_VERSION
 	default $(shell,$(LD) --version | $(srctree)/scripts/ld-version.sh)
 
 config CC_IS_CLANG
-	def_bool $(success,echo "$(CC_VERSION_TEXT)" | grep -q clang)
+	def_bool $(success,test $(cc-name) = Clang)
 
 config LD_IS_LLD
 	def_bool $(success,$(LD) -v | head -n 1 | grep -q LLD)
 
 config CLANG_VERSION
 	int
-	default $(shell,$(srctree)/scripts/clang-version.sh $(CC))
+	default $(cc-version) if CC_IS_CLANG
+	default 0
 
 config LLD_VERSION
 	int
diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include
index a5fe72c504ff..cdc8726d2904 100644
--- a/scripts/Kconfig.include
+++ b/scripts/Kconfig.include
@@ -39,6 +39,12 @@  as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler
 $(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found)
 $(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found)
 
+# Get the compiler name, version, and error out if it is unsupported.
+cc-info := $(shell,scripts/cc-version.sh $(CC))
+$(error-if,$(success,test -z "$(cc-info)"),Sorry$(comma) this compiler is unsupported.)
+cc-name := $(shell,set -- $(cc-info); echo $1)
+cc-version := $(shell,set -- $(cc-info); echo $2)
+
 # Fail if the linker is gold as it's not capable of linking the kernel proper
 $(error-if,$(success, $(LD) -v | grep -q gold), gold linker '$(LD)' not supported)
 
diff --git a/scripts/cc-version.sh b/scripts/cc-version.sh
new file mode 100755
index 000000000000..9c17c1de401c
--- /dev/null
+++ b/scripts/cc-version.sh
@@ -0,0 +1,69 @@ 
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Print the compiler name and its version in a 5 or 6-digit form.
+# Also, perform the minimum version check.
+
+set -e
+
+# When you raise the compiler version, please update
+# Documentation/process/changes.rst as well.
+gcc_min_version=4.9.0
+clang_min_version=10.0.1
+
+# print the compiler name, major version, minor version, patchlevel version
+get_compiler_info()
+{
+	cat <<- EOF | "$@" -E -P -x c - 2>/dev/null
+	#if defined(__clang__)
+	Clang	__clang_major__	__clang_minor__	__clang_patchlevel__
+	#elif defined(__INTEL_COMPILER)
+	/* How to get the version of intel compiler? */
+	ICC	0		0		0
+	#elif defined(__GNUC__)
+	GCC	__GNUC__	__GNUC_MINOR__	__GNUC_PATCHLEVEL__
+	#else
+	unsupported	0		0		0
+	#endif
+	EOF
+}
+
+# convert the version to a canonical 5 or 6-digit form for numerical comparison
+get_canonical_version()
+{
+	IFS=.
+	set -- $1
+	echo $((10000 * $1 + 100 * $2 + $3))
+}
+
+# $@ instead of $1 because multiple words might be given e.g. CC="ccache gcc"
+orig_args="$@"
+set -- $(get_compiler_info "$@")
+
+name=$1
+version=$2.$3.$4
+
+case "$name" in
+GCC) min_version=$gcc_min_version;;
+Clang) min_version=$clang_min_version;;
+ICC) ;; # ICC min version undefined?
+*) echo "$orig_args: unknown compiler" >&2; exit 1;;
+esac
+
+cversion=$(get_canonical_version $version)
+
+if [ -n "$min_version" ]; then
+
+	min_cversion=$(get_canonical_version $min_version)
+
+	if [ "$cversion" -lt "$min_cversion" ]; then
+		echo >&2 "***"
+		echo >&2 "*** Compiler is too old."
+		echo >&2 "***   Your $name version:    $version"
+		echo >&2 "***   Minimum $name version: $min_version"
+		echo >&2 "***"
+		exit 1
+	fi
+fi
+
+echo $name $cversion
diff --git a/scripts/clang-version.sh b/scripts/clang-version.sh
deleted file mode 100755
index 6fabf0695761..000000000000
--- a/scripts/clang-version.sh
+++ /dev/null
@@ -1,19 +0,0 @@ 
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-#
-# clang-version clang-command
-#
-# Print the compiler version of `clang-command' in a 5 or 6-digit form
-# such as `50001' for clang-5.0.1 etc.
-
-compiler="$*"
-
-if ! ( $compiler --version | grep -q clang) ; then
-	echo 0
-	exit 1
-fi
-
-MAJOR=$(echo __clang_major__ | $compiler -E -x c - | tail -n 1)
-MINOR=$(echo __clang_minor__ | $compiler -E -x c - | tail -n 1)
-PATCHLEVEL=$(echo __clang_patchlevel__ | $compiler -E -x c - | tail -n 1)
-printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh
deleted file mode 100755
index ae353432539b..000000000000
--- a/scripts/gcc-version.sh
+++ /dev/null
@@ -1,20 +0,0 @@ 
-#!/bin/sh
-# SPDX-License-Identifier: GPL-2.0
-#
-# gcc-version gcc-command
-#
-# Print the gcc version of `gcc-command' in a 5 or 6-digit form
-# such as `29503' for gcc-2.95.3, `30301' for gcc-3.3.1, etc.
-
-compiler="$*"
-
-if [ ${#compiler} -eq 0 ]; then
-	echo "Error: No compiler specified." >&2
-	printf "Usage:\n\t$0 <gcc-command>\n" >&2
-	exit 1
-fi
-
-MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1)
-MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1)
-PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1)
-printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL