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

module Distribution.Simple.Program.Ld (
    combineObjectFiles,
  ) where

import Distribution.Simple.Program.Types
         ( ConfiguredProgram(..) )
import Distribution.Simple.Program.Run
         ( programInvocation, multiStageProgramInvocation
         , runProgramInvocation )
import Distribution.Verbosity
         ( Verbosity )

import System.Directory
         ( renameFile )
import System.FilePath
         ( (<.>) )

-- | Call @ld -r@ to link a bunch of object files together.
--
combineObjectFiles :: Verbosity -> ConfiguredProgram
                   -> FilePath -> [FilePath] -> IO ()
combineObjectFiles verbosity ld target files =

  -- Unlike "ar", the "ld" tool is not designed to be used with xargs. That is,
  -- if we have more object files than fit on a single command line then we
  -- have a slight problem. What we have to do is link files in batches into
  -- a temp object file and then include that one in the next batch.

  let simpleArgs  = ["-r", "-o", target :: FilePathtarget]

      initialArgs = ["-r", "-o", target :: FilePathtarget]
      middleArgs  = ["-r", "-o", target :: FilePathtarget, tmpfile :: FilePathtmpfile]
      finalArgs   = middleArgs :: [[Char]]middleArgs

      simple      = programInvocation ::
  ConfiguredProgram -> [String] -> ProgramInvocationprogramInvocation ld :: ConfiguredProgramld simpleArgs :: [[Char]]simpleArgs
      initial     = programInvocation ::
  ConfiguredProgram -> [String] -> ProgramInvocationprogramInvocation ld :: ConfiguredProgramld initialArgs :: [[Char]]initialArgs
      middle      = programInvocation ::
  ConfiguredProgram -> [String] -> ProgramInvocationprogramInvocation ld :: ConfiguredProgramld middleArgs :: [[Char]]middleArgs
      final       = programInvocation ::
  ConfiguredProgram -> [String] -> ProgramInvocationprogramInvocation ld :: ConfiguredProgramld finalArgs :: [[Char]]finalArgs

      invocations = multiStageProgramInvocation ::
  ProgramInvocation
  -> (ProgramInvocation, ProgramInvocation, ProgramInvocation)
  -> [String]
  -> [ProgramInvocation]multiStageProgramInvocation
                      simple :: ProgramInvocationsimple (initial :: ProgramInvocationinitial, middle :: ProgramInvocationmiddle, final :: ProgramInvocationfinal) files :: [FilePath]files

   in run :: [ProgramInvocation] -> IO ()run invocations :: [ProgramInvocation]invocations

  where
    tmpfile        = target :: FilePathtarget (<.>) :: FilePath -> String -> FilePath<.> "tmp" -- perhaps should use a proper temp file

    run []         = return :: Monad m => forall a. a -> m areturn ()
    run [inv]      = runProgramInvocation :: Verbosity -> ProgramInvocation -> IO ()runProgramInvocation verbosity :: Verbosityverbosity inv :: ProgramInvocationinv
    run (inv:invs) = do runProgramInvocation :: Verbosity -> ProgramInvocation -> IO ()runProgramInvocation verbosity :: Verbosityverbosity inv :: ProgramInvocationinv
                        renameFile :: FilePath -> FilePath -> IO ()renameFile target :: FilePathtarget tmpfile :: FilePathtmpfile
                        run :: [ProgramInvocation] -> IO ()run invs :: [ProgramInvocation]invs