-----------------------------------------------------------------------------
-- |
-- 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 :: OSbuildOS of
             OSX -> ["-r", "-s"]
             _   -> ["-r"]

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

      extraArgs   = verbosityOpts :: Verbosity -> [[Char]]verbosityOpts verbosity :: Verbosityverbosity (++) :: [a] -> [a] -> [a]++ [target :: FilePathtarget]

      simple  = programInvocation ::
  ConfiguredProgram -> [String] -> ProgramInvocationprogramInvocation ar :: ConfiguredProgramar (simpleArgs :: [[Char]]simpleArgs  (++) :: [a] -> [a] -> [a]++ extraArgs :: [[Char]]extraArgs)
      initial = programInvocation ::
  ConfiguredProgram -> [String] -> ProgramInvocationprogramInvocation ar :: ConfiguredProgramar (initialArgs :: [[Char]]initialArgs (++) :: [a] -> [a] -> [a]++ extraArgs :: [[Char]]extraArgs)
      middle  = initial :: ProgramInvocationinitial
      final   = programInvocation ::
  ConfiguredProgram -> [String] -> ProgramInvocationprogramInvocation ar :: ConfiguredProgramar (finalArgs :: [[Char]]finalArgs   (++) :: [a] -> [a] -> [a]++ extraArgs :: [[Char]]extraArgs)

   in sequence_ :: Monad m => [m a] -> m ()sequence_
        [ runProgramInvocation :: Verbosity -> ProgramInvocation -> IO ()runProgramInvocation verbosity :: Verbosityverbosity inv :: ProgramInvocationinv
        | inv <- multiStageProgramInvocation ::
  ProgramInvocation
  -> (ProgramInvocation, ProgramInvocation, ProgramInvocation)
  -> [String]
  -> [ProgramInvocation]multiStageProgramInvocation
                   simple :: ProgramInvocationsimple (initial :: ProgramInvocationinitial, middle :: ProgramInvocationmiddle, final :: ProgramInvocationfinal) files :: [FilePath]files ]

  where
    verbosityOpts v | v :: Verbosityv (>=) :: Ord a => a -> a -> Bool>= deafening :: Verbositydeafening = ["-v"]
                    | v :: Verbosityv (>=) :: Ord a => a -> a -> Bool>= verbose :: Verbosityverbose   = [] :: [a][]
                    | otherwise :: Boolotherwise      = ["-c"]