diff options
author | Sylvain Henry <sylvain@haskus.fr> | 2020-04-05 17:39:13 +0200 |
---|---|---|
committer | Sylvain Henry <sylvain@haskus.fr> | 2020-04-18 20:04:46 +0200 |
commit | 15312bbb53f247c9ed2c5cf75100a9f44c1c7227 (patch) | |
tree | 8306dcc04a5b7c82464f903044dfdd589e7fdcd7 /compiler/main | |
parent | 3ca52151881451ce5b3a7740d003e811b586140d (diff) | |
download | haskell-15312bbb53f247c9ed2c5cf75100a9f44c1c7227.tar.gz |
Modules (#13009)
* SysTools
* Parser
* GHC.Builtin
* GHC.Iface.Recomp
* Settings
Update Haddock submodule
Metric Decrease:
Naperian
parsing001
Diffstat (limited to 'compiler/main')
-rw-r--r-- | compiler/main/Ar.hs | 268 | ||||
-rw-r--r-- | compiler/main/Constants.hs | 50 | ||||
-rw-r--r-- | compiler/main/Elf.hs | 460 | ||||
-rw-r--r-- | compiler/main/FileCleanup.hs | 314 | ||||
-rw-r--r-- | compiler/main/FileSettings.hs | 16 | ||||
-rw-r--r-- | compiler/main/GhcNameVersion.hs | 11 | ||||
-rw-r--r-- | compiler/main/HeaderInfo.hs | 357 | ||||
-rw-r--r-- | compiler/main/PlatformConstants.hs | 17 | ||||
-rw-r--r-- | compiler/main/Settings.hs | 203 | ||||
-rw-r--r-- | compiler/main/StaticPtrTable.hs | 2 | ||||
-rw-r--r-- | compiler/main/SysTools.hs | 475 | ||||
-rw-r--r-- | compiler/main/SysTools/BaseDir.hs | 137 | ||||
-rw-r--r-- | compiler/main/SysTools/ExtraObj.hs | 244 | ||||
-rw-r--r-- | compiler/main/SysTools/Info.hs | 262 | ||||
-rw-r--r-- | compiler/main/SysTools/Process.hs | 387 | ||||
-rw-r--r-- | compiler/main/SysTools/Settings.hs | 253 | ||||
-rw-r--r-- | compiler/main/SysTools/Tasks.hs | 373 | ||||
-rw-r--r-- | compiler/main/SysTools/Terminal.hs | 104 | ||||
-rw-r--r-- | compiler/main/ToolSettings.hs | 64 |
19 files changed, 1 insertions, 3996 deletions
diff --git a/compiler/main/Ar.hs b/compiler/main/Ar.hs deleted file mode 100644 index 1a1862a6fe..0000000000 --- a/compiler/main/Ar.hs +++ /dev/null @@ -1,268 +0,0 @@ -{-# LANGUAGE OverloadedStrings, GeneralizedNewtypeDeriving, CPP #-} -{- Note: [The need for Ar.hs] -Building `-staticlib` required the presence of libtool, and was a such -restricted to mach-o only. As libtool on macOS and gnu libtool are very -different, there was no simple portable way to support this. - -libtool for static archives does essentially: concatinate the input archives, -add the input objects, and create a symbol index. Using `ar` for this task -fails as even `ar` (bsd and gnu, llvm, ...) do not provide the same -features across platforms (e.g. index prefixed retrieval of objects with -the same name.) - -As Archives are rather simple structurally, we can just build the archives -with Haskell directly and use ranlib on the final result to get the symbol -index. This should allow us to work around with the differences/abailability -of libtool across different platforms. --} -module Ar - (ArchiveEntry(..) - ,Archive(..) - ,afilter - - ,parseAr - - ,loadAr - ,loadObj - ,writeBSDAr - ,writeGNUAr - - ,isBSDSymdef - ,isGNUSymdef - ) - where - -import GhcPrelude - -import Data.List (mapAccumL, isPrefixOf) -import Data.Monoid ((<>)) -import Data.Binary.Get -import Data.Binary.Put -import Control.Monad -import Control.Applicative -import qualified Data.ByteString as B -import qualified Data.ByteString.Char8 as C -import qualified Data.ByteString.Lazy as L -#if !defined(mingw32_HOST_OS) -import qualified System.Posix.Files as POSIX -#endif -import System.FilePath (takeFileName) - -data ArchiveEntry = ArchiveEntry - { filename :: String -- ^ File name. - , filetime :: Int -- ^ File modification time. - , fileown :: Int -- ^ File owner. - , filegrp :: Int -- ^ File group. - , filemode :: Int -- ^ File mode. - , filesize :: Int -- ^ File size. - , filedata :: B.ByteString -- ^ File bytes. - } deriving (Eq, Show) - -newtype Archive = Archive [ArchiveEntry] - deriving (Eq, Show, Semigroup, Monoid) - -afilter :: (ArchiveEntry -> Bool) -> Archive -> Archive -afilter f (Archive xs) = Archive (filter f xs) - -isBSDSymdef, isGNUSymdef :: ArchiveEntry -> Bool -isBSDSymdef a = "__.SYMDEF" `isPrefixOf` (filename a) -isGNUSymdef a = "/" == (filename a) - --- | Archives have numeric values padded with '\x20' to the right. -getPaddedInt :: B.ByteString -> Int -getPaddedInt = read . C.unpack . C.takeWhile (/= '\x20') - -putPaddedInt :: Int -> Int -> Put -putPaddedInt padding i = putPaddedString '\x20' padding (show i) - -putPaddedString :: Char -> Int -> String -> Put -putPaddedString pad padding s = putByteString . C.pack . take padding $ s `mappend` (repeat pad) - -getBSDArchEntries :: Get [ArchiveEntry] -getBSDArchEntries = do - empty <- isEmpty - if empty then - return [] - else do - name <- getByteString 16 - when ('/' `C.elem` name && C.take 3 name /= "#1/") $ - fail "Looks like GNU Archive" - time <- getPaddedInt <$> getByteString 12 - own <- getPaddedInt <$> getByteString 6 - grp <- getPaddedInt <$> getByteString 6 - mode <- getPaddedInt <$> getByteString 8 - st_size <- getPaddedInt <$> getByteString 10 - end <- getByteString 2 - when (end /= "\x60\x0a") $ - fail ("[BSD Archive] Invalid archive header end marker for name: " ++ - C.unpack name) - off1 <- liftM fromIntegral bytesRead :: Get Int - -- BSD stores extended filenames, by writing #1/<length> into the - -- name field, the first @length@ bytes then represent the file name - -- thus the payload size is filesize + file name length. - name <- if C.unpack (C.take 3 name) == "#1/" then - liftM (C.unpack . C.takeWhile (/= '\0')) (getByteString $ read $ C.unpack $ C.drop 3 name) - else - return $ C.unpack $ C.takeWhile (/= ' ') name - off2 <- liftM fromIntegral bytesRead :: Get Int - file <- getByteString (st_size - (off2 - off1)) - -- data sections are two byte aligned (see #15396) - when (odd st_size) $ - void (getByteString 1) - - rest <- getBSDArchEntries - return $ (ArchiveEntry name time own grp mode (st_size - (off2 - off1)) file) : rest - --- | GNU Archives feature a special '//' entry that contains the --- extended names. Those are referred to as /<num>, where num is the --- offset into the '//' entry. --- In addition, filenames are terminated with '/' in the archive. -getGNUArchEntries :: Maybe ArchiveEntry -> Get [ArchiveEntry] -getGNUArchEntries extInfo = do - empty <- isEmpty - if empty - then return [] - else - do - name <- getByteString 16 - time <- getPaddedInt <$> getByteString 12 - own <- getPaddedInt <$> getByteString 6 - grp <- getPaddedInt <$> getByteString 6 - mode <- getPaddedInt <$> getByteString 8 - st_size <- getPaddedInt <$> getByteString 10 - end <- getByteString 2 - when (end /= "\x60\x0a") $ - fail ("[BSD Archive] Invalid archive header end marker for name: " ++ - C.unpack name) - file <- getByteString st_size - -- data sections are two byte aligned (see #15396) - when (odd st_size) $ - void (getByteString 1) - name <- return . C.unpack $ - if C.unpack (C.take 1 name) == "/" - then case C.takeWhile (/= ' ') name of - name@"/" -> name -- symbol table - name@"//" -> name -- extendedn file names table - name -> getExtName extInfo (read . C.unpack $ C.drop 1 name) - else C.takeWhile (/= '/') name - case name of - "/" -> getGNUArchEntries extInfo - "//" -> getGNUArchEntries (Just (ArchiveEntry name time own grp mode st_size file)) - _ -> (ArchiveEntry name time own grp mode st_size file :) <$> getGNUArchEntries extInfo - - where - getExtName :: Maybe ArchiveEntry -> Int -> B.ByteString - getExtName Nothing _ = error "Invalid extended filename reference." - getExtName (Just info) offset = C.takeWhile (/= '/') . C.drop offset $ filedata info - --- | put an Archive Entry. This assumes that the entries --- have been preprocessed to account for the extenden file name --- table section "//" e.g. for GNU Archives. Or that the names --- have been move into the payload for BSD Archives. -putArchEntry :: ArchiveEntry -> PutM () -putArchEntry (ArchiveEntry name time own grp mode st_size file) = do - putPaddedString ' ' 16 name - putPaddedInt 12 time - putPaddedInt 6 own - putPaddedInt 6 grp - putPaddedInt 8 mode - putPaddedInt 10 (st_size + pad) - putByteString "\x60\x0a" - putByteString file - when (pad == 1) $ - putWord8 0x0a - where - pad = st_size `mod` 2 - -getArchMagic :: Get () -getArchMagic = do - magic <- liftM C.unpack $ getByteString 8 - if magic /= "!<arch>\n" - then fail $ "Invalid magic number " ++ show magic - else return () - -putArchMagic :: Put -putArchMagic = putByteString $ C.pack "!<arch>\n" - -getArch :: Get Archive -getArch = Archive <$> do - getArchMagic - getBSDArchEntries <|> getGNUArchEntries Nothing - -putBSDArch :: Archive -> PutM () -putBSDArch (Archive as) = do - putArchMagic - mapM_ putArchEntry (processEntries as) - - where - padStr pad size str = take size $ str <> repeat pad - nameSize name = case length name `divMod` 4 of - (n, 0) -> 4 * n - (n, _) -> 4 * (n + 1) - needExt name = length name > 16 || ' ' `elem` name - processEntry :: ArchiveEntry -> ArchiveEntry - processEntry archive@(ArchiveEntry name _ _ _ _ st_size _) - | needExt name = archive { filename = "#1/" <> show sz - , filedata = C.pack (padStr '\0' sz name) <> filedata archive - , filesize = st_size + sz } - | otherwise = archive - - where sz = nameSize name - - processEntries = map processEntry - -putGNUArch :: Archive -> PutM () -putGNUArch (Archive as) = do - putArchMagic - mapM_ putArchEntry (processEntries as) - - where - processEntry :: ArchiveEntry -> ArchiveEntry -> (ArchiveEntry, ArchiveEntry) - processEntry extInfo archive@(ArchiveEntry name _ _ _ _ _ _) - | length name > 15 = ( extInfo { filesize = filesize extInfo + length name + 2 - , filedata = filedata extInfo <> C.pack name <> "/\n" } - , archive { filename = "/" <> show (filesize extInfo) } ) - | otherwise = ( extInfo, archive { filename = name <> "/" } ) - - processEntries :: [ArchiveEntry] -> [ArchiveEntry] - processEntries = - uncurry (:) . mapAccumL processEntry (ArchiveEntry "//" 0 0 0 0 0 mempty) - -parseAr :: B.ByteString -> Archive -parseAr = runGet getArch . L.fromChunks . pure - -writeBSDAr, writeGNUAr :: FilePath -> Archive -> IO () -writeBSDAr fp = L.writeFile fp . runPut . putBSDArch -writeGNUAr fp = L.writeFile fp . runPut . putGNUArch - -loadAr :: FilePath -> IO Archive -loadAr fp = parseAr <$> B.readFile fp - -loadObj :: FilePath -> IO ArchiveEntry -loadObj fp = do - payload <- B.readFile fp - (modt, own, grp, mode) <- fileInfo fp - return $ ArchiveEntry - (takeFileName fp) modt own grp mode - (B.length payload) payload - --- | Take a filePath and return (mod time, own, grp, mode in decimal) -fileInfo :: FilePath -> IO ( Int, Int, Int, Int) -- ^ mod time, own, grp, mode (in decimal) -#if defined(mingw32_HOST_OS) --- on windows mod time, owner group and mode are zero. -fileInfo _ = pure (0,0,0,0) -#else -fileInfo fp = go <$> POSIX.getFileStatus fp - where go status = ( fromEnum $ POSIX.modificationTime status - , fromIntegral $ POSIX.fileOwner status - , fromIntegral $ POSIX.fileGroup status - , oct2dec . fromIntegral $ POSIX.fileMode status - ) - -oct2dec :: Int -> Int -oct2dec = foldl' (\a b -> a * 10 + b) 0 . reverse . dec 8 - where dec _ 0 = [] - dec b i = let (rest, last) = i `quotRem` b - in last:dec b rest - -#endif diff --git a/compiler/main/Constants.hs b/compiler/main/Constants.hs deleted file mode 100644 index 9935b03583..0000000000 --- a/compiler/main/Constants.hs +++ /dev/null @@ -1,50 +0,0 @@ -{- -(c) The GRASP/AQUA Project, Glasgow University, 1992-1998 - -\section[Constants]{Info about this compilation} --} - -module Constants (module Constants) where - -import GhcPrelude - -import Config - -hiVersion :: Integer -hiVersion = read (cProjectVersionInt ++ cProjectPatchLevel) :: Integer - --- All pretty arbitrary: - -mAX_TUPLE_SIZE :: Int -mAX_TUPLE_SIZE = 62 -- Should really match the number - -- of decls in Data.Tuple - -mAX_CTUPLE_SIZE :: Int -- Constraint tuples -mAX_CTUPLE_SIZE = 62 -- Should match the number of decls in GHC.Classes - -mAX_SUM_SIZE :: Int -mAX_SUM_SIZE = 62 - --- | Default maximum depth for both class instance search and type family --- reduction. See also #5395. -mAX_REDUCTION_DEPTH :: Int -mAX_REDUCTION_DEPTH = 200 - --- | Default maximum constraint-solver iterations --- Typically there should be very few -mAX_SOLVER_ITERATIONS :: Int -mAX_SOLVER_ITERATIONS = 4 - -wORD64_SIZE :: Int -wORD64_SIZE = 8 - --- Size of float in bytes. -fLOAT_SIZE :: Int -fLOAT_SIZE = 4 - --- Size of double in bytes. -dOUBLE_SIZE :: Int -dOUBLE_SIZE = 8 - -tARGET_MAX_CHAR :: Int -tARGET_MAX_CHAR = 0x10ffff diff --git a/compiler/main/Elf.hs b/compiler/main/Elf.hs deleted file mode 100644 index 4d3b06e731..0000000000 --- a/compiler/main/Elf.hs +++ /dev/null @@ -1,460 +0,0 @@ -{- ------------------------------------------------------------------------------ --- --- (c) The University of Glasgow 2015 --- --- ELF format tools --- ------------------------------------------------------------------------------ --} - -module Elf ( - readElfSectionByName, - readElfNoteAsString, - makeElfNote - ) where - -import GhcPrelude - -import AsmUtils -import Exception -import GHC.Driver.Session -import GHC.Platform -import ErrUtils -import Maybes (MaybeT(..),runMaybeT) -import Util (charToC) -import Outputable (text,hcat,SDoc) - -import Control.Monad (when) -import Data.Binary.Get -import Data.Word -import Data.Char (ord) -import Data.ByteString.Lazy (ByteString) -import qualified Data.ByteString.Lazy as LBS -import qualified Data.ByteString.Lazy.Char8 as B8 - -{- Note [ELF specification] - ~~~~~~~~~~~~~~~~~~~~~~~~ - - ELF (Executable and Linking Format) is described in the System V Application - Binary Interface (or ABI). The latter is composed of two parts: a generic - part and a processor specific part. The generic ABI describes the parts of - the interface that remain constant across all hardware implementations of - System V. - - The latest release of the specification of the generic ABI is the version - 4.1 from March 18, 1997: - - - http://www.sco.com/developers/devspecs/gabi41.pdf - - Since 1997, snapshots of the draft for the "next" version are published: - - - http://www.sco.com/developers/gabi/ - - Quoting the notice on the website: "There is more than one instance of these - chapters to permit references to older instances to remain valid. All - modifications to these chapters are forward-compatible, so that correct use - of an older specification will not be invalidated by a newer instance. - Approximately on a yearly basis, a new instance will be saved, as it reaches - what appears to be a stable state." - - Nevertheless we will see that since 1998 it is not true for Note sections. - - Many ELF sections - ----------------- - - ELF-4.1: the normal section number fields in ELF are limited to 16 bits, - which runs out of bits when you try to cram in more sections than that. Two - fields are concerned: the one containing the number of the sections and the - one containing the index of the section that contains section's names. (The - same thing applies to the field containing the number of segments, but we - don't care about it here). - - ELF-next: to solve this, theses fields in the ELF header have an escape - value (different for each case), and the actual section number is stashed - into unused fields in the first section header. - - We support this extension as it is forward-compatible with ELF-4.1. - Moreover, GHC may generate objects with a lot of sections with the - "function-sections" feature (one section per function). - - Note sections - ------------- - - Sections with type "note" (SHT_NOTE in the specification) are used to add - arbitrary data into an ELF file. An entry in a note section is composed of a - name, a type and a value. - - ELF-4.1: "The note information in sections and program header elements holds - any number of entries, each of which is an array of 4-byte words in the - format of the target processor." Each entry has the following format: - | namesz | Word32: size of the name string (including the ending \0) - | descsz | Word32: size of the value - | type | Word32: type of the note - | name | Name string (with \0 padding to ensure 4-byte alignment) - | ... | - | desc | Value (with \0 padding to ensure 4-byte alignment) - | ... | - - ELF-next: "The note information in sections and program header elements - holds a variable amount of entries. In 64-bit objects (files with - e_ident[EI_CLASS] equal to ELFCLASS64), each entry is an array of 8-byte - words in the format of the target processor. In 32-bit objects (files with - e_ident[EI_CLASS] equal to ELFCLASS32), each entry is an array of 4-byte - words in the format of the target processor." (from 1998-2015 snapshots) - - This is not forward-compatible with ELF-4.1. In practice, for almost all - platforms namesz, descz and type fields are 4-byte words for both 32-bit and - 64-bit objects (see elf.h and readelf source code). - - The only exception in readelf source code is for IA_64 machines with OpenVMS - OS: "This OS has so many departures from the ELF standard that we test it at - many places" (comment for is_ia64_vms() in readelf.c). In this case, namesz, - descsz and type fields are 8-byte words and name and value fields are padded - to ensure 8-byte alignment. - - We don't support this platform in the following code. Reading a note section - could be done easily (by testing Machine and OS fields in the ELF header). - Writing a note section, however, requires that we generate a different - assembly code for GAS depending on the target platform and this is a little - bit more involved. - --} - - --- | ELF header --- --- The ELF header indicates the native word size (32-bit or 64-bit) and the --- endianness of the target machine. We directly store getters for words of --- different sizes as it is more convenient to use. We also store the word size --- as it is useful to skip some uninteresting fields. --- --- Other information such as the target machine and OS are left out as we don't --- use them yet. We could add them in the future if we ever need them. -data ElfHeader = ElfHeader - { gw16 :: Get Word16 -- ^ Get a Word16 with the correct endianness - , gw32 :: Get Word32 -- ^ Get a Word32 with the correct endianness - , gwN :: Get Word64 -- ^ Get a Word with the correct word size - -- and endianness - , wordSize :: Int -- ^ Word size in bytes - } - - --- | Read the ELF header -readElfHeader :: DynFlags -> ByteString -> IO (Maybe ElfHeader) -readElfHeader dflags bs = runGetOrThrow getHeader bs `catchIO` \_ -> do - debugTraceMsg dflags 3 $ - text ("Unable to read ELF header") - return Nothing - where - getHeader = do - magic <- getWord32be - ws <- getWord8 - endian <- getWord8 - version <- getWord8 - skip 9 -- skip OSABI, ABI version and padding - when (magic /= 0x7F454C46 || version /= 1) $ fail "Invalid ELF header" - - case (ws, endian) of - -- ELF 32, little endian - (1,1) -> return . Just $ ElfHeader - getWord16le - getWord32le - (fmap fromIntegral getWord32le) 4 - -- ELF 32, big endian - (1,2) -> return . Just $ ElfHeader - getWord16be - getWord32be - (fmap fromIntegral getWord32be) 4 - -- ELF 64, little endian - (2,1) -> return . Just $ ElfHeader - getWord16le - getWord32le - (fmap fromIntegral getWord64le) 8 - -- ELF 64, big endian - (2,2) -> return . Just $ ElfHeader - getWord16be - getWord32be - (fmap fromIntegral getWord64be) 8 - _ -> fail "Invalid ELF header" - - ------------------- --- SECTIONS ------------------- - - --- | Description of the section table -data SectionTable = SectionTable - { sectionTableOffset :: Word64 -- ^ offset of the table describing sections - , sectionEntrySize :: Word16 -- ^ size of an entry in the section table - , sectionEntryCount :: Word64 -- ^ number of sections - , sectionNameIndex :: Word32 -- ^ index of a special section which - -- contains section's names - } - --- | Read the ELF section table -readElfSectionTable :: DynFlags - -> ElfHeader - -> ByteString - -> IO (Maybe SectionTable) - -readElfSectionTable dflags hdr bs = action `catchIO` \_ -> do - debugTraceMsg dflags 3 $ - text ("Unable to read ELF section table") - return Nothing - where - getSectionTable :: Get SectionTable - getSectionTable = do - skip (24 + 2*wordSize hdr) -- skip header and some other fields - secTableOffset <- gwN hdr - skip 10 - entrySize <- gw16 hdr - entryCount <- gw16 hdr - secNameIndex <- gw16 hdr - return (SectionTable secTableOffset entrySize - (fromIntegral entryCount) - (fromIntegral secNameIndex)) - - action = do - secTable <- runGetOrThrow getSectionTable bs - -- In some cases, the number of entries and the index of the section - -- containing section's names must be found in unused fields of the first - -- section entry (see Note [ELF specification]) - let - offSize0 = fromIntegral $ sectionTableOffset secTable + 8 - + 3 * fromIntegral (wordSize hdr) - offLink0 = fromIntegral $ offSize0 + fromIntegral (wordSize hdr) - - entryCount' <- if sectionEntryCount secTable /= 0 - then return (sectionEntryCount secTable) - else runGetOrThrow (gwN hdr) (LBS.drop offSize0 bs) - entryNameIndex' <- if sectionNameIndex secTable /= 0xffff - then return (sectionNameIndex secTable) - else runGetOrThrow (gw32 hdr) (LBS.drop offLink0 bs) - return (Just $ secTable - { sectionEntryCount = entryCount' - , sectionNameIndex = entryNameIndex' - }) - - --- | A section -data Section = Section - { entryName :: ByteString -- ^ Name of the section - , entryBS :: ByteString -- ^ Content of the section - } - --- | Read a ELF section -readElfSectionByIndex :: DynFlags - -> ElfHeader - -> SectionTable - -> Word64 - -> ByteString - -> IO (Maybe Section) - -readElfSectionByIndex dflags hdr secTable i bs = action `catchIO` \_ -> do - debugTraceMsg dflags 3 $ - text ("Unable to read ELF section") - return Nothing - where - -- read an entry from the section table - getEntry = do - nameIndex <- gw32 hdr - skip (4+2*wordSize hdr) - offset <- fmap fromIntegral $ gwN hdr - size <- fmap fromIntegral $ gwN hdr - let bs' = LBS.take size (LBS.drop offset bs) - return (nameIndex,bs') - - -- read the entry with the given index in the section table - getEntryByIndex x = runGetOrThrow getEntry bs' - where - bs' = LBS.drop off bs - off = fromIntegral $ sectionTableOffset secTable + - x * fromIntegral (sectionEntrySize secTable) - - -- Get the name of a section - getEntryName nameIndex = do - let idx = fromIntegral (sectionNameIndex secTable) - (_,nameTable) <- getEntryByIndex idx - let bs' = LBS.drop nameIndex nameTable - runGetOrThrow getLazyByteStringNul bs' - - action = do - (nameIndex,bs') <- getEntryByIndex (fromIntegral i) - name <- getEntryName (fromIntegral nameIndex) - return (Just $ Section name bs') - - --- | Find a section from its name. Return the section contents. --- --- We do not perform any check on the section type. -findSectionFromName :: DynFlags - -> ElfHeader - -> SectionTable - -> String - -> ByteString - -> IO (Maybe ByteString) -findSectionFromName dflags hdr secTable name bs = - rec [0..sectionEntryCount secTable - 1] - where - -- convert the required section name into a ByteString to perform - -- ByteString comparison instead of String comparison - name' = B8.pack name - - -- compare recursively each section name and return the contents of - -- the matching one, if any - rec [] = return Nothing - rec (x:xs) = do - me <- readElfSectionByIndex dflags hdr secTable x bs - case me of - Just e | entryName e == name' -> return (Just (entryBS e)) - _ -> rec xs - - --- | Given a section name, read its contents as a ByteString. --- --- If the section isn't found or if there is any parsing error, we return --- Nothing -readElfSectionByName :: DynFlags - -> ByteString - -> String - -> IO (Maybe LBS.ByteString) - -readElfSectionByName dflags bs name = action `catchIO` \_ -> do - debugTraceMsg dflags 3 $ - text ("Unable to read ELF section \"" ++ name ++ "\"") - return Nothing - where - action = runMaybeT $ do - hdr <- MaybeT $ readElfHeader dflags bs - secTable <- MaybeT $ readElfSectionTable dflags hdr bs - MaybeT $ findSectionFromName dflags hdr secTable name bs - ------------------- --- NOTE SECTIONS ------------------- - --- | read a Note as a ByteString --- --- If you try to read a note from a section which does not support the Note --- format, the parsing is likely to fail and Nothing will be returned -readElfNoteBS :: DynFlags - -> ByteString - -> String - -> String - -> IO (Maybe LBS.ByteString) - -readElfNoteBS dflags bs sectionName noteId = action `catchIO` \_ -> do - debugTraceMsg dflags 3 $ - text ("Unable to read ELF note \"" ++ noteId ++ - "\" in section \"" ++ sectionName ++ "\"") - return Nothing - where - -- align the getter on n bytes - align n = do - m <- bytesRead - if m `mod` n == 0 - then return () - else skip 1 >> align n - - -- noteId as a bytestring - noteId' = B8.pack noteId - - -- read notes recursively until the one with a valid identifier is found - findNote hdr = do - align 4 - namesz <- gw32 hdr - descsz <- gw32 hdr - _ <- gw32 hdr -- we don't use the note type - name <- if namesz == 0 - then return LBS.empty - else getLazyByteStringNul - align 4 - desc <- if descsz == 0 - then return LBS.empty - else getLazyByteString (fromIntegral descsz) - if name == noteId' - then return $ Just desc - else findNote hdr - - - action = runMaybeT $ do - hdr <- MaybeT $ readElfHeader dflags bs - sec <- MaybeT $ readElfSectionByName dflags bs sectionName - MaybeT $ runGetOrThrow (findNote hdr) sec - --- | read a Note as a String --- --- If you try to read a note from a section which does not support the Note --- format, the parsing is likely to fail and Nothing will be returned -readElfNoteAsString :: DynFlags - -> FilePath - -> String - -> String - -> IO (Maybe String) - -readElfNoteAsString dflags path sectionName noteId = action `catchIO` \_ -> do - debugTraceMsg dflags 3 $ - text ("Unable to read ELF note \"" ++ noteId ++ - "\" in section \"" ++ sectionName ++ "\"") - return Nothing - where - action = do - bs <- LBS.readFile path - note <- readElfNoteBS dflags bs sectionName noteId - return (fmap B8.unpack note) - - --- | Generate the GAS code to create a Note section --- --- Header fields for notes are 32-bit long (see Note [ELF specification]). -makeElfNote :: Platform -> String -> String -> Word32 -> String -> SDoc -makeElfNote platform sectionName noteName typ contents = hcat [ - text "\t.section ", - text sectionName, - text ",\"\",", - sectionType platform "note", - text "\n", - text "\t.balign 4\n", - - -- note name length (+ 1 for ending \0) - asWord32 (length noteName + 1), - - -- note contents size - asWord32 (length contents), - - -- note type - asWord32 typ, - - -- note name (.asciz for \0 ending string) + padding - text "\t.asciz \"", - text noteName, - text "\"\n", - text "\t.balign 4\n", - - -- note contents (.ascii to avoid ending \0) + padding - text "\t.ascii \"", - text (escape contents), - text "\"\n", - text "\t.balign 4\n"] - where - escape :: String -> String - escape = concatMap (charToC.fromIntegral.ord) - - asWord32 :: Show a => a -> SDoc - asWord32 x = hcat [ - text "\t.4byte ", - text (show x), - text "\n"] - - ------------------- --- Helpers ------------------- - --- | runGet in IO monad that throws an IOException on failure -runGetOrThrow :: Get a -> LBS.ByteString -> IO a -runGetOrThrow g bs = case runGetOrFail g bs of - Left _ -> fail "Error while reading file" - Right (_,_,a) -> return a diff --git a/compiler/main/FileCleanup.hs b/compiler/main/FileCleanup.hs deleted file mode 100644 index 81d0ce7a40..0000000000 --- a/compiler/main/FileCleanup.hs +++ /dev/null @@ -1,314 +0,0 @@ -{-# LANGUAGE CPP #-} -module FileCleanup - ( TempFileLifetime(..) - , cleanTempDirs, cleanTempFiles, cleanCurrentModuleTempFiles - , addFilesToClean, changeTempFilesLifetime - , newTempName, newTempLibName, newTempDir - , withSystemTempDirectory, withTempDirectory - ) where - -import GhcPrelude - -import GHC.Driver.Session -import ErrUtils -import Outputable -import Util -import Exception -import GHC.Driver.Phases - -import Control.Monad -import Data.List -import qualified Data.Set as Set -import qualified Data.Map as Map -import Data.IORef -import System.Directory -import System.FilePath -import System.IO.Error - -#if !defined(mingw32_HOST_OS) -import qualified System.Posix.Internals -#endif - --- | Used when a temp file is created. This determines which component Set of --- FilesToClean will get the temp file -data TempFileLifetime - = TFL_CurrentModule - -- ^ A file with lifetime TFL_CurrentModule will be cleaned up at the - -- end of upweep_mod - | TFL_GhcSession - -- ^ A file with lifetime TFL_GhcSession will be cleaned up at the end of - -- runGhc(T) - deriving (Show) - -cleanTempDirs :: DynFlags -> IO () -cleanTempDirs dflags - = unless (gopt Opt_KeepTmpFiles dflags) - $ mask_ - $ do let ref = dirsToClean dflags - ds <- atomicModifyIORef' ref $ \ds -> (Map.empty, ds) - removeTmpDirs dflags (Map.elems ds) - --- | Delete all files in @filesToClean dflags@. -cleanTempFiles :: DynFlags -> IO () -cleanTempFiles dflags - = unless (gopt Opt_KeepTmpFiles dflags) - $ mask_ - $ do let ref = filesToClean dflags - to_delete <- atomicModifyIORef' ref $ - \FilesToClean - { ftcCurrentModule = cm_files - , ftcGhcSession = gs_files - } -> ( emptyFilesToClean - , Set.toList cm_files ++ Set.toList gs_files) - removeTmpFiles dflags to_delete - --- | Delete all files in @filesToClean dflags@. That have lifetime --- TFL_CurrentModule. --- If a file must be cleaned eventually, but must survive a --- cleanCurrentModuleTempFiles, ensure it has lifetime TFL_GhcSession. -cleanCurrentModuleTempFiles :: DynFlags -> IO () -cleanCurrentModuleTempFiles dflags - = unless (gopt Opt_KeepTmpFiles dflags) - $ mask_ - $ do let ref = filesToClean dflags - to_delete <- atomicModifyIORef' ref $ - \ftc@FilesToClean{ftcCurrentModule = cm_files} -> - (ftc {ftcCurrentModule = Set.empty}, Set.toList cm_files) - removeTmpFiles dflags to_delete - --- | Ensure that new_files are cleaned on the next call of --- 'cleanTempFiles' or 'cleanCurrentModuleTempFiles', depending on lifetime. --- If any of new_files are already tracked, they will have their lifetime --- updated. -addFilesToClean :: DynFlags -> TempFileLifetime -> [FilePath] -> IO () -addFilesToClean dflags lifetime new_files = modifyIORef' (filesToClean dflags) $ - \FilesToClean - { ftcCurrentModule = cm_files - , ftcGhcSession = gs_files - } -> case lifetime of - TFL_CurrentModule -> FilesToClean - { ftcCurrentModule = cm_files `Set.union` new_files_set - , ftcGhcSession = gs_files `Set.difference` new_files_set - } - TFL_GhcSession -> FilesToClean - { ftcCurrentModule = cm_files `Set.difference` new_files_set - , ftcGhcSession = gs_files `Set.union` new_files_set - } - where - new_files_set = Set.fromList new_files - --- | Update the lifetime of files already being tracked. If any files are --- not being tracked they will be discarded. -changeTempFilesLifetime :: DynFlags -> TempFileLifetime -> [FilePath] -> IO () -changeTempFilesLifetime dflags lifetime files = do - FilesToClean - { ftcCurrentModule = cm_files - , ftcGhcSession = gs_files - } <- readIORef (filesToClean dflags) - let old_set = case lifetime of - TFL_CurrentModule -> gs_files - TFL_GhcSession -> cm_files - existing_files = [f | f <- files, f `Set.member` old_set] - addFilesToClean dflags lifetime existing_files - --- Return a unique numeric temp file suffix -newTempSuffix :: DynFlags -> IO Int -newTempSuffix dflags = - atomicModifyIORef' (nextTempSuffix dflags) $ \n -> (n+1,n) - --- Find a temporary name that doesn't already exist. -newTempName :: DynFlags -> TempFileLifetime -> Suffix -> IO FilePath -newTempName dflags lifetime extn - = do d <- getTempDir dflags - findTempName (d </> "ghc_") -- See Note [Deterministic base name] - where - findTempName :: FilePath -> IO FilePath - findTempName prefix - = do n <- newTempSuffix dflags - let filename = prefix ++ show n <.> extn - b <- doesFileExist filename - if b then findTempName prefix - else do -- clean it up later - addFilesToClean dflags lifetime [filename] - return filename - -newTempDir :: DynFlags -> IO FilePath -newTempDir dflags - = do d <- getTempDir dflags - findTempDir (d </> "ghc_") - where - findTempDir :: FilePath -> IO FilePath - findTempDir prefix - = do n <- newTempSuffix dflags - let filename = prefix ++ show n - b <- doesDirectoryExist filename - if b then findTempDir prefix - else do createDirectory filename - -- see mkTempDir below; this is wrong: -> consIORef (dirsToClean dflags) filename - return filename - -newTempLibName :: DynFlags -> TempFileLifetime -> Suffix - -> IO (FilePath, FilePath, String) -newTempLibName dflags lifetime extn - = do d <- getTempDir dflags - findTempName d ("ghc_") - where - findTempName :: FilePath -> String -> IO (FilePath, FilePath, String) - findTempName dir prefix - = do n <- newTempSuffix dflags -- See Note [Deterministic base name] - let libname = prefix ++ show n - filename = dir </> "lib" ++ libname <.> extn - b <- doesFileExist filename - if b then findTempName dir prefix - else do -- clean it up later - addFilesToClean dflags lifetime [filename] - return (filename, dir, libname) - - --- Return our temporary directory within tmp_dir, creating one if we --- don't have one yet. -getTempDir :: DynFlags -> IO FilePath -getTempDir dflags = do - mapping <- readIORef dir_ref - case Map.lookup tmp_dir mapping of - Nothing -> do - pid <- getProcessID - let prefix = tmp_dir </> "ghc" ++ show pid ++ "_" - mask_ $ mkTempDir prefix - Just dir -> return dir - where - tmp_dir = tmpDir dflags - dir_ref = dirsToClean dflags - - mkTempDir :: FilePath -> IO FilePath - mkTempDir prefix = do - n <- newTempSuffix dflags - let our_dir = prefix ++ show n - - -- 1. Speculatively create our new directory. - createDirectory our_dir - - -- 2. Update the dirsToClean mapping unless an entry already exists - -- (i.e. unless another thread beat us to it). - their_dir <- atomicModifyIORef' dir_ref $ \mapping -> - case Map.lookup tmp_dir mapping of - Just dir -> (mapping, Just dir) - Nothing -> (Map.insert tmp_dir our_dir mapping, Nothing) - - -- 3. If there was an existing entry, return it and delete the - -- directory we created. Otherwise return the directory we created. - case their_dir of - Nothing -> do - debugTraceMsg dflags 2 $ - text "Created temporary directory:" <+> text our_dir - return our_dir - Just dir -> do - removeDirectory our_dir - return dir - `catchIO` \e -> if isAlreadyExistsError e - then mkTempDir prefix else ioError e - -{- Note [Deterministic base name] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The filename of temporary files, especially the basename of C files, can end -up in the output in some form, e.g. as part of linker debug information. In the -interest of bit-wise exactly reproducible compilation (#4012), the basename of -the temporary file no longer contains random information (it used to contain -the process id). - -This is ok, as the temporary directory used contains the pid (see getTempDir). --} -removeTmpDirs :: DynFlags -> [FilePath] -> IO () -removeTmpDirs dflags ds - = traceCmd dflags "Deleting temp dirs" - ("Deleting: " ++ unwords ds) - (mapM_ (removeWith dflags removeDirectory) ds) - -removeTmpFiles :: DynFlags -> [FilePath] -> IO () -removeTmpFiles dflags fs - = warnNon $ - traceCmd dflags "Deleting temp files" - ("Deleting: " ++ unwords deletees) - (mapM_ (removeWith dflags removeFile) deletees) - where - -- Flat out refuse to delete files that are likely to be source input - -- files (is there a worse bug than having a compiler delete your source - -- files?) - -- - -- Deleting source files is a sign of a bug elsewhere, so prominently flag - -- the condition. - warnNon act - | null non_deletees = act - | otherwise = do - putMsg dflags (text "WARNING - NOT deleting source files:" - <+> hsep (map text non_deletees)) - act - - (non_deletees, deletees) = partition isHaskellUserSrcFilename fs - -removeWith :: DynFlags -> (FilePath -> IO ()) -> FilePath -> IO () -removeWith dflags remover f = remover f `catchIO` - (\e -> - let msg = if isDoesNotExistError e - then text "Warning: deleting non-existent" <+> text f - else text "Warning: exception raised when deleting" - <+> text f <> colon - $$ text (show e) - in debugTraceMsg dflags 2 msg - ) - -#if defined(mingw32_HOST_OS) --- relies on Int == Int32 on Windows -foreign import ccall unsafe "_getpid" getProcessID :: IO Int -#else -getProcessID :: IO Int -getProcessID = System.Posix.Internals.c_getpid >>= return . fromIntegral -#endif - --- The following three functions are from the `temporary` package. - --- | Create and use a temporary directory in the system standard temporary --- directory. --- --- Behaves exactly the same as 'withTempDirectory', except that the parent --- temporary directory will be that returned by 'getTemporaryDirectory'. -withSystemTempDirectory :: String -- ^ Directory name template. See 'openTempFile'. - -> (FilePath -> IO a) -- ^ Callback that can use the directory - -> IO a -withSystemTempDirectory template action = - getTemporaryDirectory >>= \tmpDir -> withTempDirectory tmpDir template action - - --- | Create and use a temporary directory. --- --- Creates a new temporary directory inside the given directory, making use --- of the template. The temp directory is deleted after use. For example: --- --- > withTempDirectory "src" "sdist." $ \tmpDir -> do ... --- --- The @tmpDir@ will be a new subdirectory of the given directory, e.g. --- @src/sdist.342@. -withTempDirectory :: FilePath -- ^ Temp directory to create the directory in - -> String -- ^ Directory name template. See 'openTempFile'. - -> (FilePath -> IO a) -- ^ Callback that can use the directory - -> IO a -withTempDirectory targetDir template = - Exception.bracket - (createTempDirectory targetDir template) - (ignoringIOErrors . removeDirectoryRecursive) - -ignoringIOErrors :: IO () -> IO () -ignoringIOErrors ioe = ioe `catch` (\e -> const (return ()) (e :: IOError)) - - -createTempDirectory :: FilePath -> String -> IO FilePath -createTempDirectory dir template = do - pid <- getProcessID - findTempName pid - where findTempName x = do - let path = dir </> template ++ show x - createDirectory path - return path - `catchIO` \e -> if isAlreadyExistsError e - then findTempName (x+1) else ioError e diff --git a/compiler/main/FileSettings.hs b/compiler/main/FileSettings.hs deleted file mode 100644 index 6179721cfd..0000000000 --- a/compiler/main/FileSettings.hs +++ /dev/null @@ -1,16 +0,0 @@ -module FileSettings - ( FileSettings (..) - ) where - -import GhcPrelude - --- | Paths to various files and directories used by GHC, including those that --- provide more settings. -data FileSettings = FileSettings - { fileSettings_ghcUsagePath :: FilePath -- ditto - , fileSettings_ghciUsagePath :: FilePath -- ditto - , fileSettings_toolDir :: Maybe FilePath -- ditto - , fileSettings_topDir :: FilePath -- ditto - , fileSettings_tmpDir :: String -- no trailing '/' - , fileSettings_globalPackageDatabase :: FilePath - } diff --git a/compiler/main/GhcNameVersion.hs b/compiler/main/GhcNameVersion.hs deleted file mode 100644 index 96e04186a7..0000000000 --- a/compiler/main/GhcNameVersion.hs +++ /dev/null @@ -1,11 +0,0 @@ -module GhcNameVersion - ( GhcNameVersion (..) - ) where - -import GhcPrelude - --- | Settings for what GHC this is. -data GhcNameVersion = GhcNameVersion - { ghcNameVersion_programName :: String - , ghcNameVersion_projectVersion :: String - } diff --git a/compiler/main/HeaderInfo.hs b/compiler/main/HeaderInfo.hs deleted file mode 100644 index cb1b1e3c2b..0000000000 --- a/compiler/main/HeaderInfo.hs +++ /dev/null @@ -1,357 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE ViewPatterns #-} -{-# LANGUAGE TypeFamilies #-} - ------------------------------------------------------------------------------ --- --- | Parsing the top of a Haskell source file to get its module name, --- imports and options. --- --- (c) Simon Marlow 2005 --- (c) Lemmih 2006 --- ------------------------------------------------------------------------------ - -module HeaderInfo ( getImports - , mkPrelImports -- used by the renamer too - , getOptionsFromFile, getOptions - , optionsErrorMsgs, - checkProcessArgsResult ) where - -#include "HsVersions.h" - -import GhcPrelude - -import GHC.Platform -import GHC.Driver.Types -import Parser ( parseHeader ) -import Lexer -import FastString -import GHC.Hs -import GHC.Types.Module -import PrelNames -import StringBuffer -import GHC.Types.SrcLoc -import GHC.Driver.Session -import ErrUtils -import Util -import Outputable -import Maybes -import Bag ( emptyBag, listToBag, unitBag ) -import MonadUtils -import Exception -import GHC.Types.Basic -import qualified GHC.LanguageExtensions as LangExt - -import Control.Monad -import System.IO -import System.IO.Unsafe -import Data.List - ------------------------------------------------------------------------------- - --- | Parse the imports of a source file. --- --- Throws a 'SourceError' if parsing fails. -getImports :: DynFlags - -> StringBuffer -- ^ Parse this. - -> FilePath -- ^ Filename the buffer came from. Used for - -- reporting parse error locations. - -> FilePath -- ^ The original source filename (used for locations - -- in the function result) - -> IO (Either - ErrorMessages - ([(Maybe FastString, Located ModuleName)], - [(Maybe FastString, Located ModuleName)], - Located ModuleName)) - -- ^ The source imports and normal imports (with optional package - -- names from -XPackageImports), and the module name. -getImports dflags buf filename source_filename = do - let loc = mkRealSrcLoc (mkFastString filename) 1 1 - case unP parseHeader (mkPState dflags buf loc) of - PFailed pst -> - -- assuming we're not logging warnings here as per below - return $ Left $ getErrorMessages pst dflags - POk pst rdr_module -> fmap Right $ do - let _ms@(_warns, errs) = getMessages pst dflags - -- don't log warnings: they'll be reported when we parse the file - -- for real. See #2500. - ms = (emptyBag, errs) - -- logWarnings warns - if errorsFound dflags ms - then throwIO $ mkSrcErr errs - else - let hsmod = unLoc rdr_module - mb_mod = hsmodName hsmod - imps = hsmodImports hsmod - main_loc = srcLocSpan (mkSrcLoc (mkFastString source_filename) - 1 1) - mod = mb_mod `orElse` L main_loc mAIN_NAME - (src_idecls, ord_idecls) = partition (ideclSource.unLoc) imps - - -- GHC.Prim doesn't exist physically, so don't go looking for it. - ordinary_imps = filter ((/= moduleName gHC_PRIM) . unLoc - . ideclName . unLoc) - ord_idecls - - implicit_prelude = xopt LangExt.ImplicitPrelude dflags - implicit_imports = mkPrelImports (unLoc mod) main_loc - implicit_prelude imps - convImport (L _ i) = (fmap sl_fs (ideclPkgQual i), ideclName i) - in - return (map convImport src_idecls, - map convImport (implicit_imports ++ ordinary_imps), - mod) - -mkPrelImports :: ModuleName - -> SrcSpan -- Attribute the "import Prelude" to this location - -> Bool -> [LImportDecl GhcPs] - -> [LImportDecl GhcPs] --- Construct the implicit declaration "import Prelude" (or not) --- --- NB: opt_NoImplicitPrelude is slightly different to import Prelude (); --- because the former doesn't even look at Prelude.hi for instance --- declarations, whereas the latter does. -mkPrelImports this_mod loc implicit_prelude import_decls - | this_mod == pRELUDE_NAME - || explicit_prelude_import - || not implicit_prelude - = [] - | otherwise = [preludeImportDecl] - where - explicit_prelude_import - = notNull [ () | L _ (ImportDecl { ideclName = mod - , ideclPkgQual = Nothing }) - <- import_decls - , unLoc mod == pRELUDE_NAME ] - - preludeImportDecl :: LImportDecl GhcPs - preludeImportDecl - = L loc $ ImportDecl { ideclExt = noExtField, - ideclSourceSrc = NoSourceText, - ideclName = L loc pRELUDE_NAME, - ideclPkgQual = Nothing, - ideclSource = False, - ideclSafe = False, -- Not a safe import - ideclQualified = NotQualified, - ideclImplicit = True, -- Implicit! - ideclAs = Nothing, - ideclHiding = Nothing } - --------------------------------------------------------------- --- Get options --------------------------------------------------------------- - --- | Parse OPTIONS and LANGUAGE pragmas of the source file. --- --- Throws a 'SourceError' if flag parsing fails (including unsupported flags.) -getOptionsFromFile :: DynFlags - -> FilePath -- ^ Input file - -> IO [Located String] -- ^ Parsed options, if any. -getOptionsFromFile dflags filename - = Exception.bracket - (openBinaryFile filename ReadMode) - (hClose) - (\handle -> do - opts <- fmap (getOptions' dflags) - (lazyGetToks dflags' filename handle) - seqList opts $ return opts) - where -- We don't need to get haddock doc tokens when we're just - -- getting the options from pragmas, and lazily lexing them - -- correctly is a little tricky: If there is "\n" or "\n-" - -- left at the end of a buffer then the haddock doc may - -- continue past the end of the buffer, despite the fact that - -- we already have an apparently-complete token. - -- We therefore just turn Opt_Haddock off when doing the lazy - -- lex. - dflags' = gopt_unset dflags Opt_Haddock - -blockSize :: Int --- blockSize = 17 -- for testing :-) -blockSize = 1024 - -lazyGetToks :: DynFlags -> FilePath -> Handle -> IO [Located Token] -lazyGetToks dflags filename handle = do - buf <- hGetStringBufferBlock handle blockSize - unsafeInterleaveIO $ lazyLexBuf handle (pragState dflags buf loc) False blockSize - where - loc = mkRealSrcLoc (mkFastString filename) 1 1 - - lazyLexBuf :: Handle -> PState -> Bool -> Int -> IO [Located Token] - lazyLexBuf handle state eof size = do - case unP (lexer False return) state of - POk state' t -> do - -- pprTrace "lazyLexBuf" (text (show (buffer state'))) (return ()) - if atEnd (buffer state') && not eof - -- if this token reached the end of the buffer, and we haven't - -- necessarily read up to the end of the file, then the token might - -- be truncated, so read some more of the file and lex it again. - then getMore handle state size - else case unLoc t of - ITeof -> return [t] - _other -> do rest <- lazyLexBuf handle state' eof size - return (t : rest) - _ | not eof -> getMore handle state size - | otherwise -> return [L (mkSrcSpanPs (last_loc state)) ITeof] - -- parser assumes an ITeof sentinel at the end - - getMore :: Handle -> PState -> Int -> IO [Located Token] - getMore handle state size = do - -- pprTrace "getMore" (text (show (buffer state))) (return ()) - let new_size = size * 2 - -- double the buffer size each time we read a new block. This - -- counteracts the quadratic slowdown we otherwise get for very - -- large module names (#5981) - nextbuf <- hGetStringBufferBlock handle new_size - if (len nextbuf == 0) then lazyLexBuf handle state True new_size else do - newbuf <- appendStringBuffers (buffer state) nextbuf - unsafeInterleaveIO $ lazyLexBuf handle state{buffer=newbuf} False new_size - - -getToks :: DynFlags -> FilePath -> StringBuffer -> [Located Token] -getToks dflags filename buf = lexAll (pragState dflags buf loc) - where - loc = mkRealSrcLoc (mkFastString filename) 1 1 - - lexAll state = case unP (lexer False return) state of - POk _ t@(L _ ITeof) -> [t] - POk state' t -> t : lexAll state' - _ -> [L (mkSrcSpanPs (last_loc state)) ITeof] - - --- | Parse OPTIONS and LANGUAGE pragmas of the source file. --- --- Throws a 'SourceError' if flag parsing fails (including unsupported flags.) -getOptions :: DynFlags - -> StringBuffer -- ^ Input Buffer - -> FilePath -- ^ Source filename. Used for location info. - -> [Located String] -- ^ Parsed options. -getOptions dflags buf filename - = getOptions' dflags (getToks dflags filename buf) - --- The token parser is written manually because Happy can't --- return a partial result when it encounters a lexer error. --- We want to extract options before the buffer is passed through --- CPP, so we can't use the same trick as 'getImports'. -getOptions' :: DynFlags - -> [Located Token] -- Input buffer - -> [Located String] -- Options. -getOptions' dflags toks - = parseToks toks - where - parseToks (open:close:xs) - | IToptions_prag str <- unLoc open - , ITclose_prag <- unLoc close - = case toArgs str of - Left _err -> optionsParseError str dflags $ -- #15053 - combineSrcSpans (getLoc open) (getLoc close) - Right args -> map (L (getLoc open)) args ++ parseToks xs - parseToks (open:close:xs) - | ITinclude_prag str <- unLoc open - , ITclose_prag <- unLoc close - = map (L (getLoc open)) ["-#include",removeSpaces str] ++ - parseToks xs - parseToks (open:close:xs) - | ITdocOptions str <- unLoc open - , ITclose_prag <- unLoc close - = map (L (getLoc open)) ["-haddock-opts", removeSpaces str] - ++ parseToks xs - parseToks (open:xs) - | ITlanguage_prag <- unLoc open - = parseLanguage xs - parseToks (comment:xs) -- Skip over comments - | isComment (unLoc comment) - = parseToks xs - parseToks _ = [] - parseLanguage ((L loc (ITconid fs)):rest) - = checkExtension dflags (L loc fs) : - case rest of - (L _loc ITcomma):more -> parseLanguage more - (L _loc ITclose_prag):more -> parseToks more - (L loc _):_ -> languagePragParseError dflags loc - [] -> panic "getOptions'.parseLanguage(1) went past eof token" - parseLanguage (tok:_) - = languagePragParseError dflags (getLoc tok) - parseLanguage [] - = panic "getOptions'.parseLanguage(2) went past eof token" - - isComment :: Token -> Bool - isComment c = - case c of - (ITlineComment {}) -> True - (ITblockComment {}) -> True - (ITdocCommentNext {}) -> True - (ITdocCommentPrev {}) -> True - (ITdocCommentNamed {}) -> True - (ITdocSection {}) -> True - _ -> False - ------------------------------------------------------------------------------ - --- | Complain about non-dynamic flags in OPTIONS pragmas. --- --- Throws a 'SourceError' if the input list is non-empty claiming that the --- input flags are unknown. -checkProcessArgsResult :: MonadIO m => DynFlags -> [Located String] -> m () -checkProcessArgsResult dflags flags - = when (notNull flags) $ - liftIO $ throwIO $ mkSrcErr $ listToBag $ map mkMsg flags - where mkMsg (L loc flag) - = mkPlainErrMsg dflags loc $ - (text "unknown flag in {-# OPTIONS_GHC #-} pragma:" <+> - text flag) - ------------------------------------------------------------------------------ - -checkExtension :: DynFlags -> Located FastString -> Located String -checkExtension dflags (L l ext) --- Checks if a given extension is valid, and if so returns --- its corresponding flag. Otherwise it throws an exception. - = if ext' `elem` supported - then L l ("-X"++ext') - else unsupportedExtnError dflags l ext' - where - ext' = unpackFS ext - supported = supportedLanguagesAndExtensions $ platformMini $ targetPlatform dflags - -languagePragParseError :: DynFlags -> SrcSpan -> a -languagePragParseError dflags loc = - throwErr dflags loc $ - vcat [ text "Cannot parse LANGUAGE pragma" - , text "Expecting comma-separated list of language options," - , text "each starting with a capital letter" - , nest 2 (text "E.g. {-# LANGUAGE TemplateHaskell, GADTs #-}") ] - -unsupportedExtnError :: DynFlags -> SrcSpan -> String -> a -unsupportedExtnError dflags loc unsup = - throwErr dflags loc $ - text "Unsupported extension: " <> text unsup $$ - if null suggestions then Outputable.empty else text "Perhaps you meant" <+> quotedListWithOr (map text suggestions) - where - supported = supportedLanguagesAndExtensions $ platformMini $ targetPlatform dflags - suggestions = fuzzyMatch unsup supported - - -optionsErrorMsgs :: DynFlags -> [String] -> [Located String] -> FilePath -> Messages -optionsErrorMsgs dflags unhandled_flags flags_lines _filename - = (emptyBag, listToBag (map mkMsg unhandled_flags_lines)) - where unhandled_flags_lines :: [Located String] - unhandled_flags_lines = [ L l f - | f <- unhandled_flags - , L l f' <- flags_lines - , f == f' ] - mkMsg (L flagSpan flag) = - ErrUtils.mkPlainErrMsg dflags flagSpan $ - text "unknown flag in {-# OPTIONS_GHC #-} pragma:" <+> text flag - -optionsParseError :: String -> DynFlags -> SrcSpan -> a -- #15053 -optionsParseError str dflags loc = - throwErr dflags loc $ - vcat [ text "Error while parsing OPTIONS_GHC pragma." - , text "Expecting whitespace-separated list of GHC options." - , text " E.g. {-# OPTIONS_GHC -Wall -O2 #-}" - , text ("Input was: " ++ show str) ] - -throwErr :: DynFlags -> SrcSpan -> SDoc -> a -- #15053 -throwErr dflags loc doc = - throw $ mkSrcErr $ unitBag $ mkPlainErrMsg dflags loc doc diff --git a/compiler/main/PlatformConstants.hs b/compiler/main/PlatformConstants.hs deleted file mode 100644 index 96b0f70e6d..0000000000 --- a/compiler/main/PlatformConstants.hs +++ /dev/null @@ -1,17 +0,0 @@ -{-# LANGUAGE CPP #-} - -------------------------------------------------------------------------------- --- --- | Platform constants --- --- (c) The University of Glasgow 2013 --- -------------------------------------------------------------------------------- - -module PlatformConstants (PlatformConstants(..)) where - -import GhcPrelude - --- Produced by deriveConstants -#include "GHCConstantsHaskellType.hs" - diff --git a/compiler/main/Settings.hs b/compiler/main/Settings.hs deleted file mode 100644 index a4e0f8e4a7..0000000000 --- a/compiler/main/Settings.hs +++ /dev/null @@ -1,203 +0,0 @@ -module Settings - ( Settings (..) - , sProgramName - , sProjectVersion - , sGhcUsagePath - , sGhciUsagePath - , sToolDir - , sTopDir - , sTmpDir - , sGlobalPackageDatabasePath - , sLdSupportsCompactUnwind - , sLdSupportsBuildId - , sLdSupportsFilelist - , sLdIsGnuLd - , sGccSupportsNoPie - , sPgm_L - , sPgm_P - , sPgm_F - , sPgm_c - , sPgm_a - , sPgm_l - , sPgm_dll - , sPgm_T - , sPgm_windres - , sPgm_libtool - , sPgm_ar - , sPgm_ranlib - , sPgm_lo - , sPgm_lc - , sPgm_lcc - , sPgm_i - , sOpt_L - , sOpt_P - , sOpt_P_fingerprint - , sOpt_F - , sOpt_c - , sOpt_cxx - , sOpt_a - , sOpt_l - , sOpt_windres - , sOpt_lo - , sOpt_lc - , sOpt_lcc - , sOpt_i - , sExtraGccViaCFlags - , sTargetPlatformString - , sIntegerLibrary - , sIntegerLibraryType - , sGhcWithInterpreter - , sGhcWithNativeCodeGen - , sGhcWithSMP - , sGhcRTSWays - , sTablesNextToCode - , sLeadingUnderscore - , sLibFFI - , sGhcThreaded - , sGhcDebugged - , sGhcRtsWithLibdw - ) where - -import GhcPrelude - -import CliOption -import Fingerprint -import FileSettings -import GhcNameVersion -import GHC.Platform -import PlatformConstants -import ToolSettings - -data Settings = Settings - { sGhcNameVersion :: {-# UNPACk #-} !GhcNameVersion - , sFileSettings :: {-# UNPACK #-} !FileSettings - , sTargetPlatform :: Platform -- Filled in by SysTools - , sToolSettings :: {-# UNPACK #-} !ToolSettings - , sPlatformMisc :: {-# UNPACK #-} !PlatformMisc - , sPlatformConstants :: PlatformConstants - - -- You shouldn't need to look things up in rawSettings directly. - -- They should have their own fields instead. - , sRawSettings :: [(String, String)] - } - ------------------------------------------------------------------------------ --- Accessessors from 'Settings' - -sProgramName :: Settings -> String -sProgramName = ghcNameVersion_programName . sGhcNameVersion -sProjectVersion :: Settings -> String -sProjectVersion = ghcNameVersion_projectVersion . sGhcNameVersion - -sGhcUsagePath :: Settings -> FilePath -sGhcUsagePath = fileSettings_ghcUsagePath . sFileSettings -sGhciUsagePath :: Settings -> FilePath -sGhciUsagePath = fileSettings_ghciUsagePath . sFileSettings -sToolDir :: Settings -> Maybe FilePath -sToolDir = fileSettings_toolDir . sFileSettings -sTopDir :: Settings -> FilePath -sTopDir = fileSettings_topDir . sFileSettings -sTmpDir :: Settings -> String -sTmpDir = fileSettings_tmpDir . sFileSettings -sGlobalPackageDatabasePath :: Settings -> FilePath -sGlobalPackageDatabasePath = fileSettings_globalPackageDatabase . sFileSettings - -sLdSupportsCompactUnwind :: Settings -> Bool -sLdSupportsCompactUnwind = toolSettings_ldSupportsCompactUnwind . sToolSettings -sLdSupportsBuildId :: Settings -> Bool -sLdSupportsBuildId = toolSettings_ldSupportsBuildId . sToolSettings -sLdSupportsFilelist :: Settings -> Bool -sLdSupportsFilelist = toolSettings_ldSupportsFilelist . sToolSettings -sLdIsGnuLd :: Settings -> Bool -sLdIsGnuLd = toolSettings_ldIsGnuLd . sToolSettings -sGccSupportsNoPie :: Settings -> Bool -sGccSupportsNoPie = toolSettings_ccSupportsNoPie . sToolSettings - -sPgm_L :: Settings -> String -sPgm_L = toolSettings_pgm_L . sToolSettings -sPgm_P :: Settings -> (String, [Option]) -sPgm_P = toolSettings_pgm_P . sToolSettings -sPgm_F :: Settings -> String -sPgm_F = toolSettings_pgm_F . sToolSettings -sPgm_c :: Settings -> String -sPgm_c = toolSettings_pgm_c . sToolSettings -sPgm_a :: Settings -> (String, [Option]) -sPgm_a = toolSettings_pgm_a . sToolSettings -sPgm_l :: Settings -> (String, [Option]) -sPgm_l = toolSettings_pgm_l . sToolSettings -sPgm_dll :: Settings -> (String, [Option]) -sPgm_dll = toolSettings_pgm_dll . sToolSettings -sPgm_T :: Settings -> String -sPgm_T = toolSettings_pgm_T . sToolSettings -sPgm_windres :: Settings -> String -sPgm_windres = toolSettings_pgm_windres . sToolSettings -sPgm_libtool :: Settings -> String -sPgm_libtool = toolSettings_pgm_libtool . sToolSettings -sPgm_ar :: Settings -> String -sPgm_ar = toolSettings_pgm_ar . sToolSettings -sPgm_ranlib :: Settings -> String -sPgm_ranlib = toolSettings_pgm_ranlib . sToolSettings -sPgm_lo :: Settings -> (String, [Option]) -sPgm_lo = toolSettings_pgm_lo . sToolSettings -sPgm_lc :: Settings -> (String, [Option]) -sPgm_lc = toolSettings_pgm_lc . sToolSettings -sPgm_lcc :: Settings -> (String, [Option]) -sPgm_lcc = toolSettings_pgm_lcc . sToolSettings -sPgm_i :: Settings -> String -sPgm_i = toolSettings_pgm_i . sToolSettings -sOpt_L :: Settings -> [String] -sOpt_L = toolSettings_opt_L . sToolSettings -sOpt_P :: Settings -> [String] -sOpt_P = toolSettings_opt_P . sToolSettings -sOpt_P_fingerprint :: Settings -> Fingerprint -sOpt_P_fingerprint = toolSettings_opt_P_fingerprint . sToolSettings -sOpt_F :: Settings -> [String] -sOpt_F = toolSettings_opt_F . sToolSettings -sOpt_c :: Settings -> [String] -sOpt_c = toolSettings_opt_c . sToolSettings -sOpt_cxx :: Settings -> [String] -sOpt_cxx = toolSettings_opt_cxx . sToolSettings -sOpt_a :: Settings -> [String] -sOpt_a = toolSettings_opt_a . sToolSettings -sOpt_l :: Settings -> [String] -sOpt_l = toolSettings_opt_l . sToolSettings -sOpt_windres :: Settings -> [String] -sOpt_windres = toolSettings_opt_windres . sToolSettings -sOpt_lo :: Settings -> [String] -sOpt_lo = toolSettings_opt_lo . sToolSettings -sOpt_lc :: Settings -> [String] -sOpt_lc = toolSettings_opt_lc . sToolSettings -sOpt_lcc :: Settings -> [String] -sOpt_lcc = toolSettings_opt_lcc . sToolSettings -sOpt_i :: Settings -> [String] -sOpt_i = toolSettings_opt_i . sToolSettings - -sExtraGccViaCFlags :: Settings -> [String] -sExtraGccViaCFlags = toolSettings_extraGccViaCFlags . sToolSettings - -sTargetPlatformString :: Settings -> String -sTargetPlatformString = platformMisc_targetPlatformString . sPlatformMisc -sIntegerLibrary :: Settings -> String -sIntegerLibrary = platformMisc_integerLibrary . sPlatformMisc -sIntegerLibraryType :: Settings -> IntegerLibrary -sIntegerLibraryType = platformMisc_integerLibraryType . sPlatformMisc -sGhcWithInterpreter :: Settings -> Bool -sGhcWithInterpreter = platformMisc_ghcWithInterpreter . sPlatformMisc -sGhcWithNativeCodeGen :: Settings -> Bool -sGhcWithNativeCodeGen = platformMisc_ghcWithNativeCodeGen . sPlatformMisc -sGhcWithSMP :: Settings -> Bool -sGhcWithSMP = platformMisc_ghcWithSMP . sPlatformMisc -sGhcRTSWays :: Settings -> String -sGhcRTSWays = platformMisc_ghcRTSWays . sPlatformMisc -sTablesNextToCode :: Settings -> Bool -sTablesNextToCode = platformMisc_tablesNextToCode . sPlatformMisc -sLeadingUnderscore :: Settings -> Bool -sLeadingUnderscore = platformMisc_leadingUnderscore . sPlatformMisc -sLibFFI :: Settings -> Bool -sLibFFI = platformMisc_libFFI . sPlatformMisc -sGhcThreaded :: Settings -> Bool -sGhcThreaded = platformMisc_ghcThreaded . sPlatformMisc -sGhcDebugged :: Settings -> Bool -sGhcDebugged = platformMisc_ghcDebugged . sPlatformMisc -sGhcRtsWithLibdw :: Settings -> Bool -sGhcRtsWithLibdw = platformMisc_ghcRtsWithLibdw . sPlatformMisc diff --git a/compiler/main/StaticPtrTable.hs b/compiler/main/StaticPtrTable.hs index fd4b734433..006b6f2b39 100644 --- a/compiler/main/StaticPtrTable.hs +++ b/compiler/main/StaticPtrTable.hs @@ -136,7 +136,7 @@ import GHC.Types.Module import GHC.Types.Name import Outputable import GHC.Platform -import PrelNames +import GHC.Builtin.Names import GHC.Tc.Utils.Env (lookupGlobal) import GHC.Core.Type diff --git a/compiler/main/SysTools.hs b/compiler/main/SysTools.hs deleted file mode 100644 index ea6eb178ee..0000000000 --- a/compiler/main/SysTools.hs +++ /dev/null @@ -1,475 +0,0 @@ -{- ------------------------------------------------------------------------------ --- --- (c) The University of Glasgow 2001-2003 --- --- Access to system tools: gcc, cp, rm etc --- ------------------------------------------------------------------------------ --} - -{-# LANGUAGE CPP, MultiWayIf, ScopedTypeVariables #-} - -module SysTools ( - -- * Initialisation - initSysTools, - lazyInitLlvmConfig, - - -- * Interface to system tools - module SysTools.Tasks, - module SysTools.Info, - - linkDynLib, - - copy, - copyWithHeader, - - -- * General utilities - Option(..), - expandTopDir, - - -- * Platform-specifics - libmLinkOpts, - - -- * Mac OS X frameworks - getPkgFrameworkOpts, - getFrameworkOpts - ) where - -#include "HsVersions.h" - -import GhcPrelude - -import GHC.Settings - -import GHC.Types.Module -import GHC.Driver.Packages -import Outputable -import ErrUtils -import GHC.Platform -import GHC.Driver.Session -import GHC.Driver.Ways - -import Control.Monad.Trans.Except (runExceptT) -import System.FilePath -import System.IO -import System.IO.Unsafe (unsafeInterleaveIO) -import SysTools.ExtraObj -import SysTools.Info -import SysTools.Tasks -import SysTools.BaseDir -import SysTools.Settings -import qualified Data.Set as Set - -{- -Note [How GHC finds toolchain utilities] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -SysTools.initSysProgs figures out exactly where all the auxiliary programs -are, and initialises mutable variables to make it easy to call them. -To do this, it makes use of definitions in Config.hs, which is a Haskell -file containing variables whose value is figured out by the build system. - -Config.hs contains two sorts of things - - cGCC, The *names* of the programs - cCPP e.g. cGCC = gcc - cUNLIT cCPP = gcc -E - etc They do *not* include paths - - - cUNLIT_DIR The *path* to the directory containing unlit, split etc - cSPLIT_DIR *relative* to the root of the build tree, - for use when running *in-place* in a build tree (only) - - ---------------------------------------------- -NOTES for an ALTERNATIVE scheme (i.e *not* what is currently implemented): - -Another hair-brained scheme for simplifying the current tool location -nightmare in GHC: Simon originally suggested using another -configuration file along the lines of GCC's specs file - which is fine -except that it means adding code to read yet another configuration -file. What I didn't notice is that the current package.conf is -general enough to do this: - -Package - {name = "tools", import_dirs = [], source_dirs = [], - library_dirs = [], hs_libraries = [], extra_libraries = [], - include_dirs = [], c_includes = [], package_deps = [], - extra_ghc_opts = ["-pgmc/usr/bin/gcc","-pgml${topdir}/bin/unlit", ... etc.], - extra_cc_opts = [], extra_ld_opts = []} - -Which would have the advantage that we get to collect together in one -place the path-specific package stuff with the path-specific tool -stuff. - End of NOTES ---------------------------------------------- - -************************************************************************ -* * -\subsection{Initialisation} -* * -************************************************************************ --} - --- Note [LLVM configuration] --- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ --- The `llvm-targets` and `llvm-passes` files are shipped with GHC and contain --- information needed by the LLVM backend to invoke `llc` and `opt`. --- Specifically: --- --- * llvm-targets maps autoconf host triples to the corresponding LLVM --- `data-layout` declarations. This information is extracted from clang using --- the script in utils/llvm-targets/gen-data-layout.sh and should be updated --- whenever we target a new version of LLVM. --- --- * llvm-passes maps GHC optimization levels to sets of LLVM optimization --- flags that GHC should pass to `opt`. --- --- This information is contained in files rather the GHC source to allow users --- to add new targets to GHC without having to recompile the compiler. --- --- Since this information is only needed by the LLVM backend we load it lazily --- with unsafeInterleaveIO. Consequently it is important that we lazily pattern --- match on LlvmConfig until we actually need its contents. - -lazyInitLlvmConfig :: String - -> IO LlvmConfig -lazyInitLlvmConfig top_dir - = unsafeInterleaveIO $ do -- see Note [LLVM configuration] - targets <- readAndParse "llvm-targets" mkLlvmTarget - passes <- readAndParse "llvm-passes" id - return $ LlvmConfig { llvmTargets = targets, llvmPasses = passes } - where - readAndParse name builder = - do let llvmConfigFile = top_dir </> name - llvmConfigStr <- readFile llvmConfigFile - case maybeReadFuzzy llvmConfigStr of - Just s -> return (fmap builder <$> s) - Nothing -> pgmError ("Can't parse " ++ show llvmConfigFile) - - mkLlvmTarget :: (String, String, String) -> LlvmTarget - mkLlvmTarget (dl, cpu, attrs) = LlvmTarget dl cpu (words attrs) - - -initSysTools :: String -- TopDir path - -> IO Settings -- Set all the mutable variables above, holding - -- (a) the system programs - -- (b) the package-config file - -- (c) the GHC usage message -initSysTools top_dir = do - res <- runExceptT $ initSettings top_dir - case res of - Right a -> pure a - Left (SettingsError_MissingData msg) -> pgmError msg - Left (SettingsError_BadData msg) -> pgmError msg - -{- Note [Windows stack usage] - -See: #8870 (and #8834 for related info) and #12186 - -On Windows, occasionally we need to grow the stack. In order to do -this, we would normally just bump the stack pointer - but there's a -catch on Windows. - -If the stack pointer is bumped by more than a single page, then the -pages between the initial pointer and the resulting location must be -properly committed by the Windows virtual memory subsystem. This is -only needed in the event we bump by more than one page (i.e 4097 bytes -or more). - -Windows compilers solve this by emitting a call to a special function -called _chkstk, which does this committing of the pages for you. - -The reason this was causing a segfault was because due to the fact the -new code generator tends to generate larger functions, we needed more -stack space in GHC itself. In the x86 codegen, we needed approximately -~12kb of stack space in one go, which caused the process to segfault, -as the intervening pages were not committed. - -GCC can emit such a check for us automatically but only when the flag --fstack-check is used. - -See https://gcc.gnu.org/onlinedocs/gnat_ugn/Stack-Overflow-Checking.html -for more information. - --} - -copy :: DynFlags -> String -> FilePath -> FilePath -> IO () -copy dflags purpose from to = copyWithHeader dflags purpose Nothing from to - -copyWithHeader :: DynFlags -> String -> Maybe String -> FilePath -> FilePath - -> IO () -copyWithHeader dflags purpose maybe_header from to = do - showPass dflags purpose - - hout <- openBinaryFile to WriteMode - hin <- openBinaryFile from ReadMode - ls <- hGetContents hin -- inefficient, but it'll do for now. ToDo: speed up - maybe (return ()) (header hout) maybe_header - hPutStr hout ls - hClose hout - hClose hin - where - -- write the header string in UTF-8. The header is something like - -- {-# LINE "foo.hs" #-} - -- and we want to make sure a Unicode filename isn't mangled. - header h str = do - hSetEncoding h utf8 - hPutStr h str - hSetBinaryMode h True - -{- -************************************************************************ -* * -\subsection{Support code} -* * -************************************************************************ --} - -linkDynLib :: DynFlags -> [String] -> [InstalledUnitId] -> IO () -linkDynLib dflags0 o_files dep_packages - = do - let -- This is a rather ugly hack to fix dynamically linked - -- GHC on Windows. If GHC is linked with -threaded, then - -- it links against libHSrts_thr. But if base is linked - -- against libHSrts, then both end up getting loaded, - -- and things go wrong. We therefore link the libraries - -- with the same RTS flags that we link GHC with. - dflags1 = if platformMisc_ghcThreaded $ platformMisc dflags0 - then addWay' WayThreaded dflags0 - else dflags0 - dflags2 = if platformMisc_ghcDebugged $ platformMisc dflags1 - then addWay' WayDebug dflags1 - else dflags1 - dflags = updateWays dflags2 - - verbFlags = getVerbFlags dflags - o_file = outputFile dflags - - pkgs <- getPreloadPackagesAnd dflags dep_packages - - let pkg_lib_paths = collectLibraryPaths dflags pkgs - let pkg_lib_path_opts = concatMap get_pkg_lib_path_opts pkg_lib_paths - get_pkg_lib_path_opts l - | ( osElfTarget (platformOS (targetPlatform dflags)) || - osMachOTarget (platformOS (targetPlatform dflags)) ) && - dynLibLoader dflags == SystemDependent && - WayDyn `Set.member` ways dflags - = ["-L" ++ l, "-Xlinker", "-rpath", "-Xlinker", l] - -- See Note [-Xlinker -rpath vs -Wl,-rpath] - | otherwise = ["-L" ++ l] - - let lib_paths = libraryPaths dflags - let lib_path_opts = map ("-L"++) lib_paths - - -- We don't want to link our dynamic libs against the RTS package, - -- because the RTS lib comes in several flavours and we want to be - -- able to pick the flavour when a binary is linked. - -- On Windows we need to link the RTS import lib as Windows does - -- not allow undefined symbols. - -- The RTS library path is still added to the library search path - -- above in case the RTS is being explicitly linked in (see #3807). - let platform = targetPlatform dflags - os = platformOS platform - pkgs_no_rts = case os of - OSMinGW32 -> - pkgs - _ -> - filter ((/= rtsUnitId) . packageConfigId) pkgs - let pkg_link_opts = let (package_hs_libs, extra_libs, other_flags) = collectLinkOpts dflags pkgs_no_rts - in package_hs_libs ++ extra_libs ++ other_flags - - -- probably _stub.o files - -- and last temporary shared object file - let extra_ld_inputs = ldInputs dflags - - -- frameworks - pkg_framework_opts <- getPkgFrameworkOpts dflags platform - (map unitId pkgs) - let framework_opts = getFrameworkOpts dflags platform - - case os of - OSMinGW32 -> do - ------------------------------------------------------------- - -- Making a DLL - ------------------------------------------------------------- - let output_fn = case o_file of - Just s -> s - Nothing -> "HSdll.dll" - - runLink dflags ( - map Option verbFlags - ++ [ Option "-o" - , FileOption "" output_fn - , Option "-shared" - ] ++ - [ FileOption "-Wl,--out-implib=" (output_fn ++ ".a") - | gopt Opt_SharedImplib dflags - ] - ++ map (FileOption "") o_files - - -- Permit the linker to auto link _symbol to _imp_symbol - -- This lets us link against DLLs without needing an "import library" - ++ [Option "-Wl,--enable-auto-import"] - - ++ extra_ld_inputs - ++ map Option ( - lib_path_opts - ++ pkg_lib_path_opts - ++ pkg_link_opts - )) - _ | os == OSDarwin -> do - ------------------------------------------------------------------- - -- Making a darwin dylib - ------------------------------------------------------------------- - -- About the options used for Darwin: - -- -dynamiclib - -- Apple's way of saying -shared - -- -undefined dynamic_lookup: - -- Without these options, we'd have to specify the correct - -- dependencies for each of the dylibs. Note that we could - -- (and should) do without this for all libraries except - -- the RTS; all we need to do is to pass the correct - -- HSfoo_dyn.dylib files to the link command. - -- This feature requires Mac OS X 10.3 or later; there is - -- a similar feature, -flat_namespace -undefined suppress, - -- which works on earlier versions, but it has other - -- disadvantages. - -- -single_module - -- Build the dynamic library as a single "module", i.e. no - -- dynamic binding nonsense when referring to symbols from - -- within the library. The NCG assumes that this option is - -- specified (on i386, at least). - -- -install_name - -- Mac OS/X stores the path where a dynamic library is (to - -- be) installed in the library itself. It's called the - -- "install name" of the library. Then any library or - -- executable that links against it before it's installed - -- will search for it in its ultimate install location. - -- By default we set the install name to the absolute path - -- at build time, but it can be overridden by the - -- -dylib-install-name option passed to ghc. Cabal does - -- this. - ------------------------------------------------------------------- - - let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; } - - instName <- case dylibInstallName dflags of - Just n -> return n - Nothing -> return $ "@rpath" `combine` (takeFileName output_fn) - runLink dflags ( - map Option verbFlags - ++ [ Option "-dynamiclib" - , Option "-o" - , FileOption "" output_fn - ] - ++ map Option o_files - ++ [ Option "-undefined", - Option "dynamic_lookup", - Option "-single_module" ] - ++ (if platformArch platform == ArchX86_64 - then [ ] - else [ Option "-Wl,-read_only_relocs,suppress" ]) - ++ [ Option "-install_name", Option instName ] - ++ map Option lib_path_opts - ++ extra_ld_inputs - ++ map Option framework_opts - ++ map Option pkg_lib_path_opts - ++ map Option pkg_link_opts - ++ map Option pkg_framework_opts - ++ [ Option "-Wl,-dead_strip_dylibs" ] - ) - _ -> do - ------------------------------------------------------------------- - -- Making a DSO - ------------------------------------------------------------------- - - let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; } - unregisterised = platformUnregisterised (targetPlatform dflags) - let bsymbolicFlag = -- we need symbolic linking to resolve - -- non-PIC intra-package-relocations for - -- performance (where symbolic linking works) - -- See Note [-Bsymbolic assumptions by GHC] - ["-Wl,-Bsymbolic" | not unregisterised] - - runLink dflags ( - map Option verbFlags - ++ libmLinkOpts - ++ [ Option "-o" - , FileOption "" output_fn - ] - ++ map Option o_files - ++ [ Option "-shared" ] - ++ map Option bsymbolicFlag - -- Set the library soname. We use -h rather than -soname as - -- Solaris 10 doesn't support the latter: - ++ [ Option ("-Wl,-h," ++ takeFileName output_fn) ] - ++ extra_ld_inputs - ++ map Option lib_path_opts - ++ map Option pkg_lib_path_opts - ++ map Option pkg_link_opts - ) - --- | Some platforms require that we explicitly link against @libm@ if any --- math-y things are used (which we assume to include all programs). See #14022. -libmLinkOpts :: [Option] -libmLinkOpts = -#if defined(HAVE_LIBM) - [Option "-lm"] -#else - [] -#endif - -getPkgFrameworkOpts :: DynFlags -> Platform -> [InstalledUnitId] -> IO [String] -getPkgFrameworkOpts dflags platform dep_packages - | platformUsesFrameworks platform = do - pkg_framework_path_opts <- do - pkg_framework_paths <- getPackageFrameworkPath dflags dep_packages - return $ map ("-F" ++) pkg_framework_paths - - pkg_framework_opts <- do - pkg_frameworks <- getPackageFrameworks dflags dep_packages - return $ concat [ ["-framework", fw] | fw <- pkg_frameworks ] - - return (pkg_framework_path_opts ++ pkg_framework_opts) - - | otherwise = return [] - -getFrameworkOpts :: DynFlags -> Platform -> [String] -getFrameworkOpts dflags platform - | platformUsesFrameworks platform = framework_path_opts ++ framework_opts - | otherwise = [] - where - framework_paths = frameworkPaths dflags - framework_path_opts = map ("-F" ++) framework_paths - - frameworks = cmdlineFrameworks dflags - -- reverse because they're added in reverse order from the cmd line: - framework_opts = concat [ ["-framework", fw] - | fw <- reverse frameworks ] - -{- -Note [-Bsymbolic assumptions by GHC] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -GHC has a few assumptions about interaction of relocations in NCG and linker: - -1. -Bsymbolic resolves internal references when the shared library is linked, - which is important for performance. -2. When there is a reference to data in a shared library from the main program, - the runtime linker relocates the data object into the main program using an - R_*_COPY relocation. -3. If we used -Bsymbolic, then this results in multiple copies of the data - object, because some references have already been resolved to point to the - original instance. This is bad! - -We work around [3.] for native compiled code by avoiding the generation of -R_*_COPY relocations. - -Unregisterised compiler can't evade R_*_COPY relocations easily thus we disable --Bsymbolic linking there. - -See related tickets: #4210, #15338 --} diff --git a/compiler/main/SysTools/BaseDir.hs b/compiler/main/SysTools/BaseDir.hs deleted file mode 100644 index c4fc71b502..0000000000 --- a/compiler/main/SysTools/BaseDir.hs +++ /dev/null @@ -1,137 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE ScopedTypeVariables #-} - -{- ------------------------------------------------------------------------------ --- --- (c) The University of Glasgow 2001-2017 --- --- Finding the compiler's base directory. --- ------------------------------------------------------------------------------ --} - -module SysTools.BaseDir - ( expandTopDir, expandToolDir - , findTopDir, findToolDir - , tryFindTopDir - ) where - -#include "HsVersions.h" - -import GhcPrelude - --- See note [Base Dir] for why some of this logic is shared with ghc-pkg. -import GHC.BaseDir - -import Panic - -import System.Environment (lookupEnv) -import System.FilePath - --- Windows -#if defined(mingw32_HOST_OS) -import System.Directory (doesDirectoryExist) -#endif - -#if defined(mingw32_HOST_OS) -# if defined(i386_HOST_ARCH) -# define WINDOWS_CCONV stdcall -# elif defined(x86_64_HOST_ARCH) -# define WINDOWS_CCONV ccall -# else -# error Unknown mingw32 arch -# endif -#endif - -{- -Note [topdir: How GHC finds its files] -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -GHC needs various support files (library packages, RTS etc), plus -various auxiliary programs (cp, gcc, etc). It starts by finding topdir, -the root of GHC's support files - -On Unix: - - ghc always has a shell wrapper that passes a -B<dir> option - -On Windows: - - ghc never has a shell wrapper. - - we can find the location of the ghc binary, which is - $topdir/<foo>/<something>.exe - where <something> may be "ghc", "ghc-stage2", or similar - - we strip off the "<foo>/<something>.exe" to leave $topdir. - -from topdir we can find package.conf, ghc-asm, etc. - - -Note [tooldir: How GHC finds mingw on Windows] - -GHC has some custom logic on Windows for finding the mingw -toolchain and perl. Depending on whether GHC is built -with the make build system or Hadrian, and on whether we're -running a bindist, we might find the mingw toolchain and perl -either under $topdir/../{mingw, perl}/ or -$topdir/../../{mingw, perl}/. - --} - --- | Expand occurrences of the @$tooldir@ interpolation in a string --- on Windows, leave the string untouched otherwise. -expandToolDir :: Maybe FilePath -> String -> String -#if defined(mingw32_HOST_OS) -expandToolDir (Just tool_dir) s = expandPathVar "tooldir" tool_dir s -expandToolDir Nothing _ = panic "Could not determine $tooldir" -#else -expandToolDir _ s = s -#endif - --- | Returns a Unix-format path pointing to TopDir. -findTopDir :: Maybe String -- Maybe TopDir path (without the '-B' prefix). - -> IO String -- TopDir (in Unix format '/' separated) -findTopDir m_minusb = do - maybe_exec_dir <- tryFindTopDir m_minusb - case maybe_exec_dir of - -- "Just" on Windows, "Nothing" on unix - Nothing -> throwGhcExceptionIO $ - InstallationError "missing -B<dir> option" - Just dir -> return dir - -tryFindTopDir - :: Maybe String -- ^ Maybe TopDir path (without the '-B' prefix). - -> IO (Maybe String) -- ^ TopDir (in Unix format '/' separated) -tryFindTopDir (Just minusb) = return $ Just $ normalise minusb -tryFindTopDir Nothing - = do -- The _GHC_TOP_DIR environment variable can be used to specify - -- the top dir when the -B argument is not specified. It is not - -- intended for use by users, it was added specifically for the - -- purpose of running GHC within GHCi. - maybe_env_top_dir <- lookupEnv "_GHC_TOP_DIR" - case maybe_env_top_dir of - Just env_top_dir -> return $ Just env_top_dir - -- Try directory of executable - Nothing -> getBaseDir - - --- See Note [tooldir: How GHC finds mingw and perl on Windows] --- Returns @Nothing@ when not on Windows. --- When called on Windows, it either throws an error when the --- tooldir can't be located, or returns @Just tooldirpath@. -findToolDir - :: FilePath -- ^ topdir - -> IO (Maybe FilePath) -#if defined(mingw32_HOST_OS) -findToolDir top_dir = go 0 (top_dir </> "..") - where maxDepth = 3 - go :: Int -> FilePath -> IO (Maybe FilePath) - go k path - | k == maxDepth = throwGhcExceptionIO $ - InstallationError "could not detect mingw toolchain" - | otherwise = do - oneLevel <- doesDirectoryExist (path </> "mingw") - if oneLevel - then return (Just path) - else go (k+1) (path </> "..") -#else -findToolDir _ = return Nothing -#endif diff --git a/compiler/main/SysTools/ExtraObj.hs b/compiler/main/SysTools/ExtraObj.hs deleted file mode 100644 index 27cc4f7aae..0000000000 --- a/compiler/main/SysTools/ExtraObj.hs +++ /dev/null @@ -1,244 +0,0 @@ ------------------------------------------------------------------------------ --- --- GHC Extra object linking code --- --- (c) The GHC Team 2017 --- ------------------------------------------------------------------------------ - -module SysTools.ExtraObj ( - mkExtraObj, mkExtraObjToLinkIntoBinary, mkNoteObjsToLinkIntoBinary, - checkLinkInfo, getLinkInfo, getCompilerInfo, - ghcLinkInfoSectionName, ghcLinkInfoNoteName, platformSupportsSavingLinkOpts, - haveRtsOptsFlags -) where - -import AsmUtils -import ErrUtils -import GHC.Driver.Session -import GHC.Driver.Packages -import GHC.Platform -import Outputable -import GHC.Types.SrcLoc ( noSrcSpan ) -import GHC.Types.Module -import Elf -import Util -import GhcPrelude - -import Control.Monad -import Data.Maybe - -import Control.Monad.IO.Class - -import FileCleanup -import SysTools.Tasks -import SysTools.Info - -mkExtraObj :: DynFlags -> Suffix -> String -> IO FilePath -mkExtraObj dflags extn xs - = do cFile <- newTempName dflags TFL_CurrentModule extn - oFile <- newTempName dflags TFL_GhcSession "o" - writeFile cFile xs - ccInfo <- liftIO $ getCompilerInfo dflags - runCc Nothing dflags - ([Option "-c", - FileOption "" cFile, - Option "-o", - FileOption "" oFile] - ++ if extn /= "s" - then cOpts - else asmOpts ccInfo) - return oFile - where - -- Pass a different set of options to the C compiler depending one whether - -- we're compiling C or assembler. When compiling C, we pass the usual - -- set of include directories and PIC flags. - cOpts = map Option (picCCOpts dflags) - ++ map (FileOption "-I") - (includeDirs $ getPackageDetails dflags rtsUnitId) - - -- When compiling assembler code, we drop the usual C options, and if the - -- compiler is Clang, we add an extra argument to tell Clang to ignore - -- unused command line options. See trac #11684. - asmOpts ccInfo = - if any (ccInfo ==) [Clang, AppleClang, AppleClang51] - then [Option "-Qunused-arguments"] - else [] - --- When linking a binary, we need to create a C main() function that --- starts everything off. This used to be compiled statically as part --- of the RTS, but that made it hard to change the -rtsopts setting, --- so now we generate and compile a main() stub as part of every --- binary and pass the -rtsopts setting directly to the RTS (#5373) --- --- On Windows, when making a shared library we also may need a DllMain. --- -mkExtraObjToLinkIntoBinary :: DynFlags -> IO FilePath -mkExtraObjToLinkIntoBinary dflags = do - when (gopt Opt_NoHsMain dflags && haveRtsOptsFlags dflags) $ do - putLogMsg dflags NoReason SevInfo noSrcSpan - (defaultUserStyle dflags) - (text "Warning: -rtsopts and -with-rtsopts have no effect with -no-hs-main." $$ - text " Call hs_init_ghc() from your main() function to set these options.") - - mkExtraObj dflags "c" (showSDoc dflags main) - where - main - | gopt Opt_NoHsMain dflags = Outputable.empty - | otherwise - = case ghcLink dflags of - LinkDynLib -> if platformOS (targetPlatform dflags) == OSMinGW32 - then dllMain - else Outputable.empty - _ -> exeMain - - exeMain = vcat [ - text "#include <Rts.h>", - text "extern StgClosure ZCMain_main_closure;", - text "int main(int argc, char *argv[])", - char '{', - text " RtsConfig __conf = defaultRtsConfig;", - text " __conf.rts_opts_enabled = " - <> text (show (rtsOptsEnabled dflags)) <> semi, - text " __conf.rts_opts_suggestions = " - <> text (if rtsOptsSuggestions dflags - then "true" - else "false") <> semi, - text "__conf.keep_cafs = " - <> text (if gopt Opt_KeepCAFs dflags - then "true" - else "false") <> semi, - case rtsOpts dflags of - Nothing -> Outputable.empty - Just opts -> text " __conf.rts_opts= " <> - text (show opts) <> semi, - text " __conf.rts_hs_main = true;", - text " return hs_main(argc,argv,&ZCMain_main_closure,__conf);", - char '}', - char '\n' -- final newline, to keep gcc happy - ] - - dllMain = vcat [ - text "#include <Rts.h>", - text "#include <windows.h>", - text "#include <stdbool.h>", - char '\n', - text "bool", - text "WINAPI", - text "DllMain ( HINSTANCE hInstance STG_UNUSED", - text " , DWORD reason STG_UNUSED", - text " , LPVOID reserved STG_UNUSED", - text " )", - text "{", - text " return true;", - text "}", - char '\n' -- final newline, to keep gcc happy - ] - --- Write out the link info section into a new assembly file. Previously --- this was included as inline assembly in the main.c file but this --- is pretty fragile. gas gets upset trying to calculate relative offsets --- that span the .note section (notably .text) when debug info is present -mkNoteObjsToLinkIntoBinary :: DynFlags -> [InstalledUnitId] -> IO [FilePath] -mkNoteObjsToLinkIntoBinary dflags dep_packages = do - link_info <- getLinkInfo dflags dep_packages - - if (platformSupportsSavingLinkOpts (platformOS platform )) - then fmap (:[]) $ mkExtraObj dflags "s" (showSDoc dflags (link_opts link_info)) - else return [] - - where - platform = targetPlatform dflags - link_opts info = hcat [ - -- "link info" section (see Note [LinkInfo section]) - makeElfNote platform ghcLinkInfoSectionName ghcLinkInfoNoteName 0 info, - - -- ALL generated assembly must have this section to disable - -- executable stacks. See also - -- compiler/nativeGen/AsmCodeGen.hs for another instance - -- where we need to do this. - if platformHasGnuNonexecStack platform - then text ".section .note.GNU-stack,\"\"," - <> sectionType platform "progbits" <> char '\n' - else Outputable.empty - ] - --- | Return the "link info" string --- --- See Note [LinkInfo section] -getLinkInfo :: DynFlags -> [InstalledUnitId] -> IO String -getLinkInfo dflags dep_packages = do - package_link_opts <- getPackageLinkOpts dflags dep_packages - pkg_frameworks <- if platformUsesFrameworks (targetPlatform dflags) - then getPackageFrameworks dflags dep_packages - else return [] - let extra_ld_inputs = ldInputs dflags - let - link_info = (package_link_opts, - pkg_frameworks, - rtsOpts dflags, - rtsOptsEnabled dflags, - gopt Opt_NoHsMain dflags, - map showOpt extra_ld_inputs, - getOpts dflags opt_l) - -- - return (show link_info) - -platformSupportsSavingLinkOpts :: OS -> Bool -platformSupportsSavingLinkOpts os - | os == OSSolaris2 = False -- see #5382 - | otherwise = osElfTarget os - --- See Note [LinkInfo section] -ghcLinkInfoSectionName :: String -ghcLinkInfoSectionName = ".debug-ghc-link-info" - -- if we use the ".debug" prefix, then strip will strip it by default - --- Identifier for the note (see Note [LinkInfo section]) -ghcLinkInfoNoteName :: String -ghcLinkInfoNoteName = "GHC link info" - --- Returns 'False' if it was, and we can avoid linking, because the --- previous binary was linked with "the same options". -checkLinkInfo :: DynFlags -> [InstalledUnitId] -> FilePath -> IO Bool -checkLinkInfo dflags pkg_deps exe_file - | not (platformSupportsSavingLinkOpts (platformOS (targetPlatform dflags))) - -- ToDo: Windows and OS X do not use the ELF binary format, so - -- readelf does not work there. We need to find another way to do - -- this. - = return False -- conservatively we should return True, but not - -- linking in this case was the behaviour for a long - -- time so we leave it as-is. - | otherwise - = do - link_info <- getLinkInfo dflags pkg_deps - debugTraceMsg dflags 3 $ text ("Link info: " ++ link_info) - m_exe_link_info <- readElfNoteAsString dflags exe_file - ghcLinkInfoSectionName ghcLinkInfoNoteName - let sameLinkInfo = (Just link_info == m_exe_link_info) - debugTraceMsg dflags 3 $ case m_exe_link_info of - Nothing -> text "Exe link info: Not found" - Just s - | sameLinkInfo -> text ("Exe link info is the same") - | otherwise -> text ("Exe link info is different: " ++ s) - return (not sameLinkInfo) - -{- Note [LinkInfo section] - ~~~~~~~~~~~~~~~~~~~~~~~ - -The "link info" is a string representing the parameters of the link. We save -this information in the binary, and the next time we link, if nothing else has -changed, we use the link info stored in the existing binary to decide whether -to re-link or not. - -The "link info" string is stored in a ELF section called ".debug-ghc-link-info" -(see ghcLinkInfoSectionName) with the SHT_NOTE type. For some time, it used to -not follow the specified record-based format (see #11022). - --} - -haveRtsOptsFlags :: DynFlags -> Bool -haveRtsOptsFlags dflags = - isJust (rtsOpts dflags) || case rtsOptsEnabled dflags of - RtsOptsSafeOnly -> False - _ -> True diff --git a/compiler/main/SysTools/Info.hs b/compiler/main/SysTools/Info.hs deleted file mode 100644 index b6b74406af..0000000000 --- a/compiler/main/SysTools/Info.hs +++ /dev/null @@ -1,262 +0,0 @@ -{-# LANGUAGE ScopedTypeVariables #-} ------------------------------------------------------------------------------ --- --- Compiler information functions --- --- (c) The GHC Team 2017 --- ------------------------------------------------------------------------------ -module SysTools.Info where - -import Exception -import ErrUtils -import GHC.Driver.Session -import Outputable -import Util - -import Data.List -import Data.IORef - -import System.IO - -import GHC.Platform -import GhcPrelude - -import SysTools.Process - -{- Note [Run-time linker info] - -See also: #5240, #6063, #10110 - -Before 'runLink', we need to be sure to get the relevant information -about the linker we're using at runtime to see if we need any extra -options. For example, GNU ld requires '--reduce-memory-overheads' and -'--hash-size=31' in order to use reasonable amounts of memory (see -trac #5240.) But this isn't supported in GNU gold. - -Generally, the linker changing from what was detected at ./configure -time has always been possible using -pgml, but on Linux it can happen -'transparently' by installing packages like binutils-gold, which -change what /usr/bin/ld actually points to. - -Clang vs GCC notes: - -For gcc, 'gcc -Wl,--version' gives a bunch of output about how to -invoke the linker before the version information string. For 'clang', -the version information for 'ld' is all that's output. For this -reason, we typically need to slurp up all of the standard error output -and look through it. - -Other notes: - -We cache the LinkerInfo inside DynFlags, since clients may link -multiple times. The definition of LinkerInfo is there to avoid a -circular dependency. - --} - -{- Note [ELF needed shared libs] - -Some distributions change the link editor's default handling of -ELF DT_NEEDED tags to include only those shared objects that are -needed to resolve undefined symbols. For Template Haskell we need -the last temporary shared library also if it is not needed for the -currently linked temporary shared library. We specify --no-as-needed -to override the default. This flag exists in GNU ld and GNU gold. - -The flag is only needed on ELF systems. On Windows (PE) and Mac OS X -(Mach-O) the flag is not needed. - --} - -{- Note [Windows static libGCC] - -The GCC versions being upgraded to in #10726 are configured with -dynamic linking of libgcc supported. This results in libgcc being -linked dynamically when a shared library is created. - -This introduces thus an extra dependency on GCC dll that was not -needed before by shared libraries created with GHC. This is a particular -issue on Windows because you get a non-obvious error due to this missing -dependency. This dependent dll is also not commonly on your path. - -For this reason using the static libgcc is preferred as it preserves -the same behaviour that existed before. There are however some very good -reasons to have the shared version as well as described on page 181 of -https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc.pdf : - -"There are several situations in which an application should use the - shared ‘libgcc’ instead of the static version. The most common of these - is when the application wishes to throw and catch exceptions across different - shared libraries. In that case, each of the libraries as well as the application - itself should use the shared ‘libgcc’. " - --} - -neededLinkArgs :: LinkerInfo -> [Option] -neededLinkArgs (GnuLD o) = o -neededLinkArgs (GnuGold o) = o -neededLinkArgs (LlvmLLD o) = o -neededLinkArgs (DarwinLD o) = o -neededLinkArgs (SolarisLD o) = o -neededLinkArgs (AixLD o) = o -neededLinkArgs UnknownLD = [] - --- Grab linker info and cache it in DynFlags. -getLinkerInfo :: DynFlags -> IO LinkerInfo -getLinkerInfo dflags = do - info <- readIORef (rtldInfo dflags) - case info of - Just v -> return v - Nothing -> do - v <- getLinkerInfo' dflags - writeIORef (rtldInfo dflags) (Just v) - return v - --- See Note [Run-time linker info]. -getLinkerInfo' :: DynFlags -> IO LinkerInfo -getLinkerInfo' dflags = do - let platform = targetPlatform dflags - os = platformOS platform - (pgm,args0) = pgm_l dflags - args1 = map Option (getOpts dflags opt_l) - args2 = args0 ++ args1 - args3 = filter notNull (map showOpt args2) - - -- Try to grab the info from the process output. - parseLinkerInfo stdo _stde _exitc - | any ("GNU ld" `isPrefixOf`) stdo = - -- GNU ld specifically needs to use less memory. This especially - -- hurts on small object files. #5240. - -- Set DT_NEEDED for all shared libraries. #10110. - -- TODO: Investigate if these help or hurt when using split sections. - return (GnuLD $ map Option ["-Wl,--hash-size=31", - "-Wl,--reduce-memory-overheads", - -- ELF specific flag - -- see Note [ELF needed shared libs] - "-Wl,--no-as-needed"]) - - | any ("GNU gold" `isPrefixOf`) stdo = - -- GNU gold only needs --no-as-needed. #10110. - -- ELF specific flag, see Note [ELF needed shared libs] - return (GnuGold [Option "-Wl,--no-as-needed"]) - - | any ("LLD" `isPrefixOf`) stdo = - return (LlvmLLD $ map Option [ - -- see Note [ELF needed shared libs] - "-Wl,--no-as-needed"]) - - -- Unknown linker. - | otherwise = fail "invalid --version output, or linker is unsupported" - - -- Process the executable call - info <- catchIO (do - case os of - OSSolaris2 -> - -- Solaris uses its own Solaris linker. Even all - -- GNU C are recommended to configure with Solaris - -- linker instead of using GNU binutils linker. Also - -- all GCC distributed with Solaris follows this rule - -- precisely so we assume here, the Solaris linker is - -- used. - return $ SolarisLD [] - OSAIX -> - -- IBM AIX uses its own non-binutils linker as well - return $ AixLD [] - OSDarwin -> - -- Darwin has neither GNU Gold or GNU LD, but a strange linker - -- that doesn't support --version. We can just assume that's - -- what we're using. - return $ DarwinLD [] - OSMinGW32 -> - -- GHC doesn't support anything but GNU ld on Windows anyway. - -- Process creation is also fairly expensive on win32, so - -- we short-circuit here. - return $ GnuLD $ map Option - [ -- Reduce ld memory usage - "-Wl,--hash-size=31" - , "-Wl,--reduce-memory-overheads" - -- Emit gcc stack checks - -- Note [Windows stack usage] - , "-fstack-check" - -- Force static linking of libGCC - -- Note [Windows static libGCC] - , "-static-libgcc" ] - _ -> do - -- In practice, we use the compiler as the linker here. Pass - -- -Wl,--version to get linker version info. - (exitc, stdo, stde) <- readProcessEnvWithExitCode pgm - (["-Wl,--version"] ++ args3) - c_locale_env - -- Split the output by lines to make certain kinds - -- of processing easier. In particular, 'clang' and 'gcc' - -- have slightly different outputs for '-Wl,--version', but - -- it's still easy to figure out. - parseLinkerInfo (lines stdo) (lines stde) exitc - ) - (\err -> do - debugTraceMsg dflags 2 - (text "Error (figuring out linker information):" <+> - text (show err)) - errorMsg dflags $ hang (text "Warning:") 9 $ - text "Couldn't figure out linker information!" $$ - text "Make sure you're using GNU ld, GNU gold" <+> - text "or the built in OS X linker, etc." - return UnknownLD) - return info - --- Grab compiler info and cache it in DynFlags. -getCompilerInfo :: DynFlags -> IO CompilerInfo -getCompilerInfo dflags = do - info <- readIORef (rtccInfo dflags) - case info of - Just v -> return v - Nothing -> do - v <- getCompilerInfo' dflags - writeIORef (rtccInfo dflags) (Just v) - return v - --- See Note [Run-time linker info]. -getCompilerInfo' :: DynFlags -> IO CompilerInfo -getCompilerInfo' dflags = do - let pgm = pgm_c dflags - -- Try to grab the info from the process output. - parseCompilerInfo _stdo stde _exitc - -- Regular GCC - | any ("gcc version" `isInfixOf`) stde = - return GCC - -- Regular clang - | any ("clang version" `isInfixOf`) stde = - return Clang - -- FreeBSD clang - | any ("FreeBSD clang version" `isInfixOf`) stde = - return Clang - -- Xcode 5.1 clang - | any ("Apple LLVM version 5.1" `isPrefixOf`) stde = - return AppleClang51 - -- Xcode 5 clang - | any ("Apple LLVM version" `isPrefixOf`) stde = - return AppleClang - -- Xcode 4.1 clang - | any ("Apple clang version" `isPrefixOf`) stde = - return AppleClang - -- Unknown linker. - | otherwise = fail "invalid -v output, or compiler is unsupported" - - -- Process the executable call - info <- catchIO (do - (exitc, stdo, stde) <- - readProcessEnvWithExitCode pgm ["-v"] c_locale_env - -- Split the output by lines to make certain kinds - -- of processing easier. - parseCompilerInfo (lines stdo) (lines stde) exitc - ) - (\err -> do - debugTraceMsg dflags 2 - (text "Error (figuring out C compiler information):" <+> - text (show err)) - errorMsg dflags $ hang (text "Warning:") 9 $ - text "Couldn't figure out C compiler information!" $$ - text "Make sure you're using GNU gcc, or clang" - return UnknownCC) - return info diff --git a/compiler/main/SysTools/Process.hs b/compiler/main/SysTools/Process.hs deleted file mode 100644 index eda4b29bc0..0000000000 --- a/compiler/main/SysTools/Process.hs +++ /dev/null @@ -1,387 +0,0 @@ -{-# LANGUAGE CPP #-} ------------------------------------------------------------------------------ --- --- Misc process handling code for SysTools --- --- (c) The GHC Team 2017 --- ------------------------------------------------------------------------------ -module SysTools.Process where - -#include "HsVersions.h" - -import Exception -import ErrUtils -import GHC.Driver.Session -import FastString -import Outputable -import Panic -import GhcPrelude -import Util -import GHC.Types.SrcLoc ( SrcLoc, mkSrcLoc, noSrcSpan, mkSrcSpan ) - -import Control.Concurrent -import Data.Char - -import System.Exit -import System.Environment -import System.FilePath -import System.IO -import System.IO.Error as IO -import System.Process - -import FileCleanup - --- | Enable process jobs support on Windows if it can be expected to work (e.g. --- @process >= 1.6.8.0@). -enableProcessJobs :: CreateProcess -> CreateProcess -#if defined(MIN_VERSION_process) -enableProcessJobs opts = opts { use_process_jobs = True } -#else -enableProcessJobs opts = opts -#endif - --- Similar to System.Process.readCreateProcessWithExitCode, but stderr is --- inherited from the parent process, and output to stderr is not captured. -readCreateProcessWithExitCode' - :: CreateProcess - -> IO (ExitCode, String) -- ^ stdout -readCreateProcessWithExitCode' proc = do - (_, Just outh, _, pid) <- - createProcess proc{ std_out = CreatePipe } - - -- fork off a thread to start consuming the output - output <- hGetContents outh - outMVar <- newEmptyMVar - _ <- forkIO $ evaluate (length output) >> putMVar outMVar () - - -- wait on the output - takeMVar outMVar - hClose outh - - -- wait on the process - ex <- waitForProcess pid - - return (ex, output) - -replaceVar :: (String, String) -> [(String, String)] -> [(String, String)] -replaceVar (var, value) env = - (var, value) : filter (\(var',_) -> var /= var') env - --- | Version of @System.Process.readProcessWithExitCode@ that takes a --- key-value tuple to insert into the environment. -readProcessEnvWithExitCode - :: String -- ^ program path - -> [String] -- ^ program args - -> (String, String) -- ^ addition to the environment - -> IO (ExitCode, String, String) -- ^ (exit_code, stdout, stderr) -readProcessEnvWithExitCode prog args env_update = do - current_env <- getEnvironment - readCreateProcessWithExitCode (enableProcessJobs $ proc prog args) { - env = Just (replaceVar env_update current_env) } "" - --- Don't let gcc localize version info string, #8825 -c_locale_env :: (String, String) -c_locale_env = ("LANGUAGE", "C") - --- If the -B<dir> option is set, add <dir> to PATH. This works around --- a bug in gcc on Windows Vista where it can't find its auxiliary --- binaries (see bug #1110). -getGccEnv :: [Option] -> IO (Maybe [(String,String)]) -getGccEnv opts = - if null b_dirs - then return Nothing - else do env <- getEnvironment - return (Just (mangle_paths env)) - where - (b_dirs, _) = partitionWith get_b_opt opts - - get_b_opt (Option ('-':'B':dir)) = Left dir - get_b_opt other = Right other - - -- Work around #1110 on Windows only (lest we stumble into #17266). -#if defined(mingw32_HOST_OS) - mangle_paths = map mangle_path - mangle_path (path,paths) | map toUpper path == "PATH" - = (path, '\"' : head b_dirs ++ "\";" ++ paths) - mangle_path other = other -#else - mangle_paths = id -#endif - - ------------------------------------------------------------------------------ --- Running an external program - -runSomething :: DynFlags - -> String -- For -v message - -> String -- Command name (possibly a full path) - -- assumed already dos-ified - -> [Option] -- Arguments - -- runSomething will dos-ify them - -> IO () - -runSomething dflags phase_name pgm args = - runSomethingFiltered dflags id phase_name pgm args Nothing Nothing - --- | Run a command, placing the arguments in an external response file. --- --- This command is used in order to avoid overlong command line arguments on --- Windows. The command line arguments are first written to an external, --- temporary response file, and then passed to the linker via @filepath. --- response files for passing them in. See: --- --- https://gcc.gnu.org/wiki/Response_Files --- https://gitlab.haskell.org/ghc/ghc/issues/10777 -runSomethingResponseFile - :: DynFlags -> (String->String) -> String -> String -> [Option] - -> Maybe [(String,String)] -> IO () - -runSomethingResponseFile dflags filter_fn phase_name pgm args mb_env = - runSomethingWith dflags phase_name pgm args $ \real_args -> do - fp <- getResponseFile real_args - let args = ['@':fp] - r <- builderMainLoop dflags filter_fn pgm args Nothing mb_env - return (r,()) - where - getResponseFile args = do - fp <- newTempName dflags TFL_CurrentModule "rsp" - withFile fp WriteMode $ \h -> do -#if defined(mingw32_HOST_OS) - hSetEncoding h latin1 -#else - hSetEncoding h utf8 -#endif - hPutStr h $ unlines $ map escape args - return fp - - -- Note: Response files have backslash-escaping, double quoting, and are - -- whitespace separated (some implementations use newline, others any - -- whitespace character). Therefore, escape any backslashes, newlines, and - -- double quotes in the argument, and surround the content with double - -- quotes. - -- - -- Another possibility that could be considered would be to convert - -- backslashes in the argument to forward slashes. This would generally do - -- the right thing, since backslashes in general only appear in arguments - -- as part of file paths on Windows, and the forward slash is accepted for - -- those. However, escaping is more reliable, in case somehow a backslash - -- appears in a non-file. - escape x = concat - [ "\"" - , concatMap - (\c -> - case c of - '\\' -> "\\\\" - '\n' -> "\\n" - '\"' -> "\\\"" - _ -> [c]) - x - , "\"" - ] - -runSomethingFiltered - :: DynFlags -> (String->String) -> String -> String -> [Option] - -> Maybe FilePath -> Maybe [(String,String)] -> IO () - -runSomethingFiltered dflags filter_fn phase_name pgm args mb_cwd mb_env = do - runSomethingWith dflags phase_name pgm args $ \real_args -> do - r <- builderMainLoop dflags filter_fn pgm real_args mb_cwd mb_env - return (r,()) - -runSomethingWith - :: DynFlags -> String -> String -> [Option] - -> ([String] -> IO (ExitCode, a)) - -> IO a - -runSomethingWith dflags phase_name pgm args io = do - let real_args = filter notNull (map showOpt args) - cmdLine = showCommandForUser pgm real_args - traceCmd dflags phase_name cmdLine $ handleProc pgm phase_name $ io real_args - -handleProc :: String -> String -> IO (ExitCode, r) -> IO r -handleProc pgm phase_name proc = do - (rc, r) <- proc `catchIO` handler - case rc of - ExitSuccess{} -> return r - ExitFailure n -> throwGhcExceptionIO ( - ProgramError ("`" ++ takeFileName pgm ++ "'" ++ - " failed in phase `" ++ phase_name ++ "'." ++ - " (Exit code: " ++ show n ++ ")")) - where - handler err = - if IO.isDoesNotExistError err - then does_not_exist - else throwGhcExceptionIO (ProgramError $ show err) - - does_not_exist = throwGhcExceptionIO (InstallationError ("could not execute: " ++ pgm)) - - -builderMainLoop :: DynFlags -> (String -> String) -> FilePath - -> [String] -> Maybe FilePath -> Maybe [(String, String)] - -> IO ExitCode -builderMainLoop dflags filter_fn pgm real_args mb_cwd mb_env = do - chan <- newChan - - -- We use a mask here rather than a bracket because we want - -- to distinguish between cleaning up with and without an - -- exception. This is to avoid calling terminateProcess - -- unless an exception was raised. - let safely inner = mask $ \restore -> do - -- acquire - -- On Windows due to how exec is emulated the old process will exit and - -- a new process will be created. This means waiting for termination of - -- the parent process will get you in a race condition as the child may - -- not have finished yet. This caused #16450. To fix this use a - -- process job to track all child processes and wait for each one to - -- finish. - let procdata = - enableProcessJobs - $ (proc pgm real_args) { cwd = mb_cwd - , env = mb_env - , std_in = CreatePipe - , std_out = CreatePipe - , std_err = CreatePipe - } - (Just hStdIn, Just hStdOut, Just hStdErr, hProcess) <- restore $ - createProcess_ "builderMainLoop" procdata - let cleanup_handles = do - hClose hStdIn - hClose hStdOut - hClose hStdErr - r <- try $ restore $ do - hSetBuffering hStdOut LineBuffering - hSetBuffering hStdErr LineBuffering - let make_reader_proc h = forkIO $ readerProc chan h filter_fn - bracketOnError (make_reader_proc hStdOut) killThread $ \_ -> - bracketOnError (make_reader_proc hStdErr) killThread $ \_ -> - inner hProcess - case r of - -- onException - Left (SomeException e) -> do - terminateProcess hProcess - cleanup_handles - throw e - -- cleanup when there was no exception - Right s -> do - cleanup_handles - return s - safely $ \h -> do - -- we don't want to finish until 2 streams have been complete - -- (stdout and stderr) - log_loop chan (2 :: Integer) - -- after that, we wait for the process to finish and return the exit code. - waitForProcess h - where - -- t starts at the number of streams we're listening to (2) decrements each - -- time a reader process sends EOF. We are safe from looping forever if a - -- reader thread dies, because they send EOF in a finally handler. - log_loop _ 0 = return () - log_loop chan t = do - msg <- readChan chan - case msg of - BuildMsg msg -> do - putLogMsg dflags NoReason SevInfo noSrcSpan - (defaultUserStyle dflags) msg - log_loop chan t - BuildError loc msg -> do - putLogMsg dflags NoReason SevError (mkSrcSpan loc loc) - (defaultUserStyle dflags) msg - log_loop chan t - EOF -> - log_loop chan (t-1) - -readerProc :: Chan BuildMessage -> Handle -> (String -> String) -> IO () -readerProc chan hdl filter_fn = - (do str <- hGetContents hdl - loop (linesPlatform (filter_fn str)) Nothing) - `finally` - writeChan chan EOF - -- ToDo: check errors more carefully - -- ToDo: in the future, the filter should be implemented as - -- a stream transformer. - where - loop [] Nothing = return () - loop [] (Just err) = writeChan chan err - loop (l:ls) in_err = - case in_err of - Just err@(BuildError srcLoc msg) - | leading_whitespace l -> do - loop ls (Just (BuildError srcLoc (msg $$ text l))) - | otherwise -> do - writeChan chan err - checkError l ls - Nothing -> do - checkError l ls - _ -> panic "readerProc/loop" - - checkError l ls - = case parseError l of - Nothing -> do - writeChan chan (BuildMsg (text l)) - loop ls Nothing - Just (file, lineNum, colNum, msg) -> do - let srcLoc = mkSrcLoc (mkFastString file) lineNum colNum - loop ls (Just (BuildError srcLoc (text msg))) - - leading_whitespace [] = False - leading_whitespace (x:_) = isSpace x - -parseError :: String -> Maybe (String, Int, Int, String) -parseError s0 = case breakColon s0 of - Just (filename, s1) -> - case breakIntColon s1 of - Just (lineNum, s2) -> - case breakIntColon s2 of - Just (columnNum, s3) -> - Just (filename, lineNum, columnNum, s3) - Nothing -> - Just (filename, lineNum, 0, s2) - Nothing -> Nothing - Nothing -> Nothing - --- | Break a line of an error message into a filename and the rest of the line, --- taking care to ignore colons in Windows drive letters (as noted in #17786). --- For instance, --- --- * @"hi.c: ABCD"@ is mapped to @Just ("hi.c", "ABCD")@ --- * @"C:\hi.c: ABCD"@ is mapped to @Just ("C:\hi.c", "ABCD")@ -breakColon :: String -> Maybe (String, String) -breakColon = go [] - where - -- Don't break on Windows drive letters (e.g. @C:\@ or @C:/@) - go accum (':':'\\':rest) = go ('\\':':':accum) rest - go accum (':':'/':rest) = go ('/':':':accum) rest - go accum (':':rest) = Just (reverse accum, rest) - go accum (c:rest) = go (c:accum) rest - go _accum [] = Nothing - -breakIntColon :: String -> Maybe (Int, String) -breakIntColon xs = case break (':' ==) xs of - (ys, _:zs) - | not (null ys) && all isAscii ys && all isDigit ys -> - Just (read ys, zs) - _ -> Nothing - -data BuildMessage - = BuildMsg !SDoc - | BuildError !SrcLoc !SDoc - | EOF - --- Divvy up text stream into lines, taking platform dependent --- line termination into account. -linesPlatform :: String -> [String] -#if !defined(mingw32_HOST_OS) -linesPlatform ls = lines ls -#else -linesPlatform "" = [] -linesPlatform xs = - case lineBreak xs of - (as,xs1) -> as : linesPlatform xs1 - where - lineBreak "" = ("","") - lineBreak ('\r':'\n':xs) = ([],xs) - lineBreak ('\n':xs) = ([],xs) - lineBreak (x:xs) = let (as,bs) = lineBreak xs in (x:as,bs) - -#endif diff --git a/compiler/main/SysTools/Settings.hs b/compiler/main/SysTools/Settings.hs deleted file mode 100644 index 42763f239a..0000000000 --- a/compiler/main/SysTools/Settings.hs +++ /dev/null @@ -1,253 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE ScopedTypeVariables #-} - -module SysTools.Settings - ( SettingsError (..) - , initSettings - ) where - -#include "HsVersions.h" - -import GhcPrelude - -import GHC.Settings - -import Config -import CliOption -import FileSettings -import Fingerprint -import GHC.Platform -import GhcNameVersion -import Outputable -import Settings -import SysTools.BaseDir -import ToolSettings - -import Control.Monad.Trans.Except -import Control.Monad.IO.Class -import qualified Data.Map as Map -import System.FilePath -import System.Directory - -data SettingsError - = SettingsError_MissingData String - | SettingsError_BadData String - -initSettings - :: forall m - . MonadIO m - => String -- ^ TopDir path - -> ExceptT SettingsError m Settings -initSettings top_dir = do - -- see Note [topdir: How GHC finds its files] - -- NB: top_dir is assumed to be in standard Unix - -- format, '/' separated - mtool_dir <- liftIO $ findToolDir top_dir - -- see Note [tooldir: How GHC finds mingw on Windows] - - let installed :: FilePath -> FilePath - installed file = top_dir </> file - libexec :: FilePath -> FilePath - libexec file = top_dir </> "bin" </> file - settingsFile = installed "settings" - platformConstantsFile = installed "platformConstants" - - readFileSafe :: FilePath -> ExceptT SettingsError m String - readFileSafe path = liftIO (doesFileExist path) >>= \case - True -> liftIO $ readFile path - False -> throwE $ SettingsError_MissingData $ "Missing file: " ++ path - - settingsStr <- readFileSafe settingsFile - platformConstantsStr <- readFileSafe platformConstantsFile - settingsList <- case maybeReadFuzzy settingsStr of - Just s -> pure s - Nothing -> throwE $ SettingsError_BadData $ - "Can't parse " ++ show settingsFile - let mySettings = Map.fromList settingsList - platformConstants <- case maybeReadFuzzy platformConstantsStr of - Just s -> pure s - Nothing -> throwE $ SettingsError_BadData $ - "Can't parse " ++ show platformConstantsFile - -- See Note [Settings file] for a little more about this file. We're - -- just partially applying those functions and throwing 'Left's; they're - -- written in a very portable style to keep ghc-boot light. - let getSetting key = either pgmError pure $ - getFilePathSetting0 top_dir settingsFile mySettings key - getToolSetting :: String -> ExceptT SettingsError m String - getToolSetting key = expandToolDir mtool_dir <$> getSetting key - getBooleanSetting :: String -> ExceptT SettingsError m Bool - getBooleanSetting key = either pgmError pure $ - getBooleanSetting0 settingsFile mySettings key - targetPlatformString <- getSetting "target platform string" - tablesNextToCode <- getBooleanSetting "Tables next to code" - myExtraGccViaCFlags <- getSetting "GCC extra via C opts" - -- On Windows, mingw is distributed with GHC, - -- so we look in TopDir/../mingw/bin, - -- as well as TopDir/../../mingw/bin for hadrian. - -- It would perhaps be nice to be able to override this - -- with the settings file, but it would be a little fiddly - -- to make that possible, so for now you can't. - cc_prog <- getToolSetting "C compiler command" - cc_args_str <- getSetting "C compiler flags" - cxx_args_str <- getSetting "C++ compiler flags" - gccSupportsNoPie <- getBooleanSetting "C compiler supports -no-pie" - cpp_prog <- getToolSetting "Haskell CPP command" - cpp_args_str <- getSetting "Haskell CPP flags" - - platform <- either pgmError pure $ getTargetPlatform settingsFile mySettings - - let unreg_cc_args = if platformUnregisterised platform - then ["-DNO_REGS", "-DUSE_MINIINTERPRETER"] - else [] - cpp_args = map Option (words cpp_args_str) - cc_args = words cc_args_str ++ unreg_cc_args - cxx_args = words cxx_args_str - ldSupportsCompactUnwind <- getBooleanSetting "ld supports compact unwind" - ldSupportsBuildId <- getBooleanSetting "ld supports build-id" - ldSupportsFilelist <- getBooleanSetting "ld supports filelist" - ldIsGnuLd <- getBooleanSetting "ld is GNU ld" - - let globalpkgdb_path = installed "package.conf.d" - ghc_usage_msg_path = installed "ghc-usage.txt" - ghci_usage_msg_path = installed "ghci-usage.txt" - - -- For all systems, unlit, split, mangle are GHC utilities - -- architecture-specific stuff is done when building Config.hs - unlit_path <- getToolSetting "unlit command" - - windres_path <- getToolSetting "windres command" - libtool_path <- getToolSetting "libtool command" - ar_path <- getToolSetting "ar command" - ranlib_path <- getToolSetting "ranlib command" - - -- TODO this side-effect doesn't belong here. Reading and parsing the settings - -- should be idempotent and accumulate no resources. - tmpdir <- liftIO $ getTemporaryDirectory - - touch_path <- getToolSetting "touch command" - - mkdll_prog <- getToolSetting "dllwrap command" - let mkdll_args = [] - - -- cpp is derived from gcc on all platforms - -- HACK, see setPgmP below. We keep 'words' here to remember to fix - -- Config.hs one day. - - - -- Other things being equal, as and ld are simply gcc - cc_link_args_str <- getSetting "C compiler link flags" - let as_prog = cc_prog - as_args = map Option cc_args - ld_prog = cc_prog - ld_args = map Option (cc_args ++ words cc_link_args_str) - - llvmTarget <- getSetting "LLVM target" - - -- We just assume on command line - lc_prog <- getSetting "LLVM llc command" - lo_prog <- getSetting "LLVM opt command" - lcc_prog <- getSetting "LLVM clang command" - - let iserv_prog = libexec "ghc-iserv" - - integerLibrary <- getSetting "integer library" - integerLibraryType <- case integerLibrary of - "integer-gmp" -> pure IntegerGMP - "integer-simple" -> pure IntegerSimple - _ -> pgmError $ unwords - [ "Entry for" - , show "integer library" - , "must be one of" - , show "integer-gmp" - , "or" - , show "integer-simple" - ] - - ghcWithInterpreter <- getBooleanSetting "Use interpreter" - ghcWithNativeCodeGen <- getBooleanSetting "Use native code generator" - ghcWithSMP <- getBooleanSetting "Support SMP" - ghcRTSWays <- getSetting "RTS ways" - leadingUnderscore <- getBooleanSetting "Leading underscore" - useLibFFI <- getBooleanSetting "Use LibFFI" - ghcThreaded <- getBooleanSetting "Use Threads" - ghcDebugged <- getBooleanSetting "Use Debugging" - ghcRtsWithLibdw <- getBooleanSetting "RTS expects libdw" - - return $ Settings - { sGhcNameVersion = GhcNameVersion - { ghcNameVersion_programName = "ghc" - , ghcNameVersion_projectVersion = cProjectVersion - } - - , sFileSettings = FileSettings - { fileSettings_tmpDir = normalise tmpdir - , fileSettings_ghcUsagePath = ghc_usage_msg_path - , fileSettings_ghciUsagePath = ghci_usage_msg_path - , fileSettings_toolDir = mtool_dir - , fileSettings_topDir = top_dir - , fileSettings_globalPackageDatabase = globalpkgdb_path - } - - , sToolSettings = ToolSettings - { toolSettings_ldSupportsCompactUnwind = ldSupportsCompactUnwind - , toolSettings_ldSupportsBuildId = ldSupportsBuildId - , toolSettings_ldSupportsFilelist = ldSupportsFilelist - , toolSettings_ldIsGnuLd = ldIsGnuLd - , toolSettings_ccSupportsNoPie = gccSupportsNoPie - - , toolSettings_pgm_L = unlit_path - , toolSettings_pgm_P = (cpp_prog, cpp_args) - , toolSettings_pgm_F = "" - , toolSettings_pgm_c = cc_prog - , toolSettings_pgm_a = (as_prog, as_args) - , toolSettings_pgm_l = (ld_prog, ld_args) - , toolSettings_pgm_dll = (mkdll_prog,mkdll_args) - , toolSettings_pgm_T = touch_path - , toolSettings_pgm_windres = windres_path - , toolSettings_pgm_libtool = libtool_path - , toolSettings_pgm_ar = ar_path - , toolSettings_pgm_ranlib = ranlib_path - , toolSettings_pgm_lo = (lo_prog,[]) - , toolSettings_pgm_lc = (lc_prog,[]) - , toolSettings_pgm_lcc = (lcc_prog,[]) - , toolSettings_pgm_i = iserv_prog - , toolSettings_opt_L = [] - , toolSettings_opt_P = [] - , toolSettings_opt_P_fingerprint = fingerprint0 - , toolSettings_opt_F = [] - , toolSettings_opt_c = cc_args - , toolSettings_opt_cxx = cxx_args - , toolSettings_opt_a = [] - , toolSettings_opt_l = [] - , toolSettings_opt_windres = [] - , toolSettings_opt_lcc = [] - , toolSettings_opt_lo = [] - , toolSettings_opt_lc = [] - , toolSettings_opt_i = [] - - , toolSettings_extraGccViaCFlags = words myExtraGccViaCFlags - } - - , sTargetPlatform = platform - , sPlatformMisc = PlatformMisc - { platformMisc_targetPlatformString = targetPlatformString - , platformMisc_integerLibrary = integerLibrary - , platformMisc_integerLibraryType = integerLibraryType - , platformMisc_ghcWithInterpreter = ghcWithInterpreter - , platformMisc_ghcWithNativeCodeGen = ghcWithNativeCodeGen - , platformMisc_ghcWithSMP = ghcWithSMP - , platformMisc_ghcRTSWays = ghcRTSWays - , platformMisc_tablesNextToCode = tablesNextToCode - , platformMisc_leadingUnderscore = leadingUnderscore - , platformMisc_libFFI = useLibFFI - , platformMisc_ghcThreaded = ghcThreaded - , platformMisc_ghcDebugged = ghcDebugged - , platformMisc_ghcRtsWithLibdw = ghcRtsWithLibdw - , platformMisc_llvmTarget = llvmTarget - } - - , sPlatformConstants = platformConstants - - , sRawSettings = settingsList - } diff --git a/compiler/main/SysTools/Tasks.hs b/compiler/main/SysTools/Tasks.hs deleted file mode 100644 index e4bbb32dc6..0000000000 --- a/compiler/main/SysTools/Tasks.hs +++ /dev/null @@ -1,373 +0,0 @@ -{-# LANGUAGE ScopedTypeVariables #-} ------------------------------------------------------------------------------ --- --- Tasks running external programs for SysTools --- --- (c) The GHC Team 2017 --- ------------------------------------------------------------------------------ -module SysTools.Tasks where - -import Exception -import ErrUtils -import GHC.Driver.Types -import GHC.Driver.Session -import Outputable -import GHC.Platform -import Util - -import Data.List - -import System.IO -import System.Process -import GhcPrelude - -import GHC.CmmToLlvm.Base (LlvmVersion, llvmVersionStr, supportedLlvmVersion, parseLlvmVersion) - -import SysTools.Process -import SysTools.Info - -{- -************************************************************************ -* * -\subsection{Running an external program} -* * -************************************************************************ --} - -runUnlit :: DynFlags -> [Option] -> IO () -runUnlit dflags args = traceToolCommand dflags "unlit" $ do - let prog = pgm_L dflags - opts = getOpts dflags opt_L - runSomething dflags "Literate pre-processor" prog - (map Option opts ++ args) - -runCpp :: DynFlags -> [Option] -> IO () -runCpp dflags args = traceToolCommand dflags "cpp" $ do - let (p,args0) = pgm_P dflags - args1 = map Option (getOpts dflags opt_P) - args2 = [Option "-Werror" | gopt Opt_WarnIsError dflags] - ++ [Option "-Wundef" | wopt Opt_WarnCPPUndef dflags] - mb_env <- getGccEnv args2 - runSomethingFiltered dflags id "C pre-processor" p - (args0 ++ args1 ++ args2 ++ args) Nothing mb_env - -runPp :: DynFlags -> [Option] -> IO () -runPp dflags args = traceToolCommand dflags "pp" $ do - let prog = pgm_F dflags - opts = map Option (getOpts dflags opt_F) - runSomething dflags "Haskell pre-processor" prog (args ++ opts) - --- | Run compiler of C-like languages and raw objects (such as gcc or clang). -runCc :: Maybe ForeignSrcLang -> DynFlags -> [Option] -> IO () -runCc mLanguage dflags args = traceToolCommand dflags "cc" $ do - let p = pgm_c dflags - args1 = map Option userOpts - args2 = languageOptions ++ args ++ args1 - -- We take care to pass -optc flags in args1 last to ensure that the - -- user can override flags passed by GHC. See #14452. - mb_env <- getGccEnv args2 - runSomethingResponseFile dflags cc_filter "C Compiler" p args2 mb_env - where - -- discard some harmless warnings from gcc that we can't turn off - cc_filter = unlines . doFilter . lines - - {- - gcc gives warnings in chunks like so: - In file included from /foo/bar/baz.h:11, - from /foo/bar/baz2.h:22, - from wibble.c:33: - /foo/flibble:14: global register variable ... - /foo/flibble:15: warning: call-clobbered r... - We break it up into its chunks, remove any call-clobbered register - warnings from each chunk, and then delete any chunks that we have - emptied of warnings. - -} - doFilter = unChunkWarnings . filterWarnings . chunkWarnings [] - -- We can't assume that the output will start with an "In file inc..." - -- line, so we start off expecting a list of warnings rather than a - -- location stack. - chunkWarnings :: [String] -- The location stack to use for the next - -- list of warnings - -> [String] -- The remaining lines to look at - -> [([String], [String])] - chunkWarnings loc_stack [] = [(loc_stack, [])] - chunkWarnings loc_stack xs - = case break loc_stack_start xs of - (warnings, lss:xs') -> - case span loc_start_continuation xs' of - (lsc, xs'') -> - (loc_stack, warnings) : chunkWarnings (lss : lsc) xs'' - _ -> [(loc_stack, xs)] - - filterWarnings :: [([String], [String])] -> [([String], [String])] - filterWarnings [] = [] - -- If the warnings are already empty then we are probably doing - -- something wrong, so don't delete anything - filterWarnings ((xs, []) : zs) = (xs, []) : filterWarnings zs - filterWarnings ((xs, ys) : zs) = case filter wantedWarning ys of - [] -> filterWarnings zs - ys' -> (xs, ys') : filterWarnings zs - - unChunkWarnings :: [([String], [String])] -> [String] - unChunkWarnings [] = [] - unChunkWarnings ((xs, ys) : zs) = xs ++ ys ++ unChunkWarnings zs - - loc_stack_start s = "In file included from " `isPrefixOf` s - loc_start_continuation s = " from " `isPrefixOf` s - wantedWarning w - | "warning: call-clobbered register used" `isContainedIn` w = False - | otherwise = True - - -- force the C compiler to interpret this file as C when - -- compiling .hc files, by adding the -x c option. - -- Also useful for plain .c files, just in case GHC saw a - -- -x c option. - (languageOptions, userOpts) = case mLanguage of - Nothing -> ([], userOpts_c) - Just language -> ([Option "-x", Option languageName], opts) - where - (languageName, opts) = case language of - LangC -> ("c", userOpts_c) - LangCxx -> ("c++", userOpts_cxx) - LangObjc -> ("objective-c", userOpts_c) - LangObjcxx -> ("objective-c++", userOpts_cxx) - LangAsm -> ("assembler", []) - RawObject -> ("c", []) -- claim C for lack of a better idea - userOpts_c = getOpts dflags opt_c - userOpts_cxx = getOpts dflags opt_cxx - -isContainedIn :: String -> String -> Bool -xs `isContainedIn` ys = any (xs `isPrefixOf`) (tails ys) - --- | Run the linker with some arguments and return the output -askLd :: DynFlags -> [Option] -> IO String -askLd dflags args = traceToolCommand dflags "linker" $ do - let (p,args0) = pgm_l dflags - args1 = map Option (getOpts dflags opt_l) - args2 = args0 ++ args1 ++ args - mb_env <- getGccEnv args2 - runSomethingWith dflags "gcc" p args2 $ \real_args -> - readCreateProcessWithExitCode' (proc p real_args){ env = mb_env } - -runAs :: DynFlags -> [Option] -> IO () -runAs dflags args = traceToolCommand dflags "as" $ do - let (p,args0) = pgm_a dflags - args1 = map Option (getOpts dflags opt_a) - args2 = args0 ++ args1 ++ args - mb_env <- getGccEnv args2 - runSomethingFiltered dflags id "Assembler" p args2 Nothing mb_env - --- | Run the LLVM Optimiser -runLlvmOpt :: DynFlags -> [Option] -> IO () -runLlvmOpt dflags args = traceToolCommand dflags "opt" $ do - let (p,args0) = pgm_lo dflags - args1 = map Option (getOpts dflags opt_lo) - -- We take care to pass -optlo flags (e.g. args0) last to ensure that the - -- user can override flags passed by GHC. See #14821. - runSomething dflags "LLVM Optimiser" p (args1 ++ args ++ args0) - --- | Run the LLVM Compiler -runLlvmLlc :: DynFlags -> [Option] -> IO () -runLlvmLlc dflags args = traceToolCommand dflags "llc" $ do - let (p,args0) = pgm_lc dflags - args1 = map Option (getOpts dflags opt_lc) - runSomething dflags "LLVM Compiler" p (args0 ++ args1 ++ args) - --- | Run the clang compiler (used as an assembler for the LLVM --- backend on OS X as LLVM doesn't support the OS X system --- assembler) -runClang :: DynFlags -> [Option] -> IO () -runClang dflags args = traceToolCommand dflags "clang" $ do - let (clang,_) = pgm_lcc dflags - -- be careful what options we call clang with - -- see #5903 and #7617 for bugs caused by this. - (_,args0) = pgm_a dflags - args1 = map Option (getOpts dflags opt_a) - args2 = args0 ++ args1 ++ args - mb_env <- getGccEnv args2 - Exception.catch (do - runSomethingFiltered dflags id "Clang (Assembler)" clang args2 Nothing mb_env - ) - (\(err :: SomeException) -> do - errorMsg dflags $ - text ("Error running clang! you need clang installed to use the" ++ - " LLVM backend") $+$ - text "(or GHC tried to execute clang incorrectly)" - throwIO err - ) - --- | Figure out which version of LLVM we are running this session -figureLlvmVersion :: DynFlags -> IO (Maybe LlvmVersion) -figureLlvmVersion dflags = traceToolCommand dflags "llc" $ do - let (pgm,opts) = pgm_lc dflags - args = filter notNull (map showOpt opts) - -- we grab the args even though they should be useless just in - -- case the user is using a customised 'llc' that requires some - -- of the options they've specified. llc doesn't care what other - -- options are specified when '-version' is used. - args' = args ++ ["-version"] - catchIO (do - (pin, pout, perr, _) <- runInteractiveProcess pgm args' - Nothing Nothing - {- > llc -version - LLVM (http://llvm.org/): - LLVM version 3.5.2 - ... - -} - hSetBinaryMode pout False - _ <- hGetLine pout - vline <- hGetLine pout - let mb_ver = parseLlvmVersion vline - hClose pin - hClose pout - hClose perr - return mb_ver - ) - (\err -> do - debugTraceMsg dflags 2 - (text "Error (figuring out LLVM version):" <+> - text (show err)) - errorMsg dflags $ vcat - [ text "Warning:", nest 9 $ - text "Couldn't figure out LLVM version!" $$ - text ("Make sure you have installed LLVM " ++ - llvmVersionStr supportedLlvmVersion) ] - return Nothing) - - -runLink :: DynFlags -> [Option] -> IO () -runLink dflags args = traceToolCommand dflags "linker" $ do - -- See Note [Run-time linker info] - -- - -- `-optl` args come at the end, so that later `-l` options - -- given there manually can fill in symbols needed by - -- Haskell libraries coming in via `args`. - linkargs <- neededLinkArgs `fmap` getLinkerInfo dflags - let (p,args0) = pgm_l dflags - optl_args = map Option (getOpts dflags opt_l) - args2 = args0 ++ linkargs ++ args ++ optl_args - mb_env <- getGccEnv args2 - runSomethingResponseFile dflags ld_filter "Linker" p args2 mb_env - where - ld_filter = case (platformOS (targetPlatform dflags)) of - OSSolaris2 -> sunos_ld_filter - _ -> id -{- - SunOS/Solaris ld emits harmless warning messages about unresolved - symbols in case of compiling into shared library when we do not - link against all the required libs. That is the case of GHC which - does not link against RTS library explicitly in order to be able to - choose the library later based on binary application linking - parameters. The warnings look like: - -Undefined first referenced - symbol in file -stg_ap_n_fast ./T2386_Lib.o -stg_upd_frame_info ./T2386_Lib.o -templatezmhaskell_LanguageziHaskellziTHziLib_litE_closure ./T2386_Lib.o -templatezmhaskell_LanguageziHaskellziTHziLib_appE_closure ./T2386_Lib.o -templatezmhaskell_LanguageziHaskellziTHziLib_conE_closure ./T2386_Lib.o -templatezmhaskell_LanguageziHaskellziTHziSyntax_mkNameGzud_closure ./T2386_Lib.o -newCAF ./T2386_Lib.o -stg_bh_upd_frame_info ./T2386_Lib.o -stg_ap_ppp_fast ./T2386_Lib.o -templatezmhaskell_LanguageziHaskellziTHziLib_stringL_closure ./T2386_Lib.o -stg_ap_p_fast ./T2386_Lib.o -stg_ap_pp_fast ./T2386_Lib.o -ld: warning: symbol referencing errors - - this is actually coming from T2386 testcase. The emitting of those - warnings is also a reason why so many TH testcases fail on Solaris. - - Following filter code is SunOS/Solaris linker specific and should - filter out only linker warnings. Please note that the logic is a - little bit more complex due to the simple reason that we need to preserve - any other linker emitted messages. If there are any. Simply speaking - if we see "Undefined" and later "ld: warning:..." then we omit all - text between (including) the marks. Otherwise we copy the whole output. --} - sunos_ld_filter :: String -> String - sunos_ld_filter = unlines . sunos_ld_filter' . lines - sunos_ld_filter' x = if (undefined_found x && ld_warning_found x) - then (ld_prefix x) ++ (ld_postfix x) - else x - breakStartsWith x y = break (isPrefixOf x) y - ld_prefix = fst . breakStartsWith "Undefined" - undefined_found = not . null . snd . breakStartsWith "Undefined" - ld_warn_break = breakStartsWith "ld: warning: symbol referencing errors" - ld_postfix = tail . snd . ld_warn_break - ld_warning_found = not . null . snd . ld_warn_break - - -runLibtool :: DynFlags -> [Option] -> IO () -runLibtool dflags args = traceToolCommand dflags "libtool" $ do - linkargs <- neededLinkArgs `fmap` getLinkerInfo dflags - let args1 = map Option (getOpts dflags opt_l) - args2 = [Option "-static"] ++ args1 ++ args ++ linkargs - libtool = pgm_libtool dflags - mb_env <- getGccEnv args2 - runSomethingFiltered dflags id "Linker" libtool args2 Nothing mb_env - -runAr :: DynFlags -> Maybe FilePath -> [Option] -> IO () -runAr dflags cwd args = traceToolCommand dflags "ar" $ do - let ar = pgm_ar dflags - runSomethingFiltered dflags id "Ar" ar args cwd Nothing - -askAr :: DynFlags -> Maybe FilePath -> [Option] -> IO String -askAr dflags mb_cwd args = traceToolCommand dflags "ar" $ do - let ar = pgm_ar dflags - runSomethingWith dflags "Ar" ar args $ \real_args -> - readCreateProcessWithExitCode' (proc ar real_args){ cwd = mb_cwd } - -runRanlib :: DynFlags -> [Option] -> IO () -runRanlib dflags args = traceToolCommand dflags "ranlib" $ do - let ranlib = pgm_ranlib dflags - runSomethingFiltered dflags id "Ranlib" ranlib args Nothing Nothing - -runMkDLL :: DynFlags -> [Option] -> IO () -runMkDLL dflags args = traceToolCommand dflags "mkdll" $ do - let (p,args0) = pgm_dll dflags - args1 = args0 ++ args - mb_env <- getGccEnv (args0++args) - runSomethingFiltered dflags id "Make DLL" p args1 Nothing mb_env - -runWindres :: DynFlags -> [Option] -> IO () -runWindres dflags args = traceToolCommand dflags "windres" $ do - let cc = pgm_c dflags - cc_args = map Option (sOpt_c (settings dflags)) - windres = pgm_windres dflags - opts = map Option (getOpts dflags opt_windres) - quote x = "\"" ++ x ++ "\"" - args' = -- If windres.exe and gcc.exe are in a directory containing - -- spaces then windres fails to run gcc. We therefore need - -- to tell it what command to use... - Option ("--preprocessor=" ++ - unwords (map quote (cc : - map showOpt opts ++ - ["-E", "-xc", "-DRC_INVOKED"]))) - -- ...but if we do that then if windres calls popen then - -- it can't understand the quoting, so we have to use - -- --use-temp-file so that it interprets it correctly. - -- See #1828. - : Option "--use-temp-file" - : args - mb_env <- getGccEnv cc_args - runSomethingFiltered dflags id "Windres" windres args' Nothing mb_env - -touch :: DynFlags -> String -> String -> IO () -touch dflags purpose arg = traceToolCommand dflags "touch" $ - runSomething dflags purpose (pgm_T dflags) [FileOption "" arg] - --- * Tracing utility - --- | Record in the eventlog when the given tool command starts --- and finishes, prepending the given 'String' with --- \"systool:\", to easily be able to collect and process --- all the systool events. --- --- For those events to show up in the eventlog, you need --- to run GHC with @-v2@ or @-ddump-timings@. -traceToolCommand :: DynFlags -> String -> IO a -> IO a -traceToolCommand dflags tool = withTiming - dflags (text $ "systool:" ++ tool) (const ()) diff --git a/compiler/main/SysTools/Terminal.hs b/compiler/main/SysTools/Terminal.hs deleted file mode 100644 index 162dd32010..0000000000 --- a/compiler/main/SysTools/Terminal.hs +++ /dev/null @@ -1,104 +0,0 @@ -{-# LANGUAGE CPP #-} -{-# LANGUAGE ScopedTypeVariables #-} -module SysTools.Terminal (stderrSupportsAnsiColors) where - -import GhcPrelude - -#if defined(MIN_VERSION_terminfo) -import Control.Exception (catch) -import Data.Maybe (fromMaybe) -import System.Console.Terminfo (SetupTermError, Terminal, getCapability, - setupTermFromEnv, termColors) -import System.Posix (queryTerminal, stdError) -#elif defined(mingw32_HOST_OS) -import Control.Exception (catch, try) -import Data.Bits ((.|.), (.&.)) -import Foreign (Ptr, peek, with) -import qualified Graphics.Win32 as Win32 -import qualified System.Win32 as Win32 -#endif - -import System.IO.Unsafe - -#if defined(mingw32_HOST_OS) && !defined(WINAPI) -# if defined(i386_HOST_ARCH) -# define WINAPI stdcall -# elif defined(x86_64_HOST_ARCH) -# define WINAPI ccall -# else -# error unknown architecture -# endif -#endif - --- | Does the controlling terminal support ANSI color sequences? --- This memoized to avoid thread-safety issues in ncurses (see #17922). -stderrSupportsAnsiColors :: Bool -stderrSupportsAnsiColors = unsafePerformIO stderrSupportsAnsiColors' -{-# NOINLINE stderrSupportsAnsiColors #-} - --- | Check if ANSI escape sequences can be used to control color in stderr. -stderrSupportsAnsiColors' :: IO Bool -stderrSupportsAnsiColors' = do -#if defined(MIN_VERSION_terminfo) - stderr_available <- queryTerminal stdError - if stderr_available then - fmap termSupportsColors setupTermFromEnv - `catch` \ (_ :: SetupTermError) -> pure False - else - pure False - where - termSupportsColors :: Terminal -> Bool - termSupportsColors term = fromMaybe 0 (getCapability term termColors) > 0 - -#elif defined(mingw32_HOST_OS) - h <- Win32.getStdHandle Win32.sTD_ERROR_HANDLE - `catch` \ (_ :: IOError) -> - pure Win32.nullHANDLE - if h == Win32.nullHANDLE - then pure False - else do - eMode <- try (getConsoleMode h) - case eMode of - Left (_ :: IOError) -> Win32.isMinTTYHandle h - -- Check if the we're in a MinTTY terminal - -- (e.g., Cygwin or MSYS2) - Right mode - | modeHasVTP mode -> pure True - | otherwise -> enableVTP h mode - - where - - enableVTP :: Win32.HANDLE -> Win32.DWORD -> IO Bool - enableVTP h mode = do - setConsoleMode h (modeAddVTP mode) - modeHasVTP <$> getConsoleMode h - `catch` \ (_ :: IOError) -> - pure False - - modeHasVTP :: Win32.DWORD -> Bool - modeHasVTP mode = mode .&. eNABLE_VIRTUAL_TERMINAL_PROCESSING /= 0 - - modeAddVTP :: Win32.DWORD -> Win32.DWORD - modeAddVTP mode = mode .|. eNABLE_VIRTUAL_TERMINAL_PROCESSING - -eNABLE_VIRTUAL_TERMINAL_PROCESSING :: Win32.DWORD -eNABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 - -getConsoleMode :: Win32.HANDLE -> IO Win32.DWORD -getConsoleMode h = with 64 $ \ mode -> do - Win32.failIfFalse_ "GetConsoleMode" (c_GetConsoleMode h mode) - peek mode - -setConsoleMode :: Win32.HANDLE -> Win32.DWORD -> IO () -setConsoleMode h mode = do - Win32.failIfFalse_ "SetConsoleMode" (c_SetConsoleMode h mode) - -foreign import WINAPI unsafe "windows.h GetConsoleMode" c_GetConsoleMode - :: Win32.HANDLE -> Ptr Win32.DWORD -> IO Win32.BOOL - -foreign import WINAPI unsafe "windows.h SetConsoleMode" c_SetConsoleMode - :: Win32.HANDLE -> Win32.DWORD -> IO Win32.BOOL - -#else - pure False -#endif diff --git a/compiler/main/ToolSettings.hs b/compiler/main/ToolSettings.hs deleted file mode 100644 index 82d125b5f6..0000000000 --- a/compiler/main/ToolSettings.hs +++ /dev/null @@ -1,64 +0,0 @@ -module ToolSettings - ( ToolSettings (..) - ) where - -import GhcPrelude - -import CliOption -import Fingerprint - --- | Settings for other executables GHC calls. --- --- Probably should further split down by phase, or split between --- platform-specific and platform-agnostic. -data ToolSettings = ToolSettings - { toolSettings_ldSupportsCompactUnwind :: Bool - , toolSettings_ldSupportsBuildId :: Bool - , toolSettings_ldSupportsFilelist :: Bool - , toolSettings_ldIsGnuLd :: Bool - , toolSettings_ccSupportsNoPie :: Bool - - -- commands for particular phases - , toolSettings_pgm_L :: String - , toolSettings_pgm_P :: (String, [Option]) - , toolSettings_pgm_F :: String - , toolSettings_pgm_c :: String - , toolSettings_pgm_a :: (String, [Option]) - , toolSettings_pgm_l :: (String, [Option]) - , toolSettings_pgm_dll :: (String, [Option]) - , toolSettings_pgm_T :: String - , toolSettings_pgm_windres :: String - , toolSettings_pgm_libtool :: String - , toolSettings_pgm_ar :: String - , toolSettings_pgm_ranlib :: String - , -- | LLVM: opt llvm optimiser - toolSettings_pgm_lo :: (String, [Option]) - , -- | LLVM: llc static compiler - toolSettings_pgm_lc :: (String, [Option]) - , -- | LLVM: c compiler - toolSettings_pgm_lcc :: (String, [Option]) - , toolSettings_pgm_i :: String - - -- options for particular phases - , toolSettings_opt_L :: [String] - , toolSettings_opt_P :: [String] - , -- | cached Fingerprint of sOpt_P - -- See Note [Repeated -optP hashing] - toolSettings_opt_P_fingerprint :: Fingerprint - , toolSettings_opt_F :: [String] - , toolSettings_opt_c :: [String] - , toolSettings_opt_cxx :: [String] - , toolSettings_opt_a :: [String] - , toolSettings_opt_l :: [String] - , toolSettings_opt_windres :: [String] - , -- | LLVM: llvm optimiser - toolSettings_opt_lo :: [String] - , -- | LLVM: llc static compiler - toolSettings_opt_lc :: [String] - , -- | LLVM: c compiler - toolSettings_opt_lcc :: [String] - , -- | iserv options - toolSettings_opt_i :: [String] - - , toolSettings_extraGccViaCFlags :: [String] - } |