content: module Rules.Generate (
      isGeneratedCmmFile, generatePackageCode, generateRules, copyRules,
      includesDependencies, generatedDependencies
      ) where
  
  import Base
  import Expression
  import Flavour
  import Oracles.Flag
  import Oracles.ModuleFiles
  import Oracles.Setting
  import Packages
  import Rules.Gmp
  import Rules.Libffi
  import Settings
  import Target
  import Utilities
  
  -- | Track this file to rebuild generated files whenever it changes.
  trackGenerateHs :: Expr ()
  trackGenerateHs = expr $ need [sourcePath -/- "Rules/Generate.hs"]
  
  primopsSource :: FilePath
  primopsSource = "compiler/prelude/primops.txt.pp"
  
  primopsTxt :: Stage -> FilePath
  primopsTxt stage = buildDir (vanillaContext stage compiler) -/- "primops.txt"
  
  platformH :: Stage -> FilePath
  platformH stage = buildDir (vanillaContext stage compiler) -/- "ghc_boot_platform.h"
  
  isGeneratedCmmFile :: FilePath -> Bool
  isGeneratedCmmFile file = takeBaseName file == "AutoApply"
  
  includesDependencies :: [FilePath]
  includesDependencies = fmap (generatedDir -/-)
      [ "ghcautoconf.h"
      , "ghcplatform.h"
      , "ghcversion.h" ]
  
  ghcPrimDependencies :: Expr [FilePath]
  ghcPrimDependencies = do
      stage <- getStage
      path  <- expr $ buildPath (vanillaContext stage ghcPrim)
      return [path -/- "GHC/Prim.hs", path -/- "GHC/PrimopWrappers.hs"]
  
  derivedConstantsDependencies :: [FilePath]
  derivedConstantsDependencies = fmap (generatedDir -/-)
      [ "DerivedConstants.h"
      , "GHCConstantsHaskellExports.hs"
      , "GHCConstantsHaskellType.hs"
      , "GHCConstantsHaskellWrappers.hs" ]
  
  compilerDependencies :: Expr [FilePath]
  compilerDependencies = do
      root    <- getBuildRoot
      stage   <- getStage
      isGmp   <- (== integerGmp) <$> getIntegerPackage
      ghcPath <- expr $ buildPath (vanillaContext stage compiler)
      gmpPath <- expr gmpBuildPath
      rtsPath <- expr rtsBuildPath
      mconcat [ return [root -/- platformH stage]
              , return ((root -/-) <$> includesDependencies)
              , return ((root -/-) <$> derivedConstantsDependencies)
              , notStage0 ? isGmp ? return [gmpPath -/- gmpLibraryH]
              , notStage0 ? return ((rtsPath -/-) <$> libffiDependencies)
              , return $ fmap (ghcPath -/-)
                    [ "primop-can-fail.hs-incl"
                    , "primop-code-size.hs-incl"
                    , "primop-commutable.hs-incl"
                    , "primop-data-decl.hs-incl"
                    , "primop-fixity.hs-incl"
                    , "primop-has-side-effects.hs-incl"
                    , "primop-list.hs-incl"
                    , "primop-out-of-line.hs-incl"
                    , "primop-primop-info.hs-incl"
                    , "primop-strictness.hs-incl"
                    , "primop-tag.hs-incl"
                    , "primop-vector-tycons.hs-incl"
                    , "primop-vector-tys-exports.hs-incl"
                    , "primop-vector-tys.hs-incl"
                    , "primop-vector-uniques.hs-incl" ] ]
  
  generatedDependencies :: Expr [FilePath]
  generatedDependencies = do
      root    <- getBuildRoot
      rtsPath <- expr rtsBuildPath
      mconcat [ package compiler ? compilerDependencies
              , package ghcPrim  ? ghcPrimDependencies
              , package rts      ? return (fmap (rtsPath -/-) libffiDependencies
                  ++ fmap (root -/-) includesDependencies
                  ++ fmap (root -/-) derivedConstantsDependencies)
              , stage0 ? return (fmap (root -/-) includesDependencies) ]
  
  generate :: FilePath -> Context -> Expr String -> Action ()
  generate file context expr = do
      contents <- interpretInContext context expr
      writeFileChanged file contents
      putSuccess $ "| Successfully generated " ++ file ++ "."
  
  generatePackageCode :: Context -> Rules ()
  generatePackageCode context@(Context stage pkg _) = do
      root <- buildRootRules
      let dir         = buildDir context
          generated f = (root -/- dir ++ "//*.hs") ?== f && not ("//autogen/*" ?== f)
          go gen file = generate file context gen
      generated ?> \file -> do
          let unpack = fromMaybe . error $ "No generator for " ++ file ++ "."
          (src, builder) <- unpack <$> findGenerator context file
          need [src]
          build $ target context builder [src] [file]
          let boot = src -<.> "hs-boot"
          whenM (doesFileExist boot) . copyFile boot $ file -<.> "hs-boot"
  
      priority 2.0 $ do
          when (pkg == compiler) $ do root <//> dir -/- "Config.hs" %> go generateConfigHs
                                      root <//> dir -/- "*.hs-incl" %> genPrimopCode context
          when (pkg == ghcPrim) $ do (root <//> dir -/- "GHC/Prim.hs") %> genPrimopCode context
                                     (root <//> dir -/- "GHC/PrimopWrappers.hs") %> genPrimopCode context
          when (pkg == ghcPkg) $ do root <//> dir -/- "Version.hs" %> go generateVersionHs
  
      -- TODO: needing platformH is ugly and fragile
      when (pkg == compiler) $ do
          root -/- primopsTxt stage %> \file -> do
              root <- buildRoot
              need $ [ root -/- platformH stage
                     , primopsSource]
                  ++ fmap (root -/-) includesDependencies
              build $ target context HsCpp [primopsSource] [file]
  
          -- only generate this once! Until we have the include logic fixed.
          -- See the note on `platformH`
          when (stage == Stage0) $ do
              root <//> "compiler/ghc_boot_platform.h" %> go generateGhcBootPlatformH
          root <//> platformH stage %> go generateGhcBootPlatformH
  
      when (pkg == rts) $ do
          root <//> dir -/- "cmm/AutoApply.cmm" %> \file ->
              build $ target context GenApply [] [file]
          -- XXX: this should be fixed properly, e.g. generated here on demand.
          (root <//> dir -/- "DerivedConstants.h") <~ (buildRoot <&> (-/- generatedDir))
          (root <//> dir -/- "ghcautoconf.h") <~ (buildRoot <&> (-/- generatedDir))
          (root <//> dir -/- "ghcplatform.h") <~ (buildRoot <&> (-/- generatedDir))
          (root <//> dir -/- "ghcversion.h") <~ (buildRoot <&> (-/- generatedDir))
      when (pkg == integerGmp) $ do
          (root <//> dir -/- "ghc-gmp.h") <~ (buildRoot <&> (-/- "include"))
   where
      pattern <~ mdir = pattern %> \file -> do
          dir <- mdir
          copyFile (dir -/- takeFileName file) file
  
  genPrimopCode :: Context -> FilePath -> Action ()
  genPrimopCode context@(Context stage _pkg _) file = do
      root <- buildRoot
      need [root -/- primopsTxt stage]
      build $ target context GenPrimopCode [root -/- primopsTxt stage] [file]
  
  copyRules :: Rules ()
  copyRules = do
      root <- buildRootRules
      forM_ [Stage0 ..] $ \stage -> do
          let prefix = root -/- stageString stage -/- "lib"
          prefix -/- "ghc-usage.txt"     <~ return "driver"
          prefix -/- "ghci-usage.txt"    <~ return "driver"
          prefix -/- "llvm-targets"      <~ return "."
          prefix -/- "llvm-passes"       <~ return "."
          prefix -/- "platformConstants" <~ (buildRoot <&> (-/- generatedDir))
          prefix -/- "settings"          <~ return "."
          prefix -/- "template-hsc.h"    <~ return (pkgPath hsc2hs)
    where
      infixl 1 <~
      pattern <~ mdir = pattern %> \file -> do
          dir <- mdir
          copyFile (dir -/- takeFileName file) file
  
  generateRules :: Rules ()
  generateRules = do
      root <- buildRootRules
      priority 2.0 $ (root -/- generatedDir -/- "ghcautoconf.h") <~ generateGhcAutoconfH
      priority 2.0 $ (root -/- generatedDir -/- "ghcplatform.h") <~ generateGhcPlatformH
      priority 2.0 $ (root -/- generatedDir -/-  "ghcversion.h") <~ generateGhcVersionH
  
      forM_ [Stage0 ..] $ \stage ->
          root -/- ghcSplitPath stage %> \path -> do
              generate path emptyTarget generateGhcSplit
              makeExecutable path
  
      -- TODO: simplify, get rid of fake rts context
      root -/- generatedDir ++ "//*" %> \file -> do
          withTempDir $ \dir -> build $
              target rtsContext DeriveConstants [] [file, dir]
    where
      file <~ gen = file %> \out -> generate out emptyTarget gen
  
  -- TODO: Use the Types, Luke! (drop partial function)
  -- We sometimes need to evaluate expressions that do not require knowing all
  -- information about the context. In this case, we don't want to know anything.
  emptyTarget :: Context
  emptyTarget = vanillaContext (error "Rules.Generate.emptyTarget: unknown stage")
                               (error "Rules.Generate.emptyTarget: unknown package")
  
  -- Generators
  
  -- | Given a 'String' replace charaters '.' and '-' by underscores ('_') so that
  -- the resulting 'String' is a valid C preprocessor identifier.
  cppify :: String -> String
  cppify = replaceEq '-' '_' . replaceEq '.' '_'
  
  ghcSplitSource :: FilePath
  ghcSplitSource = "driver/split/ghc-split.pl"
  
  -- ref: rules/build-perl.mk
  -- | Generate the @ghc-split@ Perl script.
  generateGhcSplit :: Expr String
  generateGhcSplit = do
      trackGenerateHs
      targetPlatform <- getSetting TargetPlatform
      ghcEnableTNC   <- expr $ yesNo <$> ghcEnableTablesNextToCode
      perlPath       <- getBuilderPath Perl
      contents       <- expr $ readFileLines ghcSplitSource
      return . unlines $
          [ "#!" ++ perlPath
          , "my $TARGETPLATFORM = " ++ show targetPlatform ++ ";"
          -- I don't see where the ghc-split tool uses TNC, but
          -- it's in the build-perl macro.
          , "my $TABLES_NEXT_TO_CODE = " ++ show ghcEnableTNC ++ ";"
          ] ++ contents
  
  -- | Generate @ghcplatform.h@ header.
  generateGhcPlatformH :: Expr String
  generateGhcPlatformH = do
      trackGenerateHs
      hostPlatform   <- getSetting HostPlatform
      hostArch       <- getSetting HostArch
      hostOs         <- getSetting HostOs
      hostVendor     <- getSetting HostVendor
      targetPlatform <- getSetting TargetPlatform
      targetArch     <- getSetting TargetArch
      targetOs       <- getSetting TargetOs
      targetVendor   <- getSetting TargetVendor
      ghcUnreg       <- getFlag    GhcUnregisterised
      return . unlines $
          [ "#ifndef __GHCPLATFORM_H__"
          , "#define __GHCPLATFORM_H__"
          , ""
          , "#define BuildPlatform_TYPE  " ++ cppify hostPlatform
          , "#define HostPlatform_TYPE   " ++ cppify targetPlatform
          , ""
          , "#define " ++ cppify hostPlatform   ++ "_BUILD 1"
          , "#define " ++ cppify targetPlatform ++ "_HOST 1"
          , ""
          , "#define " ++ hostArch   ++ "_BUILD_ARCH 1"
          , "#define " ++ targetArch ++ "_HOST_ARCH 1"
          , "#define BUILD_ARCH " ++ show hostArch
          , "#define HOST_ARCH "  ++ show targetArch
          , ""
          , "#define " ++ hostOs   ++ "_BUILD_OS 1"
          , "#define " ++ targetOs ++ "_HOST_OS 1"
          , "#define BUILD_OS " ++ show hostOs
          , "#define HOST_OS "  ++ show targetOs
          , ""
          , "#define " ++ hostVendor   ++ "_BUILD_VENDOR 1"
          , "#define " ++ targetVendor ++ "_HOST_VENDOR 1"
          , "#define BUILD_VENDOR " ++ show hostVendor
          , "#define HOST_VENDOR "  ++ show targetVendor
          , ""
          , "/* These TARGET macros are for backwards compatibility... DO NOT USE! */"
          , "#define TargetPlatform_TYPE " ++ cppify targetPlatform
          , "#define " ++ cppify targetPlatform ++ "_TARGET 1"
          , "#define " ++ targetArch ++ "_TARGET_ARCH 1"
          , "#define TARGET_ARCH " ++ show targetArch
          , "#define " ++ targetOs ++ "_TARGET_OS 1"
          , "#define TARGET_OS " ++ show targetOs
          , "#define " ++ targetVendor ++ "_TARGET_VENDOR 1" ]
          ++
          [ "#define UnregisterisedCompiler 1" | ghcUnreg ]
          ++
          [ "\n#endif /* __GHCPLATFORM_H__ */" ]
  
  -- | Generate @Config.hs@ files.
  generateConfigHs :: Expr String
  generateConfigHs = do
      trackGenerateHs
      cProjectName        <- getSetting ProjectName
      cProjectGitCommitId <- getSetting ProjectGitCommitId
      cProjectVersion     <- getSetting ProjectVersion
      cProjectVersionInt  <- getSetting ProjectVersionInt
      cProjectPatchLevel  <- getSetting ProjectPatchLevel
      cProjectPatchLevel1 <- getSetting ProjectPatchLevel1
      cProjectPatchLevel2 <- getSetting ProjectPatchLevel2
      cBooterVersion      <- getSetting GhcVersion
      intLib              <- getIntegerPackage
      debugged            <- ghcDebugged    <$> expr flavour
      let cIntegerLibraryType
              | intLib == integerGmp    = "IntegerGMP"
              | intLib == integerSimple = "IntegerSimple"
              | otherwise = error $ "Unknown integer library: " ++ pkgName intLib
      cSupportsSplitObjs         <- expr $ yesNo <$> supportsSplitObjects
      cGhcWithInterpreter        <- expr $ yesNo <$> ghcWithInterpreter
      cGhcWithNativeCodeGen      <- expr $ yesNo <$> ghcWithNativeCodeGen
      cGhcWithSMP                <- expr $ yesNo <$> ghcWithSMP
      cGhcEnableTablesNextToCode <- expr $ yesNo <$> ghcEnableTablesNextToCode
      cLeadingUnderscore         <- expr $ yesNo <$> flag LeadingUnderscore
      cGHC_UNLIT_PGM             <- fmap takeFileName $ getBuilderPath Unlit
      cLibFFI                    <- expr useLibFFIForAdjustors
      rtsWays                    <- getRtsWays
      cGhcRtsWithLibdw           <- getFlag WithLibdw
      let cGhcRTSWays = unwords $ map show rtsWays
      return $ unlines
          [ "{-# LANGUAGE CPP #-}"
          , "module Config where"
          , ""
          , "import GhcPrelude"
          , ""
          , "#include \"ghc_boot_platform.h\""
          , ""
          , "data IntegerLibrary = IntegerGMP"
          , "                    | IntegerSimple"
          , "                    deriving Eq"
          , ""
          , "cBuildPlatformString :: String"
          , "cBuildPlatformString = BuildPlatform_NAME"
          , "cHostPlatformString :: String"
          , "cHostPlatformString = HostPlatform_NAME"
          , "cTargetPlatformString :: String"
          , "cTargetPlatformString = TargetPlatform_NAME"
          , ""
          , "cProjectName          :: String"
          , "cProjectName          = " ++ show cProjectName
          , "cProjectGitCommitId   :: String"
          , "cProjectGitCommitId   = " ++ show cProjectGitCommitId
          , "cProjectVersion       :: String"
          , "cProjectVersion       = " ++ show cProjectVersion
          , "cProjectVersionInt    :: String"
          , "cProjectVersionInt    = " ++ show cProjectVersionInt
          , "cProjectPatchLevel    :: String"
          , "cProjectPatchLevel    = " ++ show cProjectPatchLevel
          , "cProjectPatchLevel1   :: String"
          , "cProjectPatchLevel1   = " ++ show cProjectPatchLevel1
          , "cProjectPatchLevel2   :: String"
          , "cProjectPatchLevel2   = " ++ show cProjectPatchLevel2
          , "cBooterVersion        :: String"
          , "cBooterVersion        = " ++ show cBooterVersion
          , "cStage                :: String"
          , "cStage                = show (STAGE :: Int)"
          , "cIntegerLibrary       :: String"
          , "cIntegerLibrary       = " ++ show (pkgName intLib)
          , "cIntegerLibraryType   :: IntegerLibrary"
          , "cIntegerLibraryType   = " ++ cIntegerLibraryType
          , "cSupportsSplitObjs    :: String"
          , "cSupportsSplitObjs    = " ++ show cSupportsSplitObjs
          , "cGhcWithInterpreter   :: String"
          , "cGhcWithInterpreter   = " ++ show cGhcWithInterpreter
          , "cGhcWithNativeCodeGen :: String"
          , "cGhcWithNativeCodeGen = " ++ show cGhcWithNativeCodeGen
          , "cGhcWithSMP           :: String"
          , "cGhcWithSMP           = " ++ show cGhcWithSMP
          , "cGhcRTSWays           :: String"
          , "cGhcRTSWays           = " ++ show cGhcRTSWays
          , "cGhcEnableTablesNextToCode :: String"
          , "cGhcEnableTablesNextToCode = " ++ show cGhcEnableTablesNextToCode
          , "cLeadingUnderscore    :: String"
          , "cLeadingUnderscore    = " ++ show cLeadingUnderscore
          , "cGHC_UNLIT_PGM        :: String"
          , "cGHC_UNLIT_PGM        = " ++ show cGHC_UNLIT_PGM
          , "cGHC_SPLIT_PGM        :: String"
          , "cGHC_SPLIT_PGM        = " ++ show "ghc-split"
          , "cLibFFI               :: Bool"
          , "cLibFFI               = " ++ show cLibFFI
          , "cGhcThreaded :: Bool"
          , "cGhcThreaded = " ++ show (any (wayUnit Threaded) rtsWays)
          , "cGhcDebugged :: Bool"
          , "cGhcDebugged = " ++ show debugged
          , "cGhcRtsWithLibdw :: Bool"
          , "cGhcRtsWithLibdw = " ++ show cGhcRtsWithLibdw ]
  
  -- | Generate @ghcautoconf.h@ header.
  generateGhcAutoconfH :: Expr String
  generateGhcAutoconfH = do
      trackGenerateHs
      configHContents  <- expr $ map undefinePackage <$> readFileLines configH
      tablesNextToCode <- expr ghcEnableTablesNextToCode
      ghcUnreg         <- getFlag    GhcUnregisterised
      ccLlvmBackend    <- getSetting CcLlvmBackend
      ccClangBackend   <- getSetting CcClangBackend
      return . unlines $
          [ "#ifndef __GHCAUTOCONF_H__"
          , "#define __GHCAUTOCONF_H__" ]
          ++ configHContents ++
          [ "\n#define TABLES_NEXT_TO_CODE 1" | tablesNextToCode && not ghcUnreg ]
          ++
          [ "\n#define llvm_CC_FLAVOR 1"      | ccLlvmBackend == "1" ]
          ++
          [ "\n#define clang_CC_FLAVOR 1"     | ccClangBackend == "1" ]
          ++
          [ "#endif /* __GHCAUTOCONF_H__ */" ]
    where
      undefinePackage s
          | "#define PACKAGE_" `isPrefixOf` s
              = "/* #undef " ++ takeWhile (/=' ') (drop 8 s) ++ " */"
          | otherwise = s
  
  -- | Generate @ghc_boot_platform.h@ headers.
  generateGhcBootPlatformH :: Expr String
  generateGhcBootPlatformH = do
      trackGenerateHs
      stage <- getStage
      let chooseSetting x y = getSetting $ if stage == Stage0 then x else y
      buildPlatform  <- chooseSetting BuildPlatform HostPlatform
      buildArch      <- chooseSetting BuildArch     HostArch
      buildOs        <- chooseSetting BuildOs       HostOs
      buildVendor    <- chooseSetting BuildVendor   HostVendor
      hostPlatform   <- chooseSetting HostPlatform  TargetPlatform
      hostArch       <- chooseSetting HostArch      TargetArch
      hostOs         <- chooseSetting HostOs        TargetOs
      hostVendor     <- chooseSetting HostVendor    TargetVendor
      targetPlatform <- getSetting TargetPlatform
      targetArch     <- getSetting TargetArch
      llvmTarget     <- getSetting LlvmTarget
      targetOs       <- getSetting TargetOs
      targetVendor   <- getSetting TargetVendor
      return $ unlines
          [ "#ifndef __PLATFORM_H__"
          , "#define __PLATFORM_H__"
          , ""
          , "#define BuildPlatform_NAME  " ++ show buildPlatform
          , "#define HostPlatform_NAME   " ++ show hostPlatform
          , "#define TargetPlatform_NAME " ++ show targetPlatform
          , ""
          , "#define " ++ cppify buildPlatform  ++ "_BUILD 1"
          , "#define " ++ cppify hostPlatform   ++ "_HOST 1"
          , "#define " ++ cppify targetPlatform ++ "_TARGET 1"
          , ""
          , "#define " ++ buildArch  ++ "_BUILD_ARCH 1"
          , "#define " ++ hostArch   ++ "_HOST_ARCH 1"
          , "#define " ++ targetArch ++ "_TARGET_ARCH 1"
          , "#define BUILD_ARCH "  ++ show buildArch
          , "#define HOST_ARCH "   ++ show hostArch
          , "#define TARGET_ARCH " ++ show targetArch
          , "#define LLVM_TARGET " ++ show llvmTarget
          , ""
          , "#define " ++ buildOs  ++ "_BUILD_OS 1"
          , "#define " ++ hostOs   ++ "_HOST_OS 1"
          , "#define " ++ targetOs ++ "_TARGET_OS 1"
          , "#define BUILD_OS "  ++ show buildOs
          , "#define HOST_OS "   ++ show hostOs
          , "#define TARGET_OS " ++ show targetOs
          , ""
          , "#define " ++ buildVendor  ++ "_BUILD_VENDOR 1"
          , "#define " ++ hostVendor   ++ "_HOST_VENDOR 1"
          , "#define " ++ targetVendor ++ "_TARGET_VENDOR  1"
          , "#define BUILD_VENDOR "  ++ show buildVendor
          , "#define HOST_VENDOR "   ++ show hostVendor
          , "#define TARGET_VENDOR " ++ show targetVendor
          , ""
          , "#endif /* __PLATFORM_H__ */" ]
  
  -- | Generate @ghcversion.h@ header.
  generateGhcVersionH :: Expr String
  generateGhcVersionH = do
      trackGenerateHs
      version     <- getSetting ProjectVersionInt
      patchLevel1 <- getSetting ProjectPatchLevel1
      patchLevel2 <- getSetting ProjectPatchLevel2
      return . unlines $
          [ "#ifndef __GHCVERSION_H__"
          , "#define __GHCVERSION_H__"
          , ""
          , "#ifndef __GLASGOW_HASKELL__"
          , "# define __GLASGOW_HASKELL__ " ++ version
          , "#endif"
          , ""]
          ++
          [ "#define __GLASGOW_HASKELL_PATCHLEVEL1__ " ++ patchLevel1 | patchLevel1 /= "" ]
          ++
          [ "#define __GLASGOW_HASKELL_PATCHLEVEL2__ " ++ patchLevel2 | patchLevel2 /= "" ]
          ++
          [ ""
          , "#define MIN_VERSION_GLASGOW_HASKELL(ma,mi,pl1,pl2) (\\"
          , "   ((ma)*100+(mi)) <  __GLASGOW_HASKELL__ || \\"
          , "   ((ma)*100+(mi)) == __GLASGOW_HASKELL__    \\"
          , "          && (pl1) <  __GLASGOW_HASKELL_PATCHLEVEL1__ || \\"
          , "   ((ma)*100+(mi)) == __GLASGOW_HASKELL__    \\"
          , "          && (pl1) == __GLASGOW_HASKELL_PATCHLEVEL1__ \\"
          , "          && (pl2) <= __GLASGOW_HASKELL_PATCHLEVEL2__ )"
          , ""
          , "#endif /* __GHCVERSION_H__ */" ]
  
  -- | Generate @Version.hs@ files.
  generateVersionHs :: Expr String
  generateVersionHs = do
      trackGenerateHs
      projectVersion <- getSetting ProjectVersion
      targetOs       <- getSetting TargetOs
      targetArch     <- getSetting TargetArch
      return $ unlines
          [ "module Version where"
          , "version, targetOS, targetARCH :: String"
          , "version    = " ++ show projectVersion
          , "targetOS   = " ++ show targetOs
          , "targetARCH = " ++ show targetArch ]
  