Merge tag 'kbuild-misc-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/masahi...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 18 Nov 2017 01:51:33 +0000 (17:51 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 18 Nov 2017 01:51:33 +0000 (17:51 -0800)
Pull Kbuild misc updates from Masahiro Yamada:

 - Clean up and fix RPM package build

 - Fix a warning in DEB package build

 - Improve coccicheck script

 - Improve some semantic patches

* tag 'kbuild-misc-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild:
  docs: dev-tools: coccinelle: delete out of date wiki reference
  coccinelle: orplus: reorganize to improve performance
  coccinelle: use exists to improve efficiency
  builddeb: Pass the kernel:debarch substvar to dpkg-genchanges
  Coccinelle: use false positive annotation
  coccinelle: fix verbose message about .cocci file being run
  coccinelle: grep Options and Requires fields more precisely
  Coccinelle: make DEBUG_FILE option more useful
  coccinelle: api: detect identical chip data arrays
  coccinelle: Improve setup_timer.cocci matching
  Coccinelle: setup_timer: improve messages from setup_timer
  kbuild: rpm-pkg: do not force -jN in submake
  kbuild: rpm-pkg: keep spec file until make mrproper
  kbuild: rpm-pkg: fix jobserver unavailable warning
  kbuild: rpm-pkg: replace $RPM_BUILD_ROOT with %{buildroot}
  kbuild: rpm-pkg: fix build error when CONFIG_MODULES is disabled
  kbuild: rpm-pkg: refactor mkspec with here doc
  kbuild: rpm-pkg: clean up mkspec
  kbuild: rpm-pkg: install vmlinux.bz2 unconditionally
  kbuild: rpm-pkg: remove ppc64 specific image handling

12 files changed:
.gitignore
Documentation/dev-tools/coccinelle.rst
scripts/coccicheck
scripts/coccinelle/api/check_bq27xxx_data.cocci [new file with mode: 0644]
scripts/coccinelle/api/setup_timer.cocci
scripts/coccinelle/iterators/list_entry_update.cocci
scripts/coccinelle/misc/ifcol.cocci
scripts/coccinelle/misc/orplus.cocci
scripts/coccinelle/null/badzero.cocci
scripts/package/Makefile
scripts/package/builddeb
scripts/package/mkspec

index 6c119eab5d46921575fe606e9fe362ab5190791e..f6050b88e95b5b59e2c08dbef865d92049956e58 100644 (file)
@@ -55,6 +55,11 @@ modules.builtin
 /System.map
 /Module.markers
 
