-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Simple.Program.Strip
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- This module provides an library interface to the @strip@ program.

module Distribution.Simple.Program.Strip (stripLib, stripExe)
       where

import Distribution.Simple.Program (ProgramConfiguration, lookupProgram
                                   , programVersion, rawSystemProgram
                                   , stripProgram)
import Distribution.Simple.Utils   (warn)
import Distribution.System         (Arch(..), Platform(..), OS (..), buildOS)
import Distribution.Verbosity      (Verbosity)
import Distribution.Version        (orLaterVersion, withinRange)

import Control.Monad               (unless)
import Data.Version                (Version(..))
import System.FilePath             (takeBaseName)

runStrip :: Verbosity -> ProgramConfiguration -> FilePath -> [String] -> IO ()
runStrip verbosity progConf path args =
  case lookupProgram stripProgram progConf of
    Just strip -> rawSystemProgram verbosity strip (path:args)
    Nothing    -> unless (buildOS == Windows) $
                  -- Don't bother warning on windows, we don't expect them to
                  -- have the strip program anyway.
                  warn verbosity $ "Unable to strip executable or library '"
                                   ++ (takeBaseName path)
                                   ++ "' (missing the 'strip' program)"

stripExe :: Verbosity -> Platform -> ProgramConfiguration -> FilePath -> IO ()
stripExe verbosity (Platform _arch os) conf path =
  runStrip verbosity conf path args
  where
    args = case os of
       OSX -> ["-x"] -- By default, stripping the ghc binary on at least
                     -- some OS X installations causes:
                     --     HSbase-3.0.o: unknown symbol `_environ'"
                     -- The -x flag fixes that.
       _   -> []

stripLib :: Verbosity -> Platform -> ProgramConfiguration -> FilePath -> IO ()
stripLib verbosity (Platform arch os) conf path = do
  case os of
    OSX -> -- '--strip-unneeded' is not supported on OS X, iOS or
           -- Solaris. See #1630.
           return ()
    IOS -> return ()
    Solaris -> return ()
    Windows -> -- Stripping triggers a bug in 'strip.exe' for
               -- libraries with lots identically named modules. See
               -- #1784.
               return()
    Linux | arch == I386 ->
      -- Versions of 'strip' on 32-bit Linux older than 2.18 are
      -- broken. See #2339.
      let okVersion = orLaterVersion (Version [2,18] [])
      in case programVersion =<< lookupProgram stripProgram conf of
          Just v | withinRange v okVersion ->
            runStrip verbosity conf path args
          _ -> warn verbosity $ "Unable to strip library '"
                                ++ (takeBaseName path)
                                ++ "' (version of 'strip' too old; "
                                ++ "requires >= 2.18 on 32-bit Linux)"
    _   -> runStrip verbosity conf path args
  where
    args = ["--strip-unneeded"]