From b1b76c66347a84f9d0147f8a775f0a04cf532de9 Mon Sep 17 00:00:00 2001
From: Brian Behlendorf <behlendorf1@llnl.gov>
Date: Tue, 10 Mar 2009 11:10:50 -0700
Subject: [PATCH] Build system and packaging (RPM support) (Part 1)

    An update to the build system to properly support all commonly
    used Makefile targets these include:

      make all        # Build everything
      make install    # Install everything
      make clean      # Clean up build products
      make distclean  # Clean up everything
      make dist       # Create package tarball
      make srpm       # Create package source RPM
      make rpm        # Create package binary RPMs
      make tags       # Create ctags and etags for everything

    Extra care was taken to ensure that the source RPMs are fully
    rebuildable against Fedora/RHEL/Chaos kernels.  To build binary
    RPMs from the source RPM for your system simply run:

      rpmbuild --rebuild zfs-x.y.z-1.src.rpm

    This will produce two binary RPMs with correct 'requires'
    dependencies for your kernel.  One will contain all zfs modules
    and support utilities, the other is a devel package for compiling
    additional kernel modules which are dependant on the zfs.

      zfs-x.y.z-1_<kernel version>.x86_64.rpm
      zfs-devel-x.y.2-1_<kernel version>.x86_64.rpm
---
 Makefile.am         |  61 ++++++++++++++++++++++---
 build/Makefile      |   1 -
 config/zfs-build.m4 | 103 +++++++++++++++++++----------------------
 configure.ac        |  70 ++++++++++++++--------------
 zfs.spec.in         | 109 ++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 243 insertions(+), 101 deletions(-)
 delete mode 100644 build/Makefile
 create mode 100644 zfs.spec.in

diff --git a/Makefile.am b/Makefile.am
index cb0a654082..ad729f7311 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,9 +1,56 @@
-AUTOMAKE_OPTIONS = foreign dist-zip
-EXTRA_DIST  = autogen.sh AUTHORS COPYING COPYRIGHT ChangeLog DISCLAIMER
-EXTRA_DIST += GIT META OPENSOLARIS.LICENSE README ZFS.RELEASE
-
 SUBDIRS = config doc scripts lib cmd module
 