+#
+# RPM spec file (make rpm-pkg)
+#
+/*.spec
+
 #
 # Debian directory (make deb-pkg)
 #
index 37e474ff69115da89dd780475a35d119d5ee4383..94f41c290bfc69eb417066c0cff30f361f1c9bcc 100644 (file)
@@ -33,9 +33,6 @@ of many distributions, e.g. :
 You can get the latest version released from the Coccinelle homepage at
 http://coccinelle.lip6.fr/
 
-Information and tips about Coccinelle are also provided on the wiki
-pages at http://cocci.ekstranet.diku.dk/wiki/doku.php
-
 Once you have it, run the following command::
 
        ./configure
index 28ad1feff9e12d07fbf1ff2369ca1ecf7e76dd85..d5f28d5044e74e996a66311b691d9b5455b88389 100755 (executable)
@@ -123,15 +123,8 @@ run_cmd_parmap() {
        if [ $VERBOSE -ne 0 ] ; then
                echo "Running ($NPROC in parallel): $@"
        fi
-       if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
-               if [ -f $DEBUG_FILE ]; then
-                       echo "Debug file $DEBUG_FILE exists, bailing"
-                       exit
-               fi
-       else
-               DEBUG_FILE="/dev/null"
-       fi
-       $@ 2>$DEBUG_FILE
+       echo $@ >>$DEBUG_FILE
+       $@ 2>>$DEBUG_FILE
        if [[ $? -ne 0 ]]; then
                echo "coccicheck failed"
                exit $?
@@ -176,8 +169,8 @@ OPTIONS="$OPTIONS $SPFLAGS"
 coccinelle () {
     COCCI="$1"
 
-    OPT=`grep "Option" $COCCI | cut -d':' -f2`
-    REQ=`grep "Requires" $COCCI | cut -d':' -f2 | sed "s| ||"`
+    OPT=`grep "Options:" $COCCI | cut -d':' -f2`
+    REQ=`grep "Requires:" $COCCI | cut -d':' -f2 | sed "s| ||"`
     REQ_NUM=$(echo $REQ | ${DIR}/scripts/ld-version.sh)
     if [ "$REQ_NUM" != "0" ] ; then
            if [ "$SPATCH_VERSION_NUM" -lt "$REQ_NUM" ] ; then
@@ -194,7 +187,7 @@ coccinelle () {
 
     if [ $VERBOSE -ne 0 -a $ONLINE -eq 0 ] ; then
 
-       FILE=`echo $COCCI | sed "s|$srctree/||"`
+       FILE=${COCCI#$srctree/}
 
        echo "Processing `basename $COCCI`"
        echo "with option(s) \"$OPT\""
@@ -247,6 +240,15 @@ coccinelle () {
 
 }
 
+if [ "$DEBUG_FILE" != "/dev/null" -a "$DEBUG_FILE" != "" ]; then
+       if [ -f $DEBUG_FILE ]; then
+               echo "Debug file $DEBUG_FILE exists, bailing"
+               exit
+       fi
+else
+       DEBUG_FILE="/dev/null"
+fi
+
 if [ "$COCCI" = "" ] ; then
     for f in `find $srctree/scripts/coccinelle/ -name '*.cocci' -type f | sort`; do
        coccinelle $f
diff --git a/scripts/coccinelle/api/check_bq27xxx_data.cocci b/scripts/coccinelle/api/check_bq27xxx_data.cocci
new file mode 100644 (file)
index 0000000..9212b85
--- /dev/null
@@ -0,0 +1,161 @@
+/// Detect BQ27XXX_DATA structures with identical registers, dm registers or
+/// properties.
+//# Doesn't unfold macros used in register or property fields.
+//# Requires OCaml scripting
+///
+// Confidence: High
+// Copyright: (C) 2017 Julia Lawall, Inria/LIP6, GPLv2.
+// URL: http://coccinelle.lip6.fr/
+// Requires: 1.0.7
+// Keywords: BQ27XXX_DATA
+
+virtual report
+
+@initialize:ocaml@
+@@
+
+let print_report p msg =
+  let p = List.hd p in
+  Printf.printf "%s:%d:%d-%d: %s" p.file p.line p.col p.col_end msg
+
+@str depends on report@
+type t;
+identifier i,i1,i2;
+expression e1,e2;
+@@
+
+t i[] = {
+  ...,
+  [e1] = BQ27XXX_DATA(i1,...),
+  ...,
+  [e2] = BQ27XXX_DATA(i2,...),
+  ...,
+};
+
+@script:ocaml tocheck@
+i1 << str.i1;
+i2 << str.i2;
+i1regs; i2regs;
+i1dmregs; i2dmregs;
+i1props; i2props;
+@@
+
+if not(i1 = i2)
+then
+  begin
+    i1regs := make_ident (i1 ^ "_regs");
+    i2regs := make_ident (i2 ^ "_regs");
+    i1dmregs := make_ident (i1 ^ "_dm_regs");
+    i2dmregs := make_ident (i2 ^ "_dm_regs");
+    i1props := make_ident (i1 ^ "_props");
+    i2props := make_ident (i2 ^ "_props")
+  end
+
+(* ---------------------------------------------------------------- *)
+
+@getregs1@
+typedef u8;
+identifier tocheck.i1regs;
+initializer list i1regs_vals;
+position p1;
+@@
+
+u8 i1regs@p1[...] = { i1regs_vals, };
+
+@getregs2@
+identifier tocheck.i2regs;
+initializer list i2regs_vals;
+position p2;
+@@
+
+u8 i2regs@p2[...] = { i2regs_vals, };
+
+@script:ocaml@
+(_,i1regs_vals) << getregs1.i1regs_vals;
+(_,i2regs_vals) << getregs2.i2regs_vals;
+i1regs << tocheck.i1regs;
+i2regs << tocheck.i2regs;
+p1 << getregs1.p1;
+p2 << getregs2.p2;
+@@
+
+if i1regs < i2regs &&
+   List.sort compare i1regs_vals = List.sort compare i2regs_vals
+then
+  let msg =
+    Printf.sprintf
+      "WARNING %s and %s (line %d) are identical\n"
+      i1regs i2regs (List.hd p2).line in
+  print_report p1 msg
+
+(* ---------------------------------------------------------------- *)
+
+@getdmregs1@
+identifier tocheck.i1dmregs;
+initializer list i1dmregs_vals;
+position p1;
+@@
+
+struct bq27xxx_dm_reg i1dmregs@p1[] = { i1dmregs_vals, };
+
+@getdmregs2@
+identifier tocheck.i2dmregs;
+initializer list i2dmregs_vals;
+position p2;
+@@
+
+struct bq27xxx_dm_reg i2dmregs@p2[] = { i2dmregs_vals, };
+
+@script:ocaml@
+(_,i1dmregs_vals) << getdmregs1.i1dmregs_vals;
+(_,i2dmregs_vals) << getdmregs2.i2dmregs_vals;
+i1dmregs << tocheck.i1dmregs;
+i2dmregs << tocheck.i2dmregs;
+p1 << getdmregs1.p1;
+p2 << getdmregs2.p2;
+@@
+
+if i1dmregs < i2dmregs &&
+   List.sort compare i1dmregs_vals = List.sort compare i2dmregs_vals
+then
+  let msg =
+    Printf.sprintf
+      "WARNING %s and %s (line %d) are identical\n"
+      i1dmregs i2dmregs (List.hd p2).line in
+  print_report p1 msg
+
+(* ---------------------------------------------------------------- *)
+
+@getprops1@
+identifier tocheck.i1props;
+initializer list[n1] i1props_vals;
+position p1;
+@@
+
+enum power_supply_property i1props@p1[] = { i1props_vals, };
+
+@getprops2@
+identifier tocheck.i2props;
+initializer list[n2] i2props_vals;
+position p2;
+@@
+
+enum power_supply_property i2props@p2[] = { i2props_vals, };
+
+@script:ocaml@
+(_,i1props_vals) << getprops1.i1props_vals;
+(_,i2props_vals) << getprops2.i2props_vals;
+i1props << tocheck.i1props;
+i2props << tocheck.i2props;
+p1 << getprops1.p1;
+p2 << getprops2.p2;
+@@
+
+if i1props < i2props &&
+   List.sort compare i1props_vals = List.sort compare i2props_vals
+then
+  let msg =
+    Printf.sprintf
+      "WARNING %s and %s (line %d) are identical\n"
+      i1props i2props (List.hd p2).line in
+  print_report p1 msg
index eb6bd9e4ab1abee4f1385188a2382f730432c3da..e4577089dcb9017e56c6393abf096235cd392fc5 100644 (file)
@@ -2,6 +2,7 @@
 /// and data fields
 // Confidence: High
 // Copyright: (C) 2016 Vaishali Thakkar, Oracle. GPLv2
+// Copyright: (C) 2017 Kees Cook, Google. GPLv2
 // Options: --no-includes --include-headers
 // Keywords: init_timer, setup_timer
 
@@ -10,60 +11,123 @@ virtual context
 virtual org
 virtual report
 
+// Match the common cases first to avoid Coccinelle parsing loops with
+// "... when" clauses.
+
 @match_immediate_function_data_after_init_timer
 depends on patch && !context && !org && !report@
 expression e, func, da;
 @@
 
--init_timer (&e);
-+setup_timer (&e, func, da);
+-init_timer
++setup_timer
+ ( \(&e\|e\)
++, func, da
+ );
+(
+-\(e.function\|e->function\) = func;
+-\(e.data\|e->data\) = da;
+|
+-\(e.data\|e->data\) = da;
+-\(e.function\|e->function\) = func;
+)
+
+@match_immediate_function_data_before_init_timer
+depends on patch && !context && !org && !report@
+expression e, func, da;
+@@
+
+(
+-\(e.function\|e->function\) = func;
+-\(e.data\|e->data\) = da;
+|
+-\(e.data\|e->data\) = da;
+-\(e.function\|e->function\) = func;
+)
+-init_timer
++setup_timer
+ ( \(&e\|e\)
++, func, da
+ );
+
+@match_function_and_data_after_init_timer
+depends on patch && !context && !org && !report@
+expression e, e2, e3, e4, e5, func, da;
+@@
 
+-init_timer
++setup_timer
+ ( \(&e\|e\)
++, func, da
+ );
+ ... when != func = e2
+     when != da = e3
 (
 -e.function = func;
+... when != da = e4
 -e.data = da;
 |
+-e->function = func;
+... when != da = e4
+-e->data = da;
+|
 -e.data = da;
+... when != func = e5
 -e.function = func;
+|
+-e->data = da;
+... when != func = e5
+-e->function = func;
 )
 
-@match_function_and_data_after_init_timer
+@match_function_and_data_before_init_timer
 depends on patch && !context && !org && !report@
-expression e1, e2, e3, e4, e5, a, b;
+expression e, e2, e3, e4, e5, func, da;
 @@
-
--init_timer (&e1);
-+setup_timer (&e1, a, b);
-
-... when != a = e2
-    when != b = e3
 (
--e1.function = a;
-... when != b = e4
--e1.data = b;
+-e.function = func;
+... when != da = e4
+-e.data = da;
 |
--e1.data = b;
-... when != a = e5
--e1.function = a;
+-e->function = func;
+... when != da = e4
+-e->data = da;
+|
+-e.data = da;
+... when != func = e5
+-e.function = func;
+|
+-e->data = da;
+... when != func = e5
+-e->function = func;
 )
+... when != func = e2
+    when != da = e3
+-init_timer
++setup_timer
+ ( \(&e\|e\)
++, func, da
+ );
 
 @r1 exists@
+expression t;
 identifier f;
 position p;
 @@
 
 f(...) { ... when any
-  init_timer@p(...)
+  init_timer@p(\(&t\|t\))
   ... when any
 }
 
 @r2 exists@
+expression r1.t;
 identifier g != r1.f;
-struct timer_list t;
 expression e8;
 @@
 
 g(...) { ... when any
-  t.data = e8
+  \(t.data\|t->data\) = e8
   ... when any
 }
 
@@ -77,14 +141,31 @@ p << r1.p;
 cocci.include_match(False)
 
 @r3 depends on patch && !context && !org && !report@
-expression e6, e7, c;
+expression r1.t, func, e7;
 position r1.p;
 @@
 
--init_timer@p (&e6);
-+setup_timer (&e6, c, 0UL);
-... when != c = e7
--e6.function = c;
+(
+-init_timer@p(&t);
++setup_timer(&t, func, 0UL);
+... when != func = e7
+-t.function = func;
+|
+-t.function = func;
+... when != func = e7
+-init_timer@p(&t);
++setup_timer(&t, func, 0UL);
+|
+-init_timer@p(t);
++setup_timer(t, func, 0UL);
+... when != func = e7
+-t->function = func;
+|
+-t->function = func;
+... when != func = e7
+-init_timer@p(t);
++setup_timer(t, func, 0UL);
+)
 
 // ----------------------------------------------------------------------------
 
@@ -104,11 +185,9 @@ position j0, j1, j2;
 )
 
 @match_function_and_data_after_init_timer_context
-depends on !patch &&
-!match_immediate_function_data_after_init_timer_context &&
- (context || org || report)@
+depends on !patch && (context || org || report)@
 expression a, b, e1, e2, e3, e4, e5;
-position j0, j1, j2;
+position j0 != match_immediate_function_data_after_init_timer_context.j0,j1,j2;
 @@
 
 * init_timer@j0 (&e1);
@@ -124,13 +203,12 @@ position j0, j1, j2;
 * e1@j2.function = a;
 )
 
-@r3_context depends on !patch &&
-!match_immediate_function_data_after_init_timer_context &&
-!match_function_and_data_after_init_timer_context &&
- (context || org || report)@
+@r3_context depends on !patch && (context || org || report)@
 expression c, e6, e7;
 position r1.p;
-position j0, j1;
+position j0 !=
+  {match_immediate_function_data_after_init_timer_context.j0,
+   match_function_and_data_after_init_timer_context.j0}, j1;
 @@
 
 * init_timer@j0@p (&e6);
index 873f444e7137f0fbbde99b683a382fbd93c3d472..be6f9f1abb343c07c42a696f60029d209a82df0d 100644 (file)
@@ -15,7 +15,7 @@ virtual context
 virtual org
 virtual report
 
-@r@
+@r exists@
 iterator name list_for_each_entry;
 expression x,E;
 position p1,p2;
index d0d00ef1f12ad0503113a1f0448ce75192f44506..ffe75407c5d2e44afbbe146347635c01f421609b 100644 (file)
@@ -3,10 +3,10 @@
 /// Sometimes, code after an if that is indented is actually intended to be
 /// part of the if branch.
 ///
-/// This has a high rate of false positives, because Coccinelle's column
-/// calculation does not distinguish between spaces and tabs, so code that
-/// is not visually aligned may be considered to be in the same column.
-///
+//# This has a high rate of false positives, because Coccinelle's column
+//# calculation does not distinguish between spaces and tabs, so code that
+//# is not visually aligned may be considered to be in the same column.
+//
 // Confidence: Low
 // Copyright: (C) 2010 Nicolas Palix, DIKU.  GPLv2.
 // Copyright: (C) 2010 Julia Lawall, DIKU.  GPLv2.
index 81fabf37939033eae4224f9cf9a99320e6f765cc..08de5be73693d818912a390dd123049f3ff389b8 100644 (file)
@@ -14,7 +14,19 @@ virtual report
 virtual context
 
 @r@
-constant c;
+constant c,c1;
+identifier i,i1;
+position p;
+@@
+
+(
+ c1 + c - 1
+|
+ c1@i1 +@p c@i
+)
+
+@s@
+constant r.c, r.c1;
 identifier i;
 expression e;
 @@
@@ -27,28 +39,31 @@ e & c@i
 e |= c@i
 |
 e &= c@i
+|
+e | c1@i
+|
+e & c1@i
+|
+e |= c1@i
+|
+e &= c1@i
 )
 
-@s@
-constant r.c,c1;
-identifier i1;
-position p;
+@depends on s@
+position r.p;
+constant c1,c2;
 @@
 
-(
- c1 + c - 1
-|
-*c1@i1 +@p c
-)
+* c1 +@p c2
 
-@script:python depends on org@
-p << s.p;
+@script:python depends on s && org@
+p << r.p;
 @@
 
 cocci.print_main("sum of probable bitmasks, consider |",p)
 
-@script:python depends on report@
-p << s.p;
+@script:python depends on s && report@
+p << r.p;
 @@
 
 msg = "WARNING: sum of probable bitmasks, consider |"
index 5551da2b4fe32baaea72e0ec84c1a5b024756535..f597c8007b763b45e8b091c56c2f894521366a2b 100644 (file)
@@ -10,7 +10,7 @@
 // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6.  GPLv2.
 // Copyright: (C) 2012 Gilles Muller, INRIA/LiP6.  GPLv2.
 // URL: http://coccinelle.lip6.fr/
-// Comments: Requires Coccinelle version 1.0.0-rc20 or later
+// Requires: 1.0.0
 // Options:
 
 virtual patch
index 73f9f3192b9fbf8770e6ef632723d23e8efb5b63..9ed96aefc72da9fcbe1f476727feea423aa23802 100644 (file)
@@ -50,17 +50,18 @@ rpm-pkg rpm: FORCE
        $(MAKE) clean
        $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec
        $(call cmd,src_tar,$(KERNELPATH),kernel.spec)
-       rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz
-       rm $(KERNELPATH).tar.gz kernel.spec
+       +rpmbuild $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz \
+       --define='_smp_mflags %{nil}'
 
 # binrpm-pkg
 # ---------------------------------------------------------------------------
 binrpm-pkg: FORCE
        $(MAKE) KBUILD_SRC=
        $(CONFIG_SHELL) $(MKSPEC) prebuilt > $(objtree)/binkernel.spec
-       rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
+       +rpmbuild $(RPMOPTS) --define "_builddir $(objtree)" --target \
                $(UTS_MACHINE) -bb $(objtree)/binkernel.spec
-       rm binkernel.spec
+
+clean-files += $(objtree)/*.spec
 
 # Deb target
 # ---------------------------------------------------------------------------
index 0bc87473f68f817b81640591f75f18c3b068351c..b4f0f2b3f8d2c6d495653c4fa81cbddbe8edbca8 100755 (executable)
@@ -408,9 +408,9 @@ EOF
        dpkg-source -cdebian/control -ldebian/changelog --format="3.0 (custom)" --target-format="3.0 (quilt)" \
                -b / ../${sourcename}_${version}.orig.tar.gz  ../${sourcename}_${packageversion}.debian.tar.gz
        mv ${sourcename}_${packageversion}*dsc ..
-       dpkg-genchanges > ../${sourcename}_${packageversion}_${debarch}.changes
+       dpkg-genchanges -Vkernel:debarch="${debarch}" > ../${sourcename}_${packageversion}_${debarch}.changes
 else
-       dpkg-genchanges -b > ../${sourcename}_${packageversion}_${debarch}.changes
+       dpkg-genchanges -b -Vkernel:debarch="${debarch}" > ../${sourcename}_${packageversion}_${debarch}.changes
 fi
 
 exit 0
index f47f17aae135188eae37db2178db6c9911a80023..280027fad991c1beeacc64fcc460eb6f6986d849 100755 (executable)
 #
 
 # how we were called determines which rpms we build and how we build them
-if [ "$1" = "prebuilt" ]; then
-       PREBUILT=true
+if [ "$1" = prebuilt ]; then
+       S=DEL
 else
-       PREBUILT=false
+       S=
 fi
 
-# starting to output the spec
-if [ "`grep CONFIG_DRM=y .config | cut -f2 -d\=`" = "y" ]; then
-       PROVIDES=kernel-drm
-fi
-
-PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
-__KERNELRELEASE=`echo $KERNELRELEASE | sed -e "s/-/_/g"`
-
-echo "Name: kernel"
-echo "Summary: The Linux Kernel"
-echo "Version: $__KERNELRELEASE"
-echo "Release: $(cat .version 2>/dev/null || echo 1)"
-echo "License: GPL"
-echo "Group: System Environment/Kernel"
-echo "Vendor: The Linux Community"
-echo "URL: http://www.kernel.org"
-
-if ! $PREBUILT; then
-echo "Source: kernel-$__KERNELRELEASE.tar.gz"
-fi
-
-echo "BuildRoot: %{_tmppath}/%{name}-%{PACKAGE_VERSION}-root"
-echo "Provides: $PROVIDES"
-echo "%define __spec_install_post /usr/lib/rpm/brp-compress || :"
-echo "%define debug_package %{nil}"
-echo ""
-echo "%description"
-echo "The Linux Kernel, the operating system core itself"
-echo ""
-echo "%package headers"
-echo "Summary: Header files for the Linux kernel for use by glibc"
-echo "Group: Development/System"
-echo "Obsoletes: kernel-headers"
-echo "Provides: kernel-headers = %{version}"
-echo "%description headers"
-echo "Kernel-headers includes the C header files that specify the interface"
-echo "between the Linux kernel and userspace libraries and programs.  The"
-echo "header files define structures and constants that are needed for"
-echo "building most standard programs and are also needed for rebuilding the"
-echo "glibc package."
-echo ""
-echo "%package devel"
-echo "Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel"
-echo "Group: System Environment/Kernel"
-echo "AutoReqProv: no"
-echo "%description -n kernel-devel"
-echo "This package provides kernel headers and makefiles sufficient to build modules"
-echo "against the $__KERNELRELEASE kernel package."
-echo ""
-
-if ! $PREBUILT; then
-echo "%prep"
-echo "%setup -q"
-echo ""
+if grep -q CONFIG_MODULES=y .config; then
+       M=
+else
+       M=DEL
 fi
 
-echo "%build"
-
-if ! $PREBUILT; then
-echo "make clean && make %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release}"
-echo ""
+if grep -q CONFIG_DRM=y .config; then
+       PROVIDES=kernel-drm
 fi
 
-echo "%install"
-echo 'KBUILD_IMAGE=$(make image_name)'
-echo "%ifarch ia64"
-echo 'mkdir -p $RPM_BUILD_ROOT/boot/efi $RPM_BUILD_ROOT/lib/modules'
-echo "%else"
-echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
-echo "%endif"
-
-echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{?_smp_mflags} KBUILD_SRC= modules_install'
-echo "%ifarch ia64"
-echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
-echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
-echo "%else"
-echo "%ifarch ppc64"
-echo "cp vmlinux arch/powerpc/boot"
-echo "cp arch/powerpc/boot/"'$KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
-echo "%else"
-echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
-echo "%endif"
-echo "%endif"
-
-echo 'make %{?_smp_mflags} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr KBUILD_SRC= headers_install'
-echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
-
-echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$KERNELRELEASE"
-
-echo "%ifnarch ppc64"
-echo 'bzip2 -9 --keep vmlinux'
-echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2"
-echo "%endif"
-
-if ! $PREBUILT; then
-echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/build"
-echo 'rm -f $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE/source"
-echo "mkdir -p "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE"
-echo "EXCLUDES=\"$RCS_TAR_IGNORE --exclude .tmp_versions --exclude=*vmlinux* --exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation --exclude .config.old --exclude .missing-syscalls.d\""
-echo "tar "'$EXCLUDES'" -cf- . | (cd "'$RPM_BUILD_ROOT'"/usr/src/kernels/$KERNELRELEASE;tar xvf -)"
-echo 'cd $RPM_BUILD_ROOT'"/lib/modules/$KERNELRELEASE"
-echo "ln -sf /usr/src/kernels/$KERNELRELEASE build"
-echo "ln -sf /usr/src/kernels/$KERNELRELEASE source"
-fi
+PROVIDES="$PROVIDES kernel-$KERNELRELEASE"
+__KERNELRELEASE=$(echo $KERNELRELEASE | sed -e "s/-/_/g")
+EXCLUDES="$RCS_TAR_IGNORE --exclude=.tmp_versions --exclude=*vmlinux* \
+--exclude=*.o --exclude=*.ko --exclude=*.cmd --exclude=Documentation \
+--exclude=.config.old --exclude=.missing-syscalls.d"
 
-echo ""
-echo "%clean"
-echo 'rm -rf $RPM_BUILD_ROOT'
-echo ""
-echo "%post"
-echo "if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then"
-echo "cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm"
-echo "cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm"
-echo "rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE"
-echo "/sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
-echo "rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm"
-echo "fi"
-echo ""
-echo "%preun"
-echo "if [ -x /sbin/new-kernel-pkg ]; then"
-echo "new-kernel-pkg --remove $KERNELRELEASE --rminitrd --initrdfile=/boot/initramfs-$KERNELRELEASE.img"
-echo "fi"
-echo ""
-echo "%postun"
-echo "if [ -x /sbin/update-bootloader ]; then"
-echo "/sbin/update-bootloader --remove $KERNELRELEASE"
-echo "fi"
-echo ""
-echo "%files"
-echo '%defattr (-, root, root)'
-echo "/lib/modules/$KERNELRELEASE"
-echo "%exclude /lib/modules/$KERNELRELEASE/build"
-echo "%exclude /lib/modules/$KERNELRELEASE/source"
-echo "/boot/*"
-echo ""
-echo "%files headers"
-echo '%defattr (-, root, root)'
-echo "/usr/include"
-echo ""
-if ! $PREBUILT; then
-echo "%files devel"
-echo '%defattr (-, root, root)'
-echo "/usr/src/kernels/$KERNELRELEASE"
-echo "/lib/modules/$KERNELRELEASE/build"
-echo "/lib/modules/$KERNELRELEASE/source"
-echo ""
-fi
+# We can label the here-doc lines for conditional output to the spec file
+#
+# Labels:
+#  $S: this line is enabled only when building source package
+#  $M: this line is enabled only when CONFIG_MODULES is enabled
+sed -e '/^DEL/d' -e 's/^\t*//' <<EOF
+       Name: kernel
+       Summary: The Linux Kernel
+       Version: $__KERNELRELEASE
+       Release: $(cat .version 2>/dev/null || echo 1)
+       License: GPL
+       Group: System Environment/Kernel
+       Vendor: The Linux Community
+       URL: http://www.kernel.org
+$S     Source: kernel-$__KERNELRELEASE.tar.gz
+       Provides: $PROVIDES
+       %define __spec_install_post /usr/lib/rpm/brp-compress || :
+       %define debug_package %{nil}
+
+       %description
+       The Linux Kernel, the operating system core itself
+
+       %package headers
+       Summary: Header files for the Linux kernel for use by glibc
+       Group: Development/System
+       Obsoletes: kernel-headers
+       Provides: kernel-headers = %{version}
+       %description headers
+       Kernel-headers includes the C header files that specify the interface
+       between the Linux kernel and userspace libraries and programs.  The
+       header files define structures and constants that are needed for
+       building most standard programs and are also needed for rebuilding the
+       glibc package.
+
+$S$M   %package devel
+$S$M   Summary: Development package for building kernel modules to match the $__KERNELRELEASE kernel
+$S$M   Group: System Environment/Kernel
+$S$M   AutoReqProv: no
+$S$M   %description -n kernel-devel
+$S$M   This package provides kernel headers and makefiles sufficient to build modules
+$S$M   against the $__KERNELRELEASE kernel package.
+$S$M
+$S     %prep
+$S     %setup -q
+$S
+$S     %build
+$S     make %{?_smp_mflags} KBUILD_BUILD_VERSION=%{release}
+$S
+       %install
+       mkdir -p %{buildroot}/boot
+       %ifarch ia64
+       mkdir -p %{buildroot}/boot/efi
+       cp \$(make image_name) %{buildroot}/boot/efi/vmlinuz-$KERNELRELEASE
+       ln -s efi/vmlinuz-$KERNELRELEASE %{buildroot}/boot/
+       %else
+       cp \$(make image_name) %{buildroot}/boot/vmlinuz-$KERNELRELEASE
+       %endif
+$M     make %{?_smp_mflags} INSTALL_MOD_PATH=%{buildroot} KBUILD_SRC= modules_install
+       make %{?_smp_mflags} INSTALL_HDR_PATH=%{buildroot}/usr KBUILD_SRC= headers_install
+       cp System.map %{buildroot}/boot/System.map-$KERNELRELEASE
+       cp .config %{buildroot}/boot/config-$KERNELRELEASE
+       bzip2 -9 --keep vmlinux
+       mv vmlinux.bz2 %{buildroot}/boot/vmlinux-$KERNELRELEASE.bz2
+$S$M   rm -f %{buildroot}/lib/modules/$KERNELRELEASE/build
+$S$M   rm -f %{buildroot}/lib/modules/$KERNELRELEASE/source
+$S$M   mkdir -p %{buildroot}/usr/src/kernels/$KERNELRELEASE
+$S$M   tar cf - . $EXCLUDES | tar xf - -C %{buildroot}/usr/src/kernels/$KERNELRELEASE
+$S$M   cd %{buildroot}/lib/modules/$KERNELRELEASE
+$S$M   ln -sf /usr/src/kernels/$KERNELRELEASE build
+$S$M   ln -sf /usr/src/kernels/$KERNELRELEASE source
+
+       %clean
+       rm -rf %{buildroot}
+
+       %post
+       if [ -x /sbin/installkernel -a -r /boot/vmlinuz-$KERNELRELEASE -a -r /boot/System.map-$KERNELRELEASE ]; then
+       cp /boot/vmlinuz-$KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm
+       cp /boot/System.map-$KERNELRELEASE /boot/.System.map-$KERNELRELEASE-rpm
+       rm -f /boot/vmlinuz-$KERNELRELEASE /boot/System.map-$KERNELRELEASE
+       /sbin/installkernel $KERNELRELEASE /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm
+       rm -f /boot/.vmlinuz-$KERNELRELEASE-rpm /boot/.System.map-$KERNELRELEASE-rpm
+       fi
+
+       %preun
+       if [ -x /sbin/new-kernel-pkg ]; then
+       new-kernel-pkg --remove $KERNELRELEASE --rminitrd --initrdfile=/boot/initramfs-$KERNELRELEASE.img
+       fi
+
+       %postun
+       if [ -x /sbin/update-bootloader ]; then
+       /sbin/update-bootloader --remove $KERNELRELEASE
+       fi
+
+       %files
+       %defattr (-, root, root)
+$M     /lib/modules/$KERNELRELEASE
+$M     %exclude /lib/modules/$KERNELRELEASE/build
+$M     %exclude /lib/modules/$KERNELRELEASE/source
+       /boot/*
+
+       %files headers
+       %defattr (-, root, root)
+       /usr/include
+$S$M
+$S$M   %files devel
+$S$M   %defattr (-, root, root)
+$S$M   /usr/src/kernels/$KERNELRELEASE
+$S$M   /lib/modules/$KERNELRELEASE/build
+$S$M   /lib/modules/$KERNELRELEASE/source
+EOF