diff --git a/COPYING b/COPYING
new file mode 100644
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Setup.lhs b/Setup.lhs
new file mode 100644
--- /dev/null
+++ b/Setup.lhs
@@ -0,0 +1,8 @@
+#!/usr/bin/env runghc
+
+> module Main where
+
+> import Distribution.Simple
+
+> main :: IO ()
+> main = defaultMain
diff --git a/cabal-rpm.cabal b/cabal-rpm.cabal
new file mode 100644
--- /dev/null
+++ b/cabal-rpm.cabal
@@ -0,0 +1,26 @@
+Name: cabal-rpm
+Version: 0.2
+License: GPL
+License-File: COPYING
+Author: Bryan O'Sullivan <bos@serpentine.com>
+Maintainer: Bryan O'Sullivan <bos@serpentine.com>
+Copyright: 2007 Bryan O'Sullivan <bos@serpentine.com>
+Homepage: http://www.serpentine.com/software/cabal-rpm/
+Stability: Experimental
+Category: Distribution
+Build-type: Simple
+Build-depends: base, Cabal >= 1.1.7, filepath, time >= 1.1, unix
+Synopsis: RPM package builder for Haskell Cabal source packages.
+Description:
+  This package turns Haskell Cabal source packages into source and
+  binary RPM packages.
+
+Executable: cabal-rpm
+Main-Is: CabalRpm.hs
+Other-Modules:
+    Distribution.Package.Rpm,
+    Distribution.Package.Rpm.Main,
+    Distribution.Package.Rpm.Setup
+Hs-Source-Dirs: src
+Extensions: CPP
+GHC-options: -fwarn-missing-signatures
diff --git a/src/CabalRpm.hs b/src/CabalRpm.hs
new file mode 100644
--- /dev/null
+++ b/src/CabalRpm.hs
@@ -0,0 +1,20 @@
+-- |
+-- Module      :  CabalRpm
+-- Copyright   :  Bryan O'Sullivan 2007
+--
+-- Maintainer  :  Bryan O'Sullivan <bos@serpentine.com>
+-- Stability   :  alpha
+-- Portability :  portable
+--
+-- Explanation: Main entry point for building RPM packages.
+
+-- This software may be used and distributed according to the terms of
+-- the GNU General Public License, incorporated herein by reference.
+
+module Main where
+
+import qualified Distribution.Package.Rpm.Main as Rpm
+
+main :: IO ()
+
+main = Rpm.main
diff --git a/src/Distribution/Package/Rpm.hs b/src/Distribution/Package/Rpm.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Package/Rpm.hs
@@ -0,0 +1,640 @@
+-- |
+-- Module      :  Distribution.Package.Rpm
+-- Copyright   :  Bryan O'Sullivan 2007
+--
+-- Maintainer  :  Bryan O'Sullivan <bos@serpentine.com>
+-- Stability   :  alpha
+-- Portability :  portable
+--
+-- Explanation: Support for building RPM packages.  Can also generate
+-- an RPM spec file if you need a basic one to hand-customize.
+
+-- This software may be used and distributed according to the terms of
+-- the GNU General Public License, incorporated herein by reference.
+
+module Distribution.Package.Rpm (
+      createSpecFile
+    , rpm
+    , rpmBuild
+    ) where
+
+import Control.Exception (bracket)
+import Control.Monad (filterM, liftM, mapM, when, unless)
+import Data.Char (toLower)
+import Data.List (find, intersperse, isPrefixOf, sort)
+import Data.Maybe
+import Data.Time.Clock (UTCTime, getCurrentTime)
+import Data.Time.Format (formatTime)
+import Data.Version (Version(..), showVersion)
+import System.Cmd (system)
+import System.Directory (canonicalizePath, createDirectoryIfMissing,
+                         doesDirectoryExist, doesFileExist,
+                         getDirectoryContents)
+import System.Environment (getProgName)
+import System.Exit (ExitCode(..))
+import System.IO
+import System.Locale (defaultTimeLocale)
+import System.Process (runInteractiveCommand, waitForProcess)
+
+import System.FilePath ((</>))
+import Distribution.Compiler (CompilerFlavor(..), Compiler(..),
+                              compilerVersion)
+import Distribution.License
+import Distribution.Package (PackageIdentifier(..))
+import Distribution.PreProcess (knownSuffixHandlers)
+import Distribution.Simple.Configure (configCompiler)
+import Distribution.Simple.LocalBuildInfo (distPref)
+import Distribution.Simple.SrcDist (createArchive, prepareTree, tarBallName)
+import Distribution.Simple.Utils (copyDirectoryRecursiveVerbose,
+                                  copyFileVerbose, die, warn)
+import Distribution.PackageDescription (BuildInfo(..), Library(..),
+                                        PackageDescription(..), exeName,
+                                        hasLibs, setupMessage, withExe,
+                                        withLib)
+import Distribution.Verbosity (Verbosity(..))
+import Distribution.Version (Dependency(..), VersionRange(..), withinRange)
+import Distribution.Package.Rpm.Setup (RpmFlags(..))
+import System.Posix.Files (setFileCreationMask)
+
+rpm :: PackageDescription       -- ^info from the .cabal file
+    -> RpmFlags                 -- ^rpm flags
+    -> IO ()
+
+rpm pkgDesc flags = do
+    case rpmCompiler flags of
+      Just GHC -> return ()
+      Just c -> die ("the " ++ show c ++ " compiler is not yet supported")
+    if rpmGenSpec flags
+      then do
+        (name, extraDocs) <- createSpecFile False pkgDesc flags "."
+        putStrLn $ "Spec file created: " ++ name
+        when ((not . null) extraDocs) $ do
+            putStrLn "NOTE: docs packaged, but not in .cabal file:"
+            mapM_ putStrLn $ sort extraDocs
+        return ()
+      else rpmBuild pkgDesc flags
+
+-- | Copy a file or directory (recursively, in the latter case) to the
+-- same name in the target directory.  Arguments flipped from the
+-- conventional order.
+
+copyTo :: Verbosity -> FilePath -> FilePath -> IO ()
+
+copyTo verbose dest src = do
+    isFile <- doesFileExist src
+    let destDir = dest </> src
+    if isFile
+      then copyFileVerbose verbose src destDir
+      else copyDirectoryRecursiveVerbose verbose src destDir
+
+autoreconf :: Verbosity -> PackageDescription -> IO ()
+
+autoreconf verbose pkgDesc = do
+    ac <- doesFileExist "configure.ac"
+    when ac $ do
+        c <- doesFileExist "configure"
+        when (not c) $ do
+            setupMessage verbose "Running autoreconf" pkgDesc
+            ret <- system "autoreconf"
+            case ret of
+              ExitSuccess -> return ()
+              ExitFailure n -> die ("autoreconf failed with status " ++ show n)
+
+rpmBuild :: PackageDescription
+         -> RpmFlags
+         -> IO ()
+
+rpmBuild pkgDesc flags = do
+    tgtPfx <- canonicalizePath (maybe distPref id $ rpmTopDir flags)
+    let verbose = rpmVerbosity flags
+        tmpDir = tgtPfx </> "src"
+    flip mapM_ ["BUILD", "RPMS", "SOURCES", "SPECS", "SRPMS"] $ \ subDir -> do
+      createDirectoryIfMissing True (tgtPfx </> subDir)
+    let specsDir = tgtPfx </> "SPECS"
+    bracket (setFileCreationMask 0o022) setFileCreationMask $ \ _ -> do
+      autoreconf verbose pkgDesc
+      (specFile, extraDocs) <- createSpecFile True pkgDesc flags specsDir
+      tree <- prepareTree pkgDesc verbose Nothing False tmpDir
+              knownSuffixHandlers 0
+      mapM_ (copyTo verbose tree) extraDocs
+      tarball <- createArchive pkgDesc verbose Nothing tmpDir
+                 (tgtPfx </> "SOURCES")
+      ret <- system ("rpmbuild -ba --define \"_topdir " ++ tgtPfx ++ "\" " ++
+                     specFile)
+      case ret of
+        ExitSuccess -> return ()
+        ExitFailure n -> die ("rpmbuild failed with status " ++ show n)
+
+defaultRelease :: UTCTime -> IO String
+
+defaultRelease now = do
+    darcsRepo <- doesDirectoryExist "_darcs"
+    return $ if darcsRepo
+               then formatTime defaultTimeLocale "0.%Y%m%d" now
+               else "1"
+
+rstrip :: (Char -> Bool) -> String -> String
+
+rstrip p = reverse . dropWhile p . reverse
+
+createSpecFile :: Bool                -- ^whether to forcibly create file
+               -> PackageDescription  -- ^info from the .cabal file
+               -> RpmFlags            -- ^rpm flags
+               -> FilePath            -- ^directory in which to create file
+               -> IO (FilePath, [FilePath])
+
+createSpecFile force pkgDesc flags tgtPfx = do
+    compiler <- configCompiler (rpmCompiler flags) Nothing Nothing
+                (rpmVerbosity flags)
+    now <- getCurrentTime
+    defRelease <- defaultRelease now
+    let pkg = package pkgDesc
+        verbose = rpmVerbosity flags
+        origName = pkgName pkg
+        name = maybe (map toLower origName) id (rpmName flags)
+        version = maybe ((showVersion . pkgVersion) pkg) id (rpmVersion flags)
+        release = maybe defRelease id (rpmRelease flags)
+        specPath = tgtPfx </> name ++ ".spec"
+        group = "Development/Languages"
+        buildRoot = "%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)"
+        cmplrVersion = compilerVersion compiler
+        doHaddock = rpmHaddock flags && hasLibs pkgDesc
+        (cmplr, runner) = case compilerFlavor compiler of
+             GHC -> ("ghc", "runghc")
+             Hugs -> ("hugs", "runhugs")
+             JHC -> ("jhc", "runjhc")
+             NHC -> ("nhc", "runnhc")
+             (OtherCompiler s) -> (s, "run" ++ s)
+    unless force $ do
+        specAlreadyExists <- doesFileExist specPath
+        when specAlreadyExists $
+            die $ "spec file already exists: " ++ specPath
+    h <- openFile specPath WriteMode
+    buildReq <- showBuildReq verbose doHaddock compiler pkgDesc
+    runtimeReq <- showRuntimeReq verbose compiler pkgDesc
+    progName <- getProgName
+    let putHdr hdr val = hPutStrLn h (hdr ++ ": " ++ val)
+        putHdr_ hdr val = when (not $ null val) $
+                              hPutStrLn h (hdr ++ ": " ++ val)
+        putHdrD hdr val dfl = hPutStrLn h (hdr ++ ": " ++
+                                           if null val then dfl else val)
+        putNewline = hPutStrLn h ""
+        put s = hPutStrLn h s
+        putDef v s = put $ "%define " ++ v ++ ' ' : s
+        putSetup s = put $ runner ++ " Setup " ++ s
+        date = formatTime defaultTimeLocale "%a %b %d %Y" now
+    putDef "hsc_name" cmplr
+    putDef "hsc_version" $ showVersion cmplrVersion
+    putDef "hsc_namever" $ compilerNameVersion compiler
+    putDef "pkg_name" origName
+    putDef "pkg_libdir" "%{_libdir}/%{hsc_name}-%{hsc_version}/%{pkg_name}-%{version}"
+    putNewline
+
+    putHdr "Name" name
+    putHdr "Version" version
+    putHdr "Release" $ release ++ "%{?dist}"
+    putHdr "License" $ (showLicense . license) pkgDesc
+    putHdr "Group" group
+    putHdr_ "URL" $ homepage pkgDesc
+    putHdr "Source" $ tarBallName pkgDesc
+    -- Some packages conflate the synopsis and description fields.  Ugh.
+    let syn = synopsis pkgDesc
+        syn' = (head . lines) syn
+        synTooLong = syn /= syn'
+        summary = if synTooLong
+                  then syn' ++ " [...]"
+                  else rstrip (== '.') syn'
+    when synTooLong $
+        warn verbose "The synopsis for this package spans multiple lines."
+    putHdrD "Summary" summary "This package has no summary"
+    putHdr "BuildRoot" buildRoot
+    putHdr "BuildRequires" buildReq
+    -- External libraries incur both build-time and runtime
+    -- dependencies.  The latter only need to be made explicit for the
+    -- built library, as RPM is smart enough to ferret out good
+    -- dependencies for binaries.
+    extDeps <- withLib pkgDesc [] (findLibDeps .libBuildInfo)
+    let extraReq = concat $ intersperse ", " extDeps
+    putHdr_ "BuildRequires" extraReq
+    putNewline
+    putNewline
+
+    let putDesc = do
+        put $ if (null . description) pkgDesc
+              then if synTooLong
+                   then syn
+                   else "This package does not have a description."
+              else description pkgDesc
+    put "%description"
+    putDesc
+    putNewline
+    putNewline
+
+    {- Compiler-specific library data goes into a package of its own.<
+
+       Unlike a library for a traditional language, the library
+       packagen depends on the compiler, because when installed, it
+       has to register itself with the compiler's own package
+       management system. -}
+
+    withLib pkgDesc () $ \_ -> do
+        put "%package -n %{hsc_namever}-%{name}"
+        putHdrD "Summary" summary "This library package has no summary"
+        putHdr "Group" "Development/Libraries"
+        putHdr "Requires" "%{hsc_name} = %{hsc_version}"
+        putHdr_ "Requires" extraReq
+        putHdr_ "Requires" runtimeReq
+        putHdr "Provides" "%{pkg_name}-%{hsc_namever} = %{version}"
+        putNewline
+        putNewline
+
+        put "%description -n %{hsc_namever}-%{name}"
+        putDesc
+        putNewline
+        put "This package contains libraries for %{hsc_name} %{hsc_version}."
+        putNewline
+        putNewline
+
+    when (rpmLibProf flags) $ do
+        put "%package -n %{hsc_namever}-%{name}-prof"
+        putHdr "Summary" "Profiling libraries for %{hsc_namever}-%{name}"
+        putHdr "Group" "Development/Libraries"
+        putHdr "Requires" "%{hsc_namever}-%{name} = %{version}"
+        putHdr "Provides" "%{pkg_name}-%{hsc_namever}-prof = %{version}"
+        putNewline
+        putNewline
+
+        put "%description -n %{hsc_namever}-%{name}-prof"
+        putDesc
+        putNewline
+        put "This package contains profiling libraries for %{hsc_name} %{hsc_version}."
+        putNewline
+        putNewline
+
+    put "%prep"
+    put $ "%setup -q -n %{pkg_name}-%{version}"
+    putNewline
+    putNewline
+
+    put "%build"
+    put "if [ -f configure.ac -a ! -f configure ]; then autoreconf; fi"
+    putSetup ("configure --prefix=%{_prefix} --libdir=%{_libdir} " ++
+              "--libsubdir='$compiler/$pkgid' " ++
+              (if (rpmLibProf flags) then "--enable" else "--disable") ++
+              "-library-profiling --" ++ cmplr)
+    withLib pkgDesc () $ \_ -> do
+        hPutStr h "if "
+        putSetup "makefile -f cabal-rpm.mk"
+        put "then"
+        put "    make -f cabal-rpm.mk %{_smp_mflags} || :"
+        put "fi"
+    putSetup "build"
+    withLib pkgDesc () $ \_ -> do
+        when doHaddock $
+            putSetup "haddock || :"
+        putSetup "register --gen-script"
+        putSetup "unregister --gen-script"
+    putNewline
+    putNewline
+
+    put "%install"
+    put "rm -rf ${RPM_BUILD_ROOT}"
+    putSetup "copy --destdir=${RPM_BUILD_ROOT}"
+    withLib pkgDesc () $ \_ -> do
+        put "install -m 755 register.sh unregister.sh ${RPM_BUILD_ROOT}%{pkg_libdir}"
+        put "cd ${RPM_BUILD_ROOT}"
+        put "echo '%defattr(-,root,root,-)' > %{_builddir}/%{?buildsubdir}/%{name}-files.prof"
+        put "find .%{pkg_libdir} \\( -name '*_p.a' -o -name '*.p_hi' \\) | sed s/^.// >> %{_builddir}/%{?buildsubdir}/%{name}-files.prof"
+        put "echo '%defattr(-,root,root,-)' > %{_builddir}/%{?buildsubdir}/%{name}-files.nonprof"
+        put "find .%{pkg_libdir} ! \\( -name '*_p.a' -o -name '*.p_hi' \\) | sed s/^.// >> %{_builddir}/%{?buildsubdir}/%{name}-files.nonprof"
+        put "sed 's,^/,%exclude /,' %{_builddir}/%{?buildsubdir}/%{name}-files.prof >> %{_builddir}/%{?buildsubdir}/%{name}-files.nonprof"
+    put "rm -rf ${RPM_BUILD_ROOT}/%{_datadir}/%{pkg_name}-%{version}/doc"
+    putNewline
+    putNewline
+
+    put "%clean"
+    put "rm -rf ${RPM_BUILD_ROOT}"
+    putNewline
+    putNewline
+
+    docs <- findDocs pkgDesc
+    withLib pkgDesc () $ \_ -> do
+        {- If we're upgrading to a library with the same Cabal
+           name+version as the currently installed library (i.e. we've
+           just bumped the release number), we need to unregister the
+           old library first, so that the register script in %post may
+           succeed.
+
+           Note that this command runs *before* the new package's
+           files are installed, and thus will execute the *previous*
+           version's unregister script, if the script exists in the
+           same location as the about-to-be-installed library's
+           script. -}
+
+        put "%pre -n %{hsc_namever}-%{name}"
+        put "[ \"$1\" = 2 ] && %{pkg_libdir}/unregister.sh >&/dev/null || :"
+        putNewline
+        putNewline
+
+        put "%post -n %{hsc_namever}-%{name}"
+        put "%{pkg_libdir}/register.sh >&/dev/null"
+        putNewline
+        putNewline
+
+        {- We must unregister an old version during an upgrade as
+           well as during a normal removal, otherwise the Haskell
+           runtime's package system will be left with a phantom record
+           for a package it can no longer use. -}
+
+        put "%preun -n %{hsc_namever}-%{name}"
+        put "%{pkg_libdir}/unregister.sh >&/dev/null"
+        putNewline
+        putNewline
+
+        {- If we're upgrading, the %preun step may have unregistered
+           the *new* version of the library (if it had an identical
+           Cabal name+version, even though the RPM release differs);
+           therefore, we must attempt to re-register it. -}
+
+        put "%postun -n %{hsc_namever}-%{name}"
+        put "[ \"$1\" = 1 ] && %{pkg_libdir}/register.sh >& /dev/null || :"
+        putNewline
+        putNewline
+
+        put "%files -n %{hsc_namever}-%{name} -f %{name}-files.nonprof"
+        when doHaddock $
+            put "%doc dist/doc/html"
+        when ((not . null) docs) $
+            put $ "%doc " ++ concat (intersperse " " docs)
+        putNewline
+        putNewline
+
+        when (rpmLibProf flags) $ do
+            put "%files -n %{hsc_namever}-%{name}-prof -f %{name}-files.prof"
+            putNewline
+            putNewline
+
+    put "%files"
+    put "%defattr(-,root,root,-)"
+    withExe pkgDesc $ \exe -> put $ "%{_bindir}/" ++ exeName exe
+    when ((not . null . dataFiles) pkgDesc) $
+        put "%{_datadir}/%{pkg_name}-%{version}"
+
+    -- Add the license file to the main package only if it wouldn't
+    -- otherwise be empty.
+    when ((not . null . licenseFile) pkgDesc &&
+          ((not . null . executables) pkgDesc ||
+           (not . null . dataFiles) pkgDesc)) $
+        put $ "%doc " ++ licenseFile pkgDesc
+    putNewline
+    putNewline
+
+    put "%changelog"
+    put ("* " ++ date ++ " cabal-rpm <cabal-devel@haskell.org> - " ++
+         version ++ "-" ++ release)
+    put "- spec file autogenerated by cabal-rpm"
+    hClose h
+    return (specPath, filter (`notElem` (extraSrcFiles pkgDesc)) docs)
+
+findDocs :: PackageDescription -> IO [FilePath]
+
+findDocs pkgDesc = do
+    contents <- getDirectoryContents "."
+    let docs = filter likely contents
+    return $ if (null . licenseFile) pkgDesc
+             then docs
+             else let license = licenseFile pkgDesc
+                  in license : filter (/= license) docs
+  where names = ["author", "copying", "doc", "example", "licence", "license",
+                 "readme", "todo"]
+        likely name = let lowerName = map toLower name
+                      in any (`isPrefixOf` lowerName) names
+
+-- | Take a Haskell package name, and turn it into a "virtual package"
+-- that encodes the compiler name and version used.
+
+virtualPackage :: Compiler -> String -> String
+virtualPackage compiler name = name ++ '-' : compilerNameVersion compiler
+
+compilerNameVersion :: Compiler -> String
+compilerNameVersion (Compiler flavour (PackageIdentifier _ version) _ _ _) = name ++ squishedVersion
+    where name = case flavour of
+                 GHC -> "ghc"
+                 Hugs -> "hugs"
+                 JHC -> "jhc"
+                 NHC -> "nhc"
+          squishedVersion = (concat . map show . versionBranch) version
+
+-- | Convert from license to RPM-friendly description.  The strings are
+-- taken from TagsCheck.py in the rpmlint distribution.
+
+showLicense :: License -> String
+showLicense GPL = "GPL"
+showLicense LGPL = "LGPL"
+showLicense BSD3 = "BSD"
+showLicense BSD4 = "BSD-like"
+showLicense PublicDomain = "Public Domain"
+showLicense AllRightsReserved = "Proprietary"
+showLicense OtherLicense = "Non-distributable"
+
+-- | Determine whether a specific version of a Haskell package is "built
+-- into" this particular version of the given compiler.
+
+isBuiltIn :: CompilerFlavor
+        -> Version
+        -> Dependency
+        -> Bool
+isBuiltIn cn cv (Dependency pkg version) = maybe False checkVersion $ do
+    (_, _, cb) <- find (\(n, v, _) -> (n,v) == (cn,cv)) builtIns
+    (_, pv) <- find (\(pn, _) -> pn == pkg) cb
+    return pv
+  where checkVersion = flip withinRange version
+        builtIns = [(GHC, Version [6,6,1] [], ghc661BuiltIns),
+                    (GHC, Version [6,6] [], ghc66BuiltIns)]
+        v n x = (n, Version x [])
+        ghc661BuiltIns = [
+            v "base" [2,1,1],
+            v "Cabal" [1,1,6,2],
+            v "cgi" [3001,1,1],
+            v "fgl" [5,4,1],
+            v "filepath" [1,0],
+            v "ghc" [6,6,1],
+            v "GLUT" [2,1,1],
+            v "haskell98" [1,0],
+            v "haskell-src" [1,0,1],
+            v "HGL" [3,1,1],
+            v "html" [1,0,1],
+            v "HUnit" [1,1,1],
+            v "mtl" [1,0,1],
+            v "network" [2,0,1],
+            v "OpenAL" [1,3,1],
+            v "OpenGL" [2,2,1],
+            v "parsec" [2,0],
+            v "QuickCheck" [1,0,1],
+            v "readline" [1,0],
+            v "regex-base" [0,72],
+            v "regex-compat" [0,71],
+            v "regex-posix" [0,71],
+            v "rts" [1,0],
+            v "stm" [2,0],
+            v "template-haskell" [2,1],
+            v "time" [1,1,1],
+            v "unix" [2,1],
+            v "X11" [1,2,1],
+            v "xhtml" [3000,0,2]
+                         ]
+        ghc66BuiltIns = [
+            v "base" [2,0],
+            v "Cabal" [1,1,6],
+            v "cgi" [2006,9,6],
+            v "fgl" [5,2],
+            v "ghc" [6,6],
+            v "GLUT" [2,0],
+            v "haskell98" [1,0],
+            v "haskell-src" [1,0],
+            v "HGL" [3,1],
+            v "html" [1,0],
+            v "HTTP" [2006,7,7],
+            v "HUnit" [1,1],
+            v "mtl" [1,0],
+            v "network" [2,0],
+            v "OpenAL" [1,3],
+            v "OpenGL" [2,1],
+            v "parsec" [2,0],
+            v "QuickCheck" [1,0],
+            v "readline" [1,0],
+            v "regex-base" [0,71],
+            v "regex-compat" [0,71],
+            v "regex-posix" [0,71],
+            v "rts" [1,0],
+            v "stm" [2,0],
+            v "template-haskell" [2,0],
+            v "time" [1,0],
+            v "unix" [1,0],
+            v "X11" [1,1],
+            v "xhtml" [2006,9,13]
+                        ]
+
+-- | Generate a string expressing runtime dependencies, but only
+-- on package/version pairs not already "built into" a compiler
+-- distribution.
+
+showRuntimeReq :: Verbosity -> Compiler -> PackageDescription -> IO String
+
+showRuntimeReq verbose c@(Compiler cFlav (PackageIdentifier _ cVersion) _ _ _)
+               pkgDesc = do
+    let externalDeps = filter (not . isBuiltIn cFlav cVersion)
+                       (buildDepends pkgDesc)
+    clauses <- mapM (showRpmReq verbose (virtualPackage c)) externalDeps
+    return $ (concat . intersperse ", " . concat) clauses
+
+-- | Generate a string expressing package build dependencies, but only
+-- on package/version pairs not already "built into" a compiler
+-- distribution.
+
+showBuildReq :: Verbosity -> Bool -> Compiler -> PackageDescription
+             -> IO String
+
+showBuildReq verbose haddock
+             c@(Compiler cFlav (PackageIdentifier _ cVersion) _ _ _) pkgDesc =
+  do
+    cPkg <- case cFlav of
+              GHC -> return "ghc"
+              Hugs -> return "hugs98"
+              _ -> die $ "unknown compiler " ++ show cFlav
+    let myDeps = [Dependency cPkg (ThisVersion cVersion)] ++
+                 if haddock then [Dependency "haddock" AnyVersion] else []
+        externalDeps = filter (not . isBuiltIn cFlav cVersion)
+                       (buildDepends pkgDesc)
+    exReqs <- mapM (showRpmReq verbose (virtualPackage c)) externalDeps
+    myReqs <- mapM (showRpmReq verbose id) myDeps
+    return $ (concat . intersperse ", " . concat) (myReqs ++ exReqs)
+
+-- | Represent a dependency in a form suitable for an RPM spec file.
+
+showRpmReq :: Verbosity -> (String -> String) -> Dependency -> IO [String]
+
+showRpmReq verbose f (Dependency pkg AnyVersion) =
+    return [f pkg]
+showRpmReq verbose f (Dependency pkg (ThisVersion v)) =
+    return [f pkg ++ " = " ++ showVersion v]
+showRpmReq verbose f (Dependency pkg (EarlierVersion v)) =
+    return [f pkg ++ " < " ++ showVersion v]
+showRpmReq verbose f (Dependency pkg (LaterVersion v)) =
+    return [f pkg ++ " > " ++ showVersion v]
+showRpmReq verbose f (Dependency pkg (UnionVersionRanges
+                         (ThisVersion v1)
+                         (LaterVersion v2)))
+    | v1 == v2 = return [f pkg ++ " >= " ++ showVersion v1]
+showRpmReq verbose f (Dependency pkg (UnionVersionRanges
+                         (ThisVersion v1)
+                         (EarlierVersion v2)))
+    | v1 == v2 = return [f pkg ++ " <= " ++ showVersion v1]
+showRpmReq verbose f (Dependency pkg (UnionVersionRanges _ _)) = do
+    warn verbose ("Cannot accurately represent " ++
+                  "dependency on package " ++ f pkg)
+    warn verbose "  (uses version union, which RPM can't handle)"
+    return [f pkg]
+showRpmReq verbose f (Dependency pkg (IntersectVersionRanges r1 r2)) = do
+    d1 <- showRpmReq verbose f (Dependency pkg r1)
+    d2 <- showRpmReq verbose f (Dependency pkg r2)
+    return (d1 ++ d2)
+
+-- | Find the paths to all "extra" libraries specified in the package
+-- config.  Prefer shared libraries, since that's what gcc prefers.
+findLibPaths :: BuildInfo -> IO [FilePath]
+
+findLibPaths buildInfo = mapM findLib (extraLibs buildInfo)
+  where findLib :: String -> IO FilePath
+        findLib lib = do
+            so <- findLibPath ("lib" ++ lib ++ ".so")
+            if isJust so
+              then return (fromJust so)
+              else findLibPath ("lib" ++ lib ++ ".a") >>=
+                   maybe (die $ "could not find library: lib" ++ lib)
+                         return
+        findLibPath extraLib = do
+            loc <- findInExtraLibs (extraLibDirs buildInfo)
+            if isJust loc
+              then return loc
+              else findWithGcc extraLib
+          where findInExtraLibs (d:ds) = do
+                    let path = d </> extraLib
+                    exists <- doesFileExist path
+                    if exists
+                      then return (Just path)
+                      else findInExtraLibs ds
+                findInExtraLibs [] = return Nothing
+
+-- | Return the full path to a file (usually an object file) that gcc
+-- knows about.
+
+findWithGcc :: FilePath -> IO (Maybe FilePath)
+
+findWithGcc lib = do
+    (i,o,e,p) <- runInteractiveCommand $ "gcc -print-file-name=" ++ lib
+    loc <- hGetLine o
+    mapM_ hClose [i,o,e]
+    waitForProcess p
+    return $ if loc == lib then Nothing else Just loc
+
+-- | Return the RPM that owns a particular file or directory.  Die if
+-- not owned.
+
+findRpmOwner :: FilePath -> IO String
+findRpmOwner path = do
+    (i,o,e,p) <- runInteractiveCommand (rpmQuery ++ path)
+    pkg <- hGetLine o
+    mapM_ hClose [i,o,e]
+    ret <- waitForProcess p
+    case ret of
+      ExitSuccess -> return pkg
+      _ -> die $ "not owned by any package: " ++ path
+  where rpmQuery = "rpm --queryformat='%{NAME}' -qf "
+
+-- | Find all RPMs on which the build of this package depends.  Die if
+-- a dependency is not present, or not owned by an RPM.
+
+findLibDeps :: BuildInfo -> IO [String]
+
+findLibDeps buildInfo = findLibPaths buildInfo >>= mapM findRpmOwner
diff --git a/src/Distribution/Package/Rpm/Main.hs b/src/Distribution/Package/Rpm/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Package/Rpm/Main.hs
@@ -0,0 +1,29 @@
+-- |
+-- Module      :  Distribution.Package.Rpm.Main
+-- Copyright   :  Bryan O'Sullivan 2007
+--
+-- Maintainer  :  Bryan O'Sullivan <bos@serpentine.com>
+-- Stability   :  alpha
+-- Portability :  portable
+--
+-- Explanation: Main entry point for building RPM packages.
+
+-- This software may be used and distributed according to the terms of
+-- the GNU General Public License, incorporated herein by reference.
+
+module Distribution.Package.Rpm.Main where
+
+import Distribution.PackageDescription (packageDescription,
+                                        readPackageDescription)
+import Distribution.Package.Rpm (rpm)
+import Distribution.Package.Rpm.Setup (RpmFlags (..), parseArgs)
+import Distribution.Simple.Utils (defaultPackageDesc)
+import System.Environment (getArgs)
+
+main :: IO ()
+
+main = do opts <- getArgs >>= parseArgs
+          let verbosity = rpmVerbosity opts
+          descPath <- defaultPackageDesc verbosity
+          pkgDesc <- readPackageDescription verbosity descPath
+          rpm (packageDescription pkgDesc) opts
diff --git a/src/Distribution/Package/Rpm/Setup.hs b/src/Distribution/Package/Rpm/Setup.hs
new file mode 100644
--- /dev/null
+++ b/src/Distribution/Package/Rpm/Setup.hs
@@ -0,0 +1,128 @@
+-- |
+-- Module      :  Distribution.Package.Rpm.Setup
+-- Copyright   :  Bryan O'Sullivan 2007
+--
+-- Maintainer  :  Bryan O'Sullivan <bos@serpentine.com>
+-- Stability   :  alpha
+-- Portability :  portable
+--
+-- Explanation: Command line option processing for building RPM
+-- packages.
+
+-- This software may be used and distributed according to the terms of
+-- the GNU General Public License, incorporated herein by reference.
+
+module Distribution.Package.Rpm.Setup (
+      RpmFlags(..)
+    , parseArgs
+    ) where
+
+import Control.Monad (when)
+import Distribution.Setup (defaultCompilerFlavor, CompilerFlavor(..))
+import Distribution.Verbosity (Verbosity(..), flagToVerbosity, normal)
+import System.Console.GetOpt (ArgDescr (..), ArgOrder (..), OptDescr (..),
+                              usageInfo, getOpt')
+import System.Environment (getProgName)
+import System.Exit (exitWith, ExitCode (..))
+import System.IO (Handle, hPutStrLn, stderr, stdout)
+
+data RpmFlags = RpmFlags
+    {
+      rpmCompiler :: Maybe CompilerFlavor
+    , rpmGenSpec :: Bool
+    , rpmHaddock :: Bool
+    , rpmHelp :: Bool
+    , rpmLibProf :: Bool
+    , rpmName :: Maybe String
+    , rpmOptimisation :: Bool
+    , rpmRelease :: Maybe String
+    , rpmSplitObjs :: Bool
+    , rpmTopDir :: Maybe FilePath
+    , rpmVerbosity :: Verbosity
+    , rpmVersion :: Maybe String
+    }
+    deriving (Eq, Show)
+
+emptyRpmFlags :: RpmFlags
+
+emptyRpmFlags = RpmFlags
+    {
+      rpmCompiler = defaultCompilerFlavor
+    , rpmGenSpec = False
+    , rpmHaddock = True
+    , rpmHelp = False
+    , rpmLibProf = True
+    , rpmName = Nothing
+    , rpmOptimisation = True
+    , rpmRelease = Nothing
+    , rpmSplitObjs = True
+    , rpmTopDir = Nothing
+    , rpmVerbosity = normal
+    , rpmVersion = Nothing
+    }
+
+options :: [OptDescr (RpmFlags -> RpmFlags)]
+
+options =
+    [
+      Option "" ["ghc"] (NoArg (\x -> x { rpmCompiler = Just GHC }))
+             "Compile with GHC",
+      Option "" ["hugs"] (NoArg (\x -> x { rpmCompiler = Just Hugs }))
+             "Compile with Hugs",
+      Option "" ["jhc"] (NoArg (\x -> x { rpmCompiler = Just JHC }))
+             "Compile with JHC",
+      Option "" ["nhc"] (NoArg (\x -> x { rpmCompiler = Just NHC }))
+             "Compile with NHC",
+      Option "" ["gen-spec"] (NoArg (\x -> x { rpmGenSpec = True }))
+             "Generate a spec file, nothing more",
+      Option "h?" ["help"] (NoArg (\x -> x { rpmHelp = True }))
+             "Show this help text",
+      Option "" ["name"] (ReqArg (\name x -> x { rpmName = Just name }) "NAME")
+             "Override the default package name",
+      Option "" ["disable-haddock"] (NoArg (\x -> x { rpmHaddock = False }))
+             "Don't generate API docs",
+      Option "" ["disable-library-profiling"] (NoArg (\x -> x { rpmLibProf = False }))
+             "Don't generate profiling libraries",
+      Option "" ["disable-optimisation"] (NoArg (\x -> x { rpmOptimisation = False }))
+             "Don't generate optimised code",
+      Option "" ["disable-optimization"] (NoArg (\x -> x { rpmOptimisation = False }))
+             "Don't generate optimised code",
+      Option "" ["disable-split-objs"] (NoArg (\x -> x { rpmSplitObjs = False }))
+             "Don't split object files up to save space",
+      Option "" ["release"] (ReqArg (\rel x -> x { rpmRelease = Just rel }) "RELEASE")
+             "Override the default package release",
+      Option "" ["topdir"] (ReqArg (\path x -> x { rpmTopDir = Just path }) "TOPDIR")
+             "Override the default build directory",
+      Option "v" ["verbose"] (ReqArg (\verb x -> x { rpmVerbosity = flagToVerbosity (Just verb) }) "n")
+             "Override the default build directory",
+      Option "" ["version"] (ReqArg (\vers x -> x { rpmVersion = Just vers }) "VERSION")
+             "Override the default package version"
+    ]
+
+printHelp :: Handle -> IO ()
+
+printHelp h = do
+    progName <- getProgName
+    hPutStrLn h (usageInfo "Usage:" options)
+
+parseArgs :: [String] -> IO RpmFlags
+
+parseArgs args = do
+     let (os, args', unknown, errs) = getOpt' RequireOrder options args
+         opts = foldl (flip ($)) emptyRpmFlags os
+     when (rpmHelp opts) $ do
+       printHelp stdout
+       exitWith ExitSuccess
+     when (not (null errs)) $ do
+       hPutStrLn stderr "Errors:"
+       mapM_ (hPutStrLn stderr) errs
+       exitWith (ExitFailure 1)
+     when (not (null unknown)) $ do
+       hPutStrLn stderr "Unrecognised options:"
+       mapM_ (hPutStrLn stderr) unknown
+       exitWith (ExitFailure 1)
+     when (not (null args')) $ do
+       hPutStrLn stderr "Unrecognised arguments:"
+       mapM_ (hPutStrLn stderr) args'
+       exitWith (ExitFailure 1)
+     return opts
