Skip to content

Commit f3ae87f

Browse files
authored
Merge pull request #3327 from commercialhaskell/849-unify-flags-ghc-options
Promote packages to local database by ghc-options #849
2 parents 09de319 + f5801f4 commit f3ae87f

File tree

7 files changed

+59
-69
lines changed

7 files changed

+59
-69
lines changed

ChangeLog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ Behavior changes:
2626
paths. TH relative paths will still work when loading a single
2727
package into intero. See
2828
[#3309](https://github.com/commercialhaskell/stack/issues/3309)
29+
* Setting GHC options for a package via `ghc-options:` in your
30+
`stack.yaml` will promote it to a local package, providing for more
31+
consistency with flags and better reproducibility. See:
32+
[#849](https://github.com/commercialhaskell/stack/issues/849)
2933

3034
Other enhancements:
3135

doc/yaml_configuration.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -503,10 +503,17 @@ ghc-options:
503503
some-package: -DSOME_CPP_FLAG
504504
```
505505

506-
Caveat emptor: setting options like this will affect your snapshot packages,
507-
which can lead to unpredictable behavior versus official Stackage snapshots.
508-
This is in contrast to the `ghc-options` command line flag, which will only
509-
affect the packages specified by the [`apply-ghc-options` option](yaml_configuration.md#apply-ghc-options).
506+
Since 0.1.6, setting a GHC options for a specific package will
507+
automatically promote it to a local package (much like setting a
508+
custom package flag). However, setting options via `"*"` on all flags
509+
will not do so (see
510+
[Github discussion](https://github.com/commercialhaskell/stack/issues/849#issuecomment-320892095)
511+
for reasoning). This can lead to unpredicable behavior by affecting
512+
your snapshot packages.
513+
514+
By contrast, the `ghc-options` command line flag will only affect the
515+
packages specified by the
516+
[`apply-ghc-options` option](yaml_configuration.md#apply-ghc-options).
510517

511518
### apply-ghc-options
512519

src/Stack/Build/Source.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,12 @@ loadSourceMapFull needTargets boptsCli = do
9292
[ Map.fromList $ map (\lp' -> (packageName $ lpPackage lp', PSLocal lp')) locals
9393
, flip Map.mapWithKey localDeps $ \n lpi ->
9494
let configOpts = getGhcOptions bconfig boptsCli n False False
95-
in PSUpstream (lpiVersion lpi) Local (lpiFlags lpi) (lpiGhcOptions lpi ++ configOpts) (lpiLocation lpi)
95+
-- NOTE: configOpts includes lpiGhcOptions for now, this may get refactored soon
96+
in PSUpstream (lpiVersion lpi) Local (lpiFlags lpi) configOpts (lpiLocation lpi)
9697
, flip Map.mapWithKey (lsPackages ls) $ \n lpi ->
9798
let configOpts = getGhcOptions bconfig boptsCli n False False
98-
in PSUpstream (lpiVersion lpi) Snap (lpiFlags lpi) (lpiGhcOptions lpi ++ configOpts) (lpiLocation lpi)
99+
-- NOTE: configOpts includes lpiGhcOptions for now, this may get refactored soon
100+
in PSUpstream (lpiVersion lpi) Snap (lpiFlags lpi) configOpts (lpiLocation lpi)
99101
]
100102
`Map.difference` Map.fromList (map (, ()) (HashSet.toList wiredInPackages))
101103

@@ -125,7 +127,8 @@ getLocalFlags bconfig boptsCli name = Map.unions
125127
-- configuration and commandline.
126128
getGhcOptions :: BuildConfig -> BuildOptsCLI -> PackageName -> Bool -> Bool -> [Text]
127129
getGhcOptions bconfig boptsCli name isTarget isLocal = concat
128-
[ ghcOptionsFor name (configGhcOptions config)
130+
[ Map.findWithDefault [] name (configGhcOptionsByName config)
131+
, configGhcOptionsAll config
129132
, concat [["-fhpc"] | isLocal && toCoverage (boptsTestOpts bopts)]
130133
, if boptsLibProfile bopts || boptsExeProfile bopts
131134
then ["-auto-all","-caf-all"]

src/Stack/Build/Target.hs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -522,16 +522,12 @@ parseTargets needTargets boptscli = do
522522
(bcFlags bconfig)
523523
hides = Map.empty -- not supported to add hidden packages
524524

525-
-- We set this to empty here, which will prevent the call to
526-
-- calculatePackagePromotion from promoting packages based on
527-
-- changed GHC options. This is probably not ideal behavior,
528-
-- but is consistent with pre-extensible-snapshots behavior of
529-
-- Stack. We can consider modifying this instead.
525+
-- We promote packages to the local database if the GHC options
526+
-- are added to them by name. See:
527+
-- https://github.com/commercialhaskell/stack/issues/849#issuecomment-320892095.
530528
--
531-
-- Nonetheless, GHC options will be calculated later based on
532-
-- config file and command line parameters, so we're not
533-
-- actually losing them.
534-
options = Map.empty
529+
-- GHC options applied to all packages are handled by getGhcOptions.
530+
options = configGhcOptionsByName (bcConfig bconfig)
535531

536532
drops = Set.empty -- not supported to add drops
537533

src/Stack/Config.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,8 @@ configFromConfigMonoid
358358

359359
let configTemplateParams = configMonoidTemplateParameters
360360
configScmInit = getFirst configMonoidScmInit
361-
configGhcOptions = configMonoidGhcOptions
361+
configGhcOptionsByName = configMonoidGhcOptionsByName
362+
configGhcOptionsAll = configMonoidGhcOptionsAll
362363
configSetupInfoLocations = configMonoidSetupInfoLocations
363364
configPvpBounds = fromFirst (PvpBounds PvpBoundsNone False) configMonoidPvpBounds
364365
configModifyCodePage = fromFirst True configMonoidModifyCodePage

src/Stack/Ghci.hs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,10 +301,8 @@ runGhci GhciOpts{..} targets mainIsTargets pkgs extraFiles = do
301301
genOpts = nubOrd (concatMap (concatMap (oneWordOpts . snd) . ghciPkgOpts) pkgs)
302302
(omittedOpts, ghcOpts) = partition badForGhci $
303303
concatMap (concatMap (bioOpts . snd) . ghciPkgOpts) pkgs ++
304-
getUserOptions Nothing ++
305-
concatMap (getUserOptions . Just . ghciPkgName) pkgs
306-
getUserOptions mpkg =
307-
map T.unpack (M.findWithDefault [] mpkg (unGhcOptions (configGhcOptions config)))
304+
map T.unpack (configGhcOptionsAll config ++ concatMap (getUserOptions . ghciPkgName) pkgs)
305+
getUserOptions pkg = M.findWithDefault [] pkg (configGhcOptionsByName config)
308306
badForGhci x =
309307
isPrefixOf "-O" x || elem x (words "-debug -threaded -ticky -static -Werror")
310308
unless (null omittedOpts) $

src/Stack/Types/Config.hs

Lines changed: 29 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@ module Stack.Types.Config
104104
,readColorWhen
105105
-- ** SCM
106106
,SCM(..)
107-
-- ** GhcOptions
108-
,GhcOptions(..)
109-
,ghcOptionsFor
110107
-- * Paths
111108
,bindirSuffix
112109
,configInstalledCache
@@ -172,11 +169,11 @@ module Stack.Types.Config
172169

173170
import Stack.Prelude
174171
import Data.Aeson.Extended
175-
(ToJSON, toJSON, FromJSON, parseJSON, withText, object,
172+
(ToJSON, toJSON, FromJSON, FromJSONKey (..), parseJSON, withText, object,
176173
(.=), (..:), (..:?), (..!=), Value(Bool, String),
177174
withObjectWarnings, WarningParser, Object, jsonSubWarnings,
178-
jsonSubWarningsT, jsonSubWarningsTT, WithJSONWarnings(..), noJSONWarnings)
179-
import Data.Attoparsec.Args
175+
jsonSubWarningsT, jsonSubWarningsTT, WithJSONWarnings(..), noJSONWarnings,
176+
FromJSONKeyFunction (FromJSONKeyTextParser))
180177
import qualified Data.ByteString.Char8 as S8
181178
import Data.List (stripPrefix)
182179
import Data.List.NonEmpty (NonEmpty)
@@ -314,9 +311,10 @@ data Config =
314311
-- ^ Parameters for templates.
315312
,configScmInit :: !(Maybe SCM)
316313
-- ^ Initialize SCM (e.g. git) when creating new projects.
317-
,configGhcOptions :: !GhcOptions
318-
-- ^ Additional GHC options to apply to either all packages (Nothing)
319-
-- or a specific package (Just).
314+
,configGhcOptionsByName :: !(Map PackageName [Text])
315+
-- ^ Additional GHC options to apply to specific packages.
316+
,configGhcOptionsAll :: ![Text]
317+
-- ^ Additional GHC options to apply to all packages
320318
,configSetupInfoLocations :: ![SetupInfoLocation]
321319
-- ^ Additional SetupInfo (inline or remote) to use to find tools.
322320
,configPvpBounds :: !PvpBounds
@@ -709,8 +707,10 @@ data ConfigMonoid =
709707
-- ^ Template parameters.
710708
,configMonoidScmInit :: !(First SCM)
711709
-- ^ Initialize SCM (e.g. git init) when making new projects?
712-
,configMonoidGhcOptions :: !GhcOptions
713-
-- ^ See 'configGhcOptions'
710+
,configMonoidGhcOptionsByName :: !(Map PackageName [Text])
711+
-- ^ See 'configGhcOptionsByName'
712+
,configMonoidGhcOptionsAll :: ![Text]
713+
-- ^ See 'configGhcOptionsAll'
714714
,configMonoidExtraPath :: ![Path Abs Dir]
715715
-- ^ Additional paths to search for executables in
716716
,configMonoidSetupInfoLocations :: ![SetupInfoLocation]
@@ -795,6 +795,14 @@ parseConfigMonoidObject rootDir obj = do
795795
configMonoidCompilerCheck <- First <$> obj ..:? configMonoidCompilerCheckName
796796

797797
configMonoidGhcOptions <- obj ..:? configMonoidGhcOptionsName ..!= mempty
798+
let configMonoidGhcOptionsByName = Map.unions (map
799+
(\(mname, opts) ->
800+
case mname of
801+
GOKAll -> Map.empty
802+
GOKPackage name -> Map.singleton name opts)
803+
(Map.toList configMonoidGhcOptions))
804+
configMonoidGhcOptionsAll = Map.findWithDefault [] GOKAll configMonoidGhcOptions
805+
798806
configMonoidExtraPath <- obj ..:? configMonoidExtraPathName ..!= []
799807
configMonoidSetupInfoLocations <-
800808
maybeToList <$> jsonSubWarningsT (obj ..:? configMonoidSetupInfoLocationsName)
@@ -1713,43 +1721,16 @@ data DockerUser = DockerUser
17131721
, duUmask :: FileMode -- ^ File creation mask }
17141722
} deriving (Read,Show)
17151723

1716-
newtype GhcOptions = GhcOptions
1717-
{ unGhcOptions :: Map (Maybe PackageName) [Text] }
1718-
deriving Show
1719-
1720-
instance FromJSON GhcOptions where
1721-
parseJSON val = do
1722-
ghcOptions <- parseJSON val
1723-
fmap (GhcOptions . Map.fromList) $ mapM handleGhcOptions $ Map.toList ghcOptions
1724-
where
1725-
handleGhcOptions :: Monad m => (Text, Text) -> m (Maybe PackageName, [Text])
1726-
handleGhcOptions (name', vals') = do
1727-
name <-
1728-
if name' == "*"
1729-
then return Nothing
1730-
else case parsePackageNameFromString $ T.unpack name' of
1731-
Left e -> fail $ show e
1732-
Right x -> return $ Just x
1733-
1734-
case parseArgs Escaping vals' of
1735-
Left e -> fail e
1736-
Right vals -> return (name, map T.pack vals)
1737-
1738-
instance Monoid GhcOptions where
1739-
mempty = GhcOptions mempty
1740-
-- FIXME: Should GhcOptions really monoid like this? Keeping it this
1741-
-- way preserves the behavior of the ConfigMonoid. However, this
1742-
-- means there isn't the ability to fully override snapshot
1743-
-- ghc-options in the same way there is for flags. Do we want to
1744-
-- change the semantics here? (particularly for extensible
1745-
-- snapshots)
1746-
mappend (GhcOptions l) (GhcOptions r) =
1747-
GhcOptions (Map.unionWith (++) l r)
1748-
1749-
ghcOptionsFor :: PackageName -> GhcOptions -> [Text]
1750-
ghcOptionsFor name (GhcOptions mp) =
1751-
M.findWithDefault [] Nothing mp ++
1752-
M.findWithDefault [] (Just name) mp
1724+
data GhcOptionKey = GOKAll | GOKPackage !PackageName
1725+
deriving (Eq, Ord)
1726+
instance FromJSONKey GhcOptionKey where
1727+
fromJSONKey = FromJSONKeyTextParser $ \t ->
1728+
if t == "*"
1729+
then return GOKAll
1730+
else case parsePackageName t of
1731+
Left e -> fail $ show e
1732+
Right x -> return $ GOKPackage x
1733+
fromJSONKeyList = FromJSONKeyTextParser $ \_ -> fail "GhcOptionKey.fromJSONKeyList"
17531734

17541735
-----------------------------------
17551736
-- Lens classes

0 commit comments

Comments
 (0)