module Settings.Builders.Hsc2Hs (hsc2hsBuilderArgs) where

import Hadrian.Haskell.Cabal.Type

import Builder
import Settings.Builders.Common
import GHC.Toolchain (tgtCCompilerLink, ccLinkProgram)
import GHC.Toolchain.Program

hsc2hsBuilderArgs :: Args
hsc2hsBuilderArgs = builder Hsc2Hs ? do
    stage   <- getStage
    ccPath  <- getBuilderPath $ Cc CompileC stage
    gmpDir  <- getSetting GmpIncludeDir
    top     <- expr topDirectory
    hArch   <- queryHost queryArch
    hOs     <- queryHost queryOS
    tArch   <- queryTarget queryArch
    tOs     <- queryTarget queryOS
    version <- case stage of
                  Stage0 {} -> expr ghcCanonVersion
                  _ ->  getSetting ProjectVersionInt
    tmpl <- (top -/-) <$> expr (templateHscPath stage0Boot)
    mconcat [ arg $ "--cc=" ++ ccPath
            , arg $ "--ld=" ++ ccPath
            , notM isWinTarget ? notM (flag CrossCompiling) ? arg "--cross-safe"
            , pure $ map ("-I" ++) (words gmpDir)
            , map ("--cflag=" ++) <$> getCFlags
            , map ("--lflag=" ++) <$> getLFlags
            , notStage0 ? flag CrossCompiling ? arg "--cross-compile"
            , stage0    ? arg ("--cflag=-D" ++ hArch ++ "_HOST_ARCH=1")
            , stage0    ? arg ("--cflag=-D" ++ hOs   ++ "_HOST_OS=1"  )
            , notStage0 ? arg ("--cflag=-D" ++ tArch ++ "_HOST_ARCH=1")
            , notStage0 ? arg ("--cflag=-D" ++ tOs   ++ "_HOST_OS=1"  )
            , arg $ "--cflag=-D__GLASGOW_HASKELL__=" ++ version
            , arg $ "--template=" ++ tmpl
              -- We'll assume we compile with gcc or clang, and both support
              -- `-S` and can as such use the --via-asm flag, which should be
              -- faster and is required for cross compiling to windows, as the c
              -- compiler complains about non-constant expressions even though
              -- they are constant and end up as constants in the assembly.
              -- See #12849
            , flag CrossCompiling ? isWinTarget ? arg "--via-asm"
            , arg =<< getInput
            , arg "-o", arg =<< getOutput ]

getCFlags :: Expr [String]
getCFlags = do
    context <- getContext
    autogen <- expr $ autogenPath context
    let cabalMacros = autogen -/- "cabal_macros.h"
    expr $ need [cabalMacros]
    mconcat [ remove ["-O"] (cArgs <> getStagedCCFlags)
            -- Either "-E" is not part of the configured cpp args, or we can't add those args to invocations of things like this
            -- ROMES:TODO: , prgFlags . cppProgram . tgtCPreprocessor <$> getStagedTargetConfig
            , cIncludeArgs
            , getContextData ccOpts
            -- we might be able to leave out cppOpts, to be investigated.
            , getContextData cppOpts
            , getContextData depCcOpts
            , cWarnings
            , arg "-include", arg cabalMacros ]

getLFlags :: Expr [String]
getLFlags =
    mconcat [ prgFlags . ccLinkProgram . tgtCCompilerLink <$> getStagedTarget
            , ldArgs
            , getContextData ldOpts
            , getContextData depLdOpts ]