-.PHONY: rpm
-rpms: dist-bzip2
-	rpmbuild -ta $(distdir).tar.bz2
+AUTOMAKE_OPTIONS = foreign dist-zip
+EXTRA_DIST  = autogen.sh zfs.spec.in META DISCLAIMER GIT
+EXTRA_DIST += OPENSOLARIS.LICENSE ZFS.RELEASE
+include_HEADERS = zfs_config.h
+
+distclean-local::
+	-$(RM) -R autom4te*.cache
+	-find . \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS \
+		-o -name .pc -o -name .hg -o -name .git \) -prune -o \
+		\( -name '*.orig' -o -name '*.rej' -o -name '*~' \
+		-o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
+		-o -name '.*.rej' -o -name 'aclocal.m4' -o -size 0 \
+		-o -name '*%' -o -name '.*.cmd' -o -name 'core' \
+		-o -name 'Makefile' -o -name 'Module.symvers' \
+		-o -name '.script-config' \) \
+		-type f -print | xargs $(RM)
+
+install-data-local:
+	$(INSTALL) module/Module.symvers $(DESTDIR)/$(includedir)
+
+ctags:
+	$(RM) $(top_srcdir)/tags
+	find $(top_srcdir) -name .git -prune -o -name '*.[hc]' | xargs ctags
+
+etags:
+	$(RM) $(top_srcdir)/TAGS
+	find $(top_srcdir) -name .pc -prune -o -name '*.[hc]' | xargs etags -a
+
+tags: ctags etags
+
+rpm-local:
+	mkdir -p $(rpmbuild)/TMP && \
+	mkdir -p $(rpmbuild)/BUILD && \
+	mkdir -p $(rpmbuild)/RPMS && \
+	mkdir -p $(rpmbuild)/SRPMS && \
+	mkdir -p $(rpmbuild)/SPECS && cp $(PACKAGE).spec $(rpmbuild)/SPECS && \
+	mkdir -p $(rpmbuild)/SOURCES && cp $(distdir).tar.gz $(rpmbuild)/SOURCES
+
+srpm: dist
+	rpmbuild=`mktemp -t -d $(PACKAGE)-build-$$USER-XXXXXXXX`; \
+	$(MAKE) $(AM_MAKEFLAGS) rpmbuild="$$rpmbuild" rpm-local || exit 1; \
+	/usr/bin/rpmbuild --define "_tmppath $$rpmbuild/TMP" --define "_topdir $$rpmbuild" --define "build_src_rpm 1" --define "dist %{nil}" --nodeps -bs $$rpmbuild/SPECS/$(PACKAGE).spec || exit 1; \
+	cp $$rpmbuild/SRPMS/$(distdir)-$(ZFS_META_RELEASE).src.rpm . || exit 1;\
+	$(RM) -R $$rpmbuild
+
+# Use 'make rpm LINUX_VERSION=2.x.y-z' to rebuild the source RPM
+# against any installed kernel-devel-2.x.y-z package.  This will
+# override the LINUX_VERSION detected at configure time.
+rpm: srpm
+	rpmbuild=`mktemp -t -d $(PACKAGE)-build-$$USER-XXXXXXXX`; \
+	$(MAKE) $(AM_MAKEFLAGS) rpmbuild="$$rpmbuild" rpm-local || exit 1; \
+	/usr/bin/rpmbuild --define "_tmppath $$rpmbuild/TMP" --define "_topdir $$rpmbuild" --define "dist %{nil}" --define "require_kver $(LINUX_VERSION)" --nodeps --rebuild $(distdir)-$(ZFS_META_RELEASE).src.rpm || exit 1; \
+	cp $$rpmbuild/RPMS/*/* . || exit 1; \
+	$(RM) -R $$rpmbuild
diff --git a/build/Makefile b/build/Makefile
deleted file mode 100644
index f84b8e9ccf..0000000000
--- a/build/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-m := conftest.o
diff --git a/config/zfs-build.m4 b/config/zfs-build.m4
index 8bfc05f6a4..e9b24edb61 100644
--- a/config/zfs-build.m4
+++ b/config/zfs-build.m4
@@ -88,31 +88,15 @@ AC_DEFUN([ZFS_AC_SPL], [
 
 
 	AC_MSG_CHECKING([spl source directory])
-	if test -z "$splsrc"; then
-		splbuild=
-		sourcelink=/tmp/`whoami`/spl
-		buildlink=/tmp/`whoami`/spl
-
-		if test -e $sourcelink; then
-			splsrc=`(cd $sourcelink; /bin/pwd)`
-		fi
-		if test -e $buildlink; then
-			splbuild=`(cd $buildlink; /bin/pwd)`
-		fi
-		if test -z "$splsrc"; then
-			splsrc=$splbuild
-		fi
-	fi
-
 	if test -z "$splsrc" -o -z "$splbuild"; then
-		sourcelink=/lib/modules/${ver}/source
-		buildlink=/lib/modules/${ver}/build
+		sourcelink=${LINUX}/include/spl
+		buildlink=${LINUX_OBJ}/include/spl
 
 		if test -e $sourcelink; then
-			splsrc=`(cd $sourcelink; /bin/pwd)`
+			splsrc=`readlink -f ${sourcelink}`
 		fi
 		if test -e $buildlink; then
-			splbuild=`(cd $buildlink; /bin/pwd)`
+			splbuild=`readlink -f ${buildlink}`
 		fi
 		if test -z "$splsrc"; then
 			splsrc=$splbuild
@@ -129,6 +113,22 @@ AC_DEFUN([ZFS_AC_SPL], [
 	AC_MSG_CHECKING([spl build directory])
 	AC_MSG_RESULT([$splbuild])
 
+	AC_MSG_CHECKING([spl Module.symvers])
+	if test -r $splbuild/module/Module.symvers; then
+		splsymvers=$splbuild/module/Module.symvers
+	elif test -r $kernelbuild/include/spl/Module.symvers; then
+		splsymvers=$kernelbuild/include/spl/Module.symvers
+	fi
+
+	if test -z "$splsymvers"; then
+	        AC_MSG_RESULT([Not found])
+	        AC_MSG_ERROR([
+                *** Cannot find extra Module.symvers in the spl source.
+                *** Please prepare the spl source before running this script])
+	fi
+
+	AC_MSG_RESULT([$splsymvers])
+
 	AC_MSG_CHECKING([spl source version])
 	if test -r $splbuild/spl_config.h && 
 		fgrep -q VERSION $splbuild/spl_config.h; then
@@ -148,33 +148,20 @@ AC_DEFUN([ZFS_AC_SPL], [
 
 	AC_MSG_RESULT([$splsrcver])
 
-	AC_MSG_CHECKING([spl Module.symvers])
-	if test -r $splbuild/module/Module.symvers; then
-		splsymvers=$splbuild/module/Module.symvers
-	elif test -r $kernelbuild/Module.symvers; then
-		splsymvers=$kernelbuild/Module.symvers
-	fi
-
-	if test -z "$splsymvers"; then
-	        AC_MSG_RESULT([Not found])
-	        AC_MSG_ERROR([
-                *** Cannot find extra Module.symvers in the spl source.
-                *** Please prepare the spl source before running this script])
-	fi
-
-	AC_MSG_RESULT([$splsymvers])
 	AC_SUBST(splsrc)
 	AC_SUBST(splsymvers)
 ])
 
 AC_DEFUN([ZFS_AC_LICENSE], [
 	AC_MSG_CHECKING([zfs license])
-	license=`grep MODULE_LICENSE module/zfs/zfs_ioctl.c | cut -f2 -d'"'`
-	AC_MSG_RESULT([$license])
-	if test "$license" = GPL; then
+	LICENSE=`grep MODULE_LICENSE module/zfs/zfs_ioctl.c | cut -f2 -d'"'`
+	AC_MSG_RESULT([$LICENSE])
+	if test "$LICENSE" = GPL; then
 		AC_DEFINE([HAVE_GPL_ONLY_SYMBOLS], [1],
 		          [Define to 1 if module is licensed under the GPL])
 	fi
+
+	AC_SUBST(LICENSE)
 ])
 
 AC_DEFUN([ZFS_AC_DEBUG], [
@@ -228,30 +215,34 @@ AC_DEFUN([ZFS_AC_CONFIG], [
 	MODDIR=$TOPDIR/module
 	UNAME=`uname -r | cut -d- -f1`
 
+	if test -z "$ZFS_CONFIG"; then
+		ZFS_CONFIG=all
+	fi
+
 	AC_SUBST(UNAME)
 	AC_SUBST(TOPDIR)
 	AC_SUBST(BUILDDIR)
 	AC_SUBST(LIBDIR)
 	AC_SUBST(CMDDIR)
 	AC_SUBST(MODDIR)
-	AC_SUBST(UNAME)
+	AC_SUBST(ZFS_CONFIG)
 
 	AC_ARG_WITH([zfs-config],
 		AS_HELP_STRING([--with-config=CONFIG],
 		[Config file 'kernel|user|all']),
-		[zfsconfig="$withval"])
+		[ZFS_CONFIG="$withval"])
 
 	AC_MSG_CHECKING([zfs config])
-	AC_MSG_RESULT([$zfsconfig]);
+	AC_MSG_RESULT([$ZFS_CONFIG]);
 
-	case "$zfsconfig" in
+	case "$ZFS_CONFIG" in
 		kernel) ZFS_AC_CONFIG_KERNEL ;;
 		user)	ZFS_AC_CONFIG_USER   ;;
 		all)    ZFS_AC_CONFIG_KERNEL
 			ZFS_AC_CONFIG_USER   ;;
 		*)
 		AC_MSG_RESULT([Error!])
-		AC_MSG_ERROR([Bad value "$zfsconfig" for --with-config,
+		AC_MSG_ERROR([Bad value "$ZFS_CONFIG" for --with-config,
 		              user kernel|user|all]) ;;
 	esac
 
@@ -287,15 +278,15 @@ dnl #
 dnl # ZFS_LINUX_COMPILE_IFELSE / like AC_COMPILE_IFELSE
 dnl #
 AC_DEFUN([ZFS_LINUX_COMPILE_IFELSE], [
-m4_ifvaln([$1], [ZFS_LINUX_CONFTEST([$1])])dnl
-rm -f build/conftest.o build/conftest.mod.c build/conftest.ko build/Makefile
-echo "obj-m := conftest.o" >build/Makefile
-dnl AS_IF([AC_TRY_COMMAND(cp conftest.c build && make [$2] CC="$CC" -f $PWD/build/Makefile LINUXINCLUDE="-Iinclude -include include/linux/autoconf.h" -o tmp_include_depends -o scripts -o include/config/MARKER -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM SUBDIRS=$PWD/build) >/dev/null && AC_TRY_COMMAND([$3])],
-AS_IF([AC_TRY_COMMAND(cp conftest.c build && make [$2] CC="$CC" LINUXINCLUDE="-Iinclude -include include/linux/autoconf.h" -o tmp_include_depends -o scripts -o include/config/MARKER -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build) >/dev/null && AC_TRY_COMMAND([$3])],
-        [$4],
-        [_AC_MSG_LOG_CONFTEST
-m4_ifvaln([$5],[$5])dnl])dnl
-rm -f build/conftest.o build/conftest.mod.c build/conftest.mod.o build/conftest.ko m4_ifval([$1], [build/conftest.c conftest.c])[]dnl
+	m4_ifvaln([$1], [ZFS_LINUX_CONFTEST([$1])])
+	rm -Rf build && mkdir -p build
+	echo "obj-m := conftest.o" >build/Makefile
+	AS_IF(
+		[AC_TRY_COMMAND(cp conftest.c build && make [$2] CC="$CC" LINUXINCLUDE="-Iinclude -Iinclude2 -I$LINUX/include -include include/linux/autoconf.h" -o tmp_include_depends -o scripts -o include/config/MARKER -C $LINUX_OBJ EXTRA_CFLAGS="-Werror-implicit-function-declaration $EXTRA_KCFLAGS" $ARCH_UM M=$PWD/build) >/dev/null && AC_TRY_COMMAND([$3])],
+		[$4],
+		[_AC_MSG_LOG_CONFTEST m4_ifvaln([$5],[$5])]
+	)
+	rm -Rf build
 ])
 
 dnl #
@@ -303,10 +294,10 @@ dnl # ZFS_LINUX_TRY_COMPILE like AC_TRY_COMPILE
 dnl #
 AC_DEFUN([ZFS_LINUX_TRY_COMPILE],
 	[ZFS_LINUX_COMPILE_IFELSE(
-        [AC_LANG_SOURCE([ZFS_LANG_PROGRAM([[$1]], [[$2]])])],
-        [modules],
-        [test -s build/conftest.o],
-        [$3], [$4])
+	[AC_LANG_SOURCE([ZFS_LANG_PROGRAM([[$1]], [[$2]])])],
+	[modules],
+	[test -s build/conftest.o],
+	[$3], [$4])
 ])
 
 dnl #
diff --git a/configure.ac b/configure.ac
index bdd98ed4d2..b05d31a1b8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,34 +1,34 @@
-#
-# This file is part of the ZFS Linux port.
-#
-# Copyright (c) 2008 Lawrence Livermore National Security, LLC.
-# Produced at Lawrence Livermore National Laboratory
-# Written by:
-#         Brian Behlendorf <behlendorf1@llnl.gov>,
-#         Herb Wartens <wartens2@llnl.gov>,
-#         Jim Garlick <garlick@llnl.gov>
-# LLNL-CODE-403049
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
+/*
+ * This file is part of the ZFS Linux port.
+ *
+ * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
+ * Produced at Lawrence Livermore National Laboratory
+ * Written by:
+ *         Brian Behlendorf <behlendorf1@llnl.gov>,
+ *         Herb Wartens <wartens2@llnl.gov>,
+ *         Jim Garlick <garlick@llnl.gov>
+ * LLNL-CODE-403049
+ *
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
 
 AC_INIT
 AC_LANG(C)
@@ -44,12 +44,6 @@ AC_PROG_CC
 AC_PROG_LIBTOOL
 AM_PROG_AS
 
-zfsconfig=all
-kernelsrc=
-kernelbuild=
-splsrc=
-splbuild=
-
 ZFS_AC_KERNEL
 ZFS_AC_SPL
 ZFS_AC_LICENSE
@@ -92,5 +86,7 @@ AC_CONFIG_FILES([
 	module/zfs/Makefile
 	scripts/Makefile
 	scripts/zpool-config/Makefile
+	zfs.spec
 ])
+
 AC_OUTPUT
diff --git a/zfs.spec.in b/zfs.spec.in
new file mode 100644
index 0000000000..f4e598c127
--- /dev/null
+++ b/zfs.spec.in
@@ -0,0 +1,109 @@
+# The following block is used to allow the source RPM to be rebuilt 
+# against arbitrary kernels.  It ensure the release name is correct
+# and the proper build/install requires are set.
+%if 0%{?require_kver:1}
+%define kver %{require_kver}
+%else
+%define _kdir %((echo X; ls -1d /usr/src/kernels/* /usr/src/linux-* 2>/dev/null)|sed -e 's/linux-//' | tail -1)
+%define kver %(basename %{_kdir})
+%endif
+
+# Each distro has its own kernel package naming convention.
+%if 0%{?ch4}
+%define kstr chaos-kernel
+%define kdev chaos-kernel-devel
+%define kdir /usr/src/kernels/%{kver}
+%else
+%define kstr kernel
+%define kdev kernel-devel
+%define kdir /usr/src/kernels/%{kver}
+%endif
+
+%define debug_package %{nil}
+
+# The kernel version should only be appended to a binary RPM.
+# When building a source RPM it must be kernel version agnostic.
+%define name     @PACKAGE@
+%define version  @VERSION@
+
+%if %{?build_src_rpm:1}0
+%define release  @ZFS_META_RELEASE@
+%else
+%define release  @ZFS_META_RELEASE@_%(echo %{kver} | sed -e 's/-/_/g')
+%endif
+
+%if 0%{?require_kver:1}
+%define k_buildrequires   %{kdev}=%{kver}
+%define spl_buildrequires spl-devel>=@VERSION@
+%else
+%define k_buildrequires   %{kdev}
+%define spl_buildrequires spl-devel
+%endif
+
+Summary:         ZFS File System
+Group:           Utilities/System
+Name:            %{name}
+Version:         %{version}
+Release:         %{release}
+License:         @LICENSE@
+URL:             git://eris.llnl.gov/zfs.git
+BuildRoot:       %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n)
+Source:          %{name}-%{version}.tar.gz
+Requires:        %{kstr} = %{kver}
+Requires:        spl >= @VERSION@
+BuildRequires:   %{k_buildrequires}
+BuildRequires:   %{spl_buildrequires}
+
+%description
+The %{name} package contains kernel modules and support utilities for
+the %{name} file system.
+
+%package devel
+Summary:         ZFS File System Headers and Symbols
+Group:           Development/Libraries
+Requires:        %{kstr} = %{kver}
+Requires:        spl >= @VERSION@
+BuildRequires:   %{k_buildrequires}
+BuildRequires:   %{spl_buildrequires}
+
+%description devel
+The %{name}-devel package contains the header files and Module.symvers
+symbols needed for building additional modules which use %{name}.
+
+%prep
+%setup
+%build
+%configure --includedir=%{kdir}/include/zfs --with-linux=%{kdir}
+make
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make DESTDIR=$RPM_BUILD_ROOT install
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-, root, root)
+%doc AUTHORS ChangeLog COPYING COPYRIGHT DISCLAIMER GIT
+%doc OPENSOLARIS.LICENSE README TODO ZFS.RELEASE
+%{_sbindir}/*
+/lib/modules/*
+
+%files devel
+%defattr(-,root,root)
+%{kdir}/include/zfs/*
+
+%post
+if [ -f /boot/System.map-%{kver} ]; then
+	depmod -ae -F /boot/System.map-%{kver} %{kver} || exit 0
+else
+	depmod -ae %{kver} || exit 0
+fi
+
+%postun
+if [ -f /boot/System.map-%{kver} ]; then
+	depmod -ae -F /boot/System.map-%{kver} %{kver} || exit 0
+else
+	depmod -ae %{kver} || exit 0
+fi