----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.Program.Builtin -- Copyright : Isaac Jones 2006, Duncan Coutts 2007-2009 -- -- Maintainer : cabal-devel@haskell.org -- Portability : portable -- -- The module defines all the known built-in 'Program's. -- -- Where possible we try to find their version numbers. module Distribution.Simple.Program.Builtin ( -- * The collection of unconfigured and configured programs builtinPrograms -- * Programs that Cabal knows about , ghcProgram , ghcPkgProgram , runghcProgram , ghcjsProgram , ghcjsPkgProgram , jhcProgram , uhcProgram , gccProgram , gppProgram , arProgram , stripProgram , happyProgram , alexProgram , hsc2hsProgram , c2hsProgram , cpphsProgram , hscolourProgram , doctestProgram , haddockProgram , ldProgram , tarProgram , cppProgram , pkgConfigProgram , hpcProgram ) where import Distribution.Compat.Prelude import Prelude () import Distribution.Simple.Program.Find import Distribution.Simple.Program.GHC import Distribution.Simple.Program.Internal import Distribution.Simple.Program.Run import Distribution.Simple.Program.Types import Distribution.Simple.Utils import Distribution.Verbosity import Distribution.Version import qualified Data.Map as Map -- ------------------------------------------------------------ -- * Known programs -- ------------------------------------------------------------ -- | The default list of programs. -- These programs are typically used internally to Cabal. builtinPrograms :: [Program] builtinPrograms = [ -- compilers and related progs ghcProgram , runghcProgram , ghcPkgProgram , ghcjsProgram , ghcjsPkgProgram , jhcProgram , uhcProgram , hpcProgram , -- preprocessors hscolourProgram , doctestProgram , haddockProgram , happyProgram , alexProgram , hsc2hsProgram , c2hsProgram , cpphsProgram , -- platform toolchain gccProgram , arProgram , stripProgram , ldProgram , tarProgram , -- configuration tools pkgConfigProgram ] ghcProgram :: Program ghcProgram = (simpleProgram "ghc") { programFindVersion = findProgramVersion "--numeric-version" id , programPostConf = ghcPostConf , programNormaliseArgs = normaliseGhcArgs } where ghcPostConf _verbosity ghcProg = do let setLanguageEnv prog = prog { programOverrideEnv = ("LANGUAGE", Just "en") : programOverrideEnv ghcProg } ignorePackageEnv prog = prog{programDefaultArgs = "-package-env=-" : programDefaultArgs prog} -- Only the 7.8 branch seems to be affected. Fixed in 7.8.4. affectedVersionRange = intersectVersionRanges (laterVersion $ mkVersion [7, 8, 0]) (earlierVersion $ mkVersion [7, 8, 4]) canIgnorePackageEnv = orLaterVersion $ mkVersion [8, 4, 4] applyWhen cond f prog = if cond then f prog else prog return $ maybe ghcProg ( \v -> -- By default, ignore GHC_ENVIRONMENT variable of any package environmnet -- files. See #10759 applyWhen (withinRange v canIgnorePackageEnv) ignorePackageEnv -- Workaround for https://gitlab.haskell.org/ghc/ghc/-/issues/8825 -- (spurious warning on non-english locales) $ applyWhen (withinRange v affectedVersionRange) setLanguageEnv $ ghcProg ) (programVersion ghcProg) runghcProgram :: Program runghcProgram = (simpleProgram "runghc") { programFindVersion = findProgramVersion "--version" $ \str -> case words str of -- "runghc 7.10.3" (_ : ver : _) -> ver _ -> "" } ghcPkgProgram :: Program ghcPkgProgram = (simpleProgram "ghc-pkg") { programFindVersion = findProgramVersion "--version" $ \str -> -- Invoking "ghc-pkg --version" gives a string like -- "GHC package manager version 6.4.1" case words str of (_ : _ : _ : _ : ver : _) -> ver _ -> "" } ghcjsProgram :: Program ghcjsProgram = (simpleProgram "ghcjs") { programFindVersion = findProgramVersion "--numeric-ghcjs-version" id } -- note: version is the version number of the GHC version that ghcjs-pkg was built with ghcjsPkgProgram :: Program ghcjsPkgProgram = (simpleProgram "ghcjs-pkg") { programFindVersion = findProgramVersion "--version" $ \str -> -- Invoking "ghcjs-pkg --version" gives a string like -- "GHCJS package manager version 6.4.1" case words str of (_ : _ : _ : _ : ver : _) -> ver _ -> "" } jhcProgram :: Program jhcProgram = (simpleProgram "jhc") { programFindVersion = findProgramVersion "--version" $ \str -> -- invoking "jhc --version" gives a string like -- "jhc 0.3.20080208 (wubgipkamcep-2) -- compiled by ghc-6.8 on a x86_64 running linux" case words str of (_ : ver : _) -> ver _ -> "" } uhcProgram :: Program uhcProgram = (simpleProgram "uhc") { programFindVersion = findProgramVersion "--version-dotted" id } hpcProgram :: Program hpcProgram = (simpleProgram "hpc") { programFindVersion = findProgramVersion "version" $ \str -> case words str of (_ : _ : _ : ver : _) -> ver _ -> "" } happyProgram :: Program happyProgram = (simpleProgram "happy") { programFindVersion = findProgramVersion "--version" $ \str -> -- Invoking "happy --version" gives a string like -- "Happy Version 1.16 Copyright (c) ...." case words str of (_ : _ : ver : _) -> ver _ -> "" } alexProgram :: Program alexProgram = (simpleProgram "alex") { programFindVersion = findProgramVersion "--version" $ \str -> -- Invoking "alex --version" gives a string like -- "Alex version 2.1.0, (c) 2003 Chris Dornan and Simon Marlow" case words str of (_ : _ : ver : _) -> takeWhile (\x -> isDigit x || x == '.') ver _ -> "" } gccProgram :: Program gccProgram = (simpleProgram "gcc") { programFindVersion = findProgramVersion "-dumpversion" id } gppProgram :: Program gppProgram = (simpleProgram "gpp") { programFindVersion = findProgramVersion "-dumpversion" id , programFindLocation = \v p -> findProgramOnSearchPath v p "g++" } arProgram :: Program arProgram = simpleProgram "ar" stripProgram :: Program stripProgram = (simpleProgram "strip") { programFindVersion = \verbosity -> findProgramVersion "--version" stripExtractVersion (lessVerbose verbosity) } hsc2hsProgram :: Program hsc2hsProgram = (simpleProgram "hsc2hs") { programFindVersion = findProgramVersion "--version" $ \str -> -- Invoking "hsc2hs --version" gives a string like "hsc2hs version 0.66" case words str of (_ : _ : ver : _) -> ver _ -> "" } c2hsProgram :: Program c2hsProgram = (simpleProgram "c2hs") { programFindVersion = findProgramVersion "--numeric-version" id } cpphsProgram :: Program cpphsProgram = (simpleProgram "cpphs") { programFindVersion = findProgramVersion "--version" $ \str -> -- Invoking "cpphs --version" gives a string like "cpphs 1.3" case words str of (_ : ver : _) -> ver _ -> "" } hscolourProgram :: Program hscolourProgram = (simpleProgram "hscolour") { programFindLocation = \v p -> findProgramOnSearchPath v p "HsColour" , programFindVersion = findProgramVersion "-version" $ \str -> -- Invoking "HsColour -version" gives a string like "HsColour 1.7" case words str of (_ : ver : _) -> ver _ -> "" } -- TODO: Ensure that doctest is built against the same GHC as the one -- that's being used. Same for haddock. @phadej pointed this out. doctestProgram :: Program doctestProgram = (simpleProgram "doctest") { programFindLocation = \v p -> findProgramOnSearchPath v p "doctest" , programFindVersion = findProgramVersion "--version" $ \str -> -- "doctest version 0.11.2" case words str of (_ : _ : ver : _) -> ver _ -> "" } haddockProgram :: Program haddockProgram = (simpleProgram "haddock") { programFindVersion = findProgramVersion "--version" $ \str -> -- Invoking "haddock --version" gives a string like -- "Haddock version 0.8, (c) Simon Marlow 2006" case words str of (_ : _ : ver : _) -> takeWhile (`elem` ('.' : ['0' .. '9'])) ver _ -> "" , programNormaliseArgs = \_ _ args -> args } ldProgram :: Program ldProgram = (simpleProgram "ld") { programPostConf = \verbosity ldProg -> do -- The `lld` linker cannot create merge (relocatable) objects so we -- want to detect this. -- If the linker does support relocatable objects, we want to use that -- to create partially pre-linked objects for GHCi, so we get much -- faster loading as we do not have to do the separate loading and -- in-memory linking the static linker in GHC does, but can offload -- parts of this process to a pre-linking step. -- However this requires the linker to support this features. Not all -- linkers do, and notably as of this writing `lld` which is a popular -- choice for windows linking does not support this feature. However -- if using binutils ld or another linker that supports --relocatable, -- we should still be good to generate pre-linked objects. ldHelpOutput <- getProgramInvocationOutput verbosity (programInvocation ldProg ["--help"]) -- In case the linker does not support '--help'. Eg the LLVM linker, -- `lld` only accepts `-help`. `catchIO` (\_ -> return "") let k = "Supports relocatable output" -- Standard GNU `ld` uses `--relocatable` while `ld.gold` uses -- `-relocatable` (single `-`). v | "-relocatable" `isInfixOf` ldHelpOutput = "YES" -- ld64 on macOS has this lovely response for "--help" -- -- ld64: For information on command line options please use 'man ld'. -- -- it does however support -r, if you read the manpage -- (e.g. https://www.manpagez.com/man/1/ld64/) | "ld64:" `isPrefixOf` ldHelpOutput = "YES" | otherwise = "NO" m = Map.insert k v (programProperties ldProg) return $ ldProg{programProperties = m} } tarProgram :: Program tarProgram = (simpleProgram "tar") { -- See #1901. Some versions of 'tar' (OpenBSD, NetBSD, ...) don't support the -- '--format' option. programPostConf = \verbosity tarProg -> do tarHelpOutput <- getProgramInvocationOutput verbosity (programInvocation tarProg ["--help"]) -- Some versions of tar don't support '--help'. `catchIO` (\_ -> return "") let k = "Supports --format" v = if ("--format" `isInfixOf` tarHelpOutput) then "YES" else "NO" m = Map.insert k v (programProperties tarProg) return $ tarProg{programProperties = m} } cppProgram :: Program cppProgram = simpleProgram "cpp" pkgConfigProgram :: Program pkgConfigProgram = (simpleProgram "pkg-config") { programFindVersion = findProgramVersion "--version" id , programPostConf = \_ pkgConfProg -> let programOverrideEnv' = programOverrideEnv pkgConfProg ++ [ ("PKG_CONFIG_ALLOW_SYSTEM_CFLAGS", Just "1") , ("PKG_CONFIG_ALLOW_SYSTEM_LIBS", Just "1") ] in pure $ pkgConfProg{programOverrideEnv = programOverrideEnv'} }