    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Distribution.Simple.Program.Ar
    -- Copyright   :  Duncan Coutts 2009
    --
    -- Maintainer  :  cabal-devel@haskell.org
    -- Portability :  portable
    --
    -- This module provides an library interface to the @ar@ program.

    module Distribution.Simple.Program.Ar (
        createArLibArchive,
        multiStageProgramInvocation,
      ) where

    import Distribution.Simple.Program.Types
             ( ConfiguredProgram(..) )
    import Distribution.Simple.Program.Run
             ( programInvocation, multiStageProgramInvocation
             , runProgramInvocation )
    import Distribution.System
             ( OS(..), buildOS )
    import Distribution.Verbosity
             ( Verbosity, deafening, verbose )

    -- | Call @ar@ to create a library archive from a bunch of object files.
    --
    createArLibArchive :: Verbosity -> ConfiguredProgram
                       -> FilePath -> [FilePath] -> IO ()
    createArLibArchive verbosity ar target files =

      -- The args to use with "ar" are actually rather subtle and system-dependent.
      -- In particular we have the following issues:
      --
      --  -- On OS X, "ar q" does not make an archive index. Archives with no
      --     index cannot be used.
      --
      --  -- GNU "ar r" will not let us add duplicate objects, only "ar q" lets us
      --     do that. We have duplicates because of modules like "A.M" and "B.M"
      --     both make an object file "M.o" and ar does not consider the directory.
      --
      -- Our solution is to use "ar r" in the simple case when one call is enough.
      -- When we need to call ar multiple times we use "ar q" and for the last
      -- call on OSX we use "ar qs" so that it'll make the index.

      let simpleArgs  = case buildOS of
                 OSX -> ["-r", "-s"]
                 _   -> ["-r"]

          initialArgs = ["-q"]
          finalArgs   = case buildOS of
                 OSX -> ["-q", "-s"]
                 _   -> ["-q"]

          extraArgs   = verbosityOpts verbosity ++ [target]

          simple  = programInvocation ar (simpleArgs  ++ extraArgs)
          initial = programInvocation ar (initialArgs ++ extraArgs)
          middle  = initial
          final   = programInvocation ar (finalArgs   ++ extraArgs)

       in sequence_
            [ runProgramInvocation verbosity inv
            | inv <- multiStageProgramInvocation
                       simple (initial, middle, final) files ]

      where
        verbosityOpts v | v >= deafening = ["-v"]
                        | v >= verbose   = []
                        | otherwise      = ["-c"]