diff --git a/Cabal-syntax/src/Distribution/PackageDescription/FieldGrammar.hs b/Cabal-syntax/src/Distribution/PackageDescription/FieldGrammar.hs
index db6b7f7607b5bba2f2956ef05c9d16aa3a52b665..4d9ada935afb51b0d607baac6417e361193d420e 100644
--- a/Cabal-syntax/src/Distribution/PackageDescription/FieldGrammar.hs
+++ b/Cabal-syntax/src/Distribution/PackageDescription/FieldGrammar.hs
@@ -673,6 +673,7 @@ buildInfoFieldGrammar =
     <*> optionsFieldGrammar
     <*> profOptionsFieldGrammar
     <*> sharedOptionsFieldGrammar
+    <*> profSharedOptionsFieldGrammar
     <*> pure mempty -- static-options ???
     <*> prefixedFields "x-" L.customFieldsBI
     <*> monoidalFieldAla "build-depends" formatDependencyList L.targetBuildDepends
@@ -738,6 +739,19 @@ sharedOptionsFieldGrammar =
     extract :: CompilerFlavor -> ALens' BuildInfo [String]
     extract flavor = L.sharedOptions . lookupLens flavor
 
+profSharedOptionsFieldGrammar
+  :: (FieldGrammar c g, Applicative (g BuildInfo), c (List NoCommaFSep Token' String))
+  => g BuildInfo (PerCompilerFlavor [String])
+profSharedOptionsFieldGrammar =
+  PerCompilerFlavor
+    <$> monoidalFieldAla "ghc-prof-shared-options" (alaList' NoCommaFSep Token') (extract GHC)
+      ^^^ availableSince CabalSpecV3_14 []
+    <*> monoidalFieldAla "ghcjs-prof-shared-options" (alaList' NoCommaFSep Token') (extract GHCJS)
+      ^^^ availableSince CabalSpecV3_14 []
+  where
+    extract :: CompilerFlavor -> ALens' BuildInfo [String]
+    extract flavor = L.profSharedOptions . lookupLens flavor
+
 lookupLens :: (Functor f, Monoid v) => CompilerFlavor -> LensLike' f (PerCompilerFlavor v) v
 lookupLens k f p@(PerCompilerFlavor ghc ghcjs)
   | k == GHC = (\n -> PerCompilerFlavor n ghcjs) <$> f ghc
diff --git a/Cabal-syntax/src/Distribution/Types/BuildInfo.hs b/Cabal-syntax/src/Distribution/Types/BuildInfo.hs
index da1f8aea88f09243f19e4303b3560d7a85ef54cc..680b9bf49dbb99486859cb702a2f5f7b0bbe6620 100644
--- a/Cabal-syntax/src/Distribution/Types/BuildInfo.hs
+++ b/Cabal-syntax/src/Distribution/Types/BuildInfo.hs
@@ -12,6 +12,7 @@ module Distribution.Types.BuildInfo
   , hcOptions
   , hcProfOptions
   , hcSharedOptions
+  , hcProfSharedOptions
   , hcStaticOptions
   ) where
 
@@ -133,6 +134,7 @@ data BuildInfo = BuildInfo
   , options :: PerCompilerFlavor [String]
   , profOptions :: PerCompilerFlavor [String]
   , sharedOptions :: PerCompilerFlavor [String]
+  , profSharedOptions :: PerCompilerFlavor [String]
   , staticOptions :: PerCompilerFlavor [String]
   , customFieldsBI :: [(String, String)]
   -- ^ Custom fields starting
@@ -193,6 +195,7 @@ instance Monoid BuildInfo where
       , options = mempty
       , profOptions = mempty
       , sharedOptions = mempty
+      , profSharedOptions = mempty
       , staticOptions = mempty
       , customFieldsBI = []
       , targetBuildDepends = []
@@ -245,6 +248,7 @@ instance Semigroup BuildInfo where
       , options = combine options
       , profOptions = combine profOptions
       , sharedOptions = combine sharedOptions
+      , profSharedOptions = combine profSharedOptions
       , staticOptions = combine staticOptions
       , customFieldsBI = combine customFieldsBI
       , targetBuildDepends = combineNub targetBuildDepends
@@ -295,6 +299,9 @@ hcProfOptions = lookupHcOptions profOptions
 hcSharedOptions :: CompilerFlavor -> BuildInfo -> [String]
 hcSharedOptions = lookupHcOptions sharedOptions
 
+hcProfSharedOptions :: CompilerFlavor -> BuildInfo -> [String]
+hcProfSharedOptions = lookupHcOptions profSharedOptions
+
 hcStaticOptions :: CompilerFlavor -> BuildInfo -> [String]
 hcStaticOptions = lookupHcOptions staticOptions
 
diff --git a/Cabal-syntax/src/Distribution/Types/BuildInfo/Lens.hs b/Cabal-syntax/src/Distribution/Types/BuildInfo/Lens.hs
index 19453a671b967b7dbeee91978a4b0e42d674f15d..ac99f3c65a57837bf0e9fe25af19e4814db556c3 100644
--- a/Cabal-syntax/src/Distribution/Types/BuildInfo/Lens.hs
+++ b/Cabal-syntax/src/Distribution/Types/BuildInfo/Lens.hs
@@ -195,6 +195,10 @@ class HasBuildInfo a where
   sharedOptions = buildInfo . sharedOptions
   {-# INLINE sharedOptions #-}
 
+  profSharedOptions :: Lens' a (PerCompilerFlavor [String])
+  profSharedOptions = buildInfo . profSharedOptions
+  {-# INLINE profSharedOptions #-}
+
   staticOptions :: Lens' a (PerCompilerFlavor [String])
   staticOptions = buildInfo . staticOptions
   {-# INLINE staticOptions #-}
@@ -341,6 +345,9 @@ instance HasBuildInfo BuildInfo where
   sharedOptions f s = fmap (\x -> s{T.sharedOptions = x}) (f (T.sharedOptions s))
   {-# INLINE sharedOptions #-}
 
+  profSharedOptions f s = fmap (\x -> s{T.profSharedOptions = x}) (f (T.profSharedOptions s))
+  {-# INLINE profSharedOptions #-}
+
   staticOptions f s = fmap (\x -> s{T.staticOptions = x}) (f (T.staticOptions s))
   {-# INLINE staticOptions #-}
 
diff --git a/Cabal-tests/tests/ParserTests/regressions/Octree-0.5.expr b/Cabal-tests/tests/ParserTests/regressions/Octree-0.5.expr
index 3d03421210bbeaecf439218a1743e8471e5cad1b..b3494104aede3a2ca929050f8ca4b815468332a1 100644
--- a/Cabal-tests/tests/ParserTests/regressions/Octree-0.5.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/Octree-0.5.expr
@@ -132,6 +132,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -238,6 +240,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -339,6 +343,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/anynone.expr b/Cabal-tests/tests/ParserTests/regressions/anynone.expr
index 3191425d609d54bd56008b3e7d5ba52cc24203c3..8c9c8879ab48f1d638415e7351d0c9e2a8fb4ed0 100644
--- a/Cabal-tests/tests/ParserTests/regressions/anynone.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/anynone.expr
@@ -95,6 +95,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/big-version.expr b/Cabal-tests/tests/ParserTests/regressions/big-version.expr
index e677de2062672f65ce5cffd66a3c812110b34d8a..d4ef82adf5291a6625b3a3d14f40a3c481a12369 100644
--- a/Cabal-tests/tests/ParserTests/regressions/big-version.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/big-version.expr
@@ -96,6 +96,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/common-conditional.expr b/Cabal-tests/tests/ParserTests/regressions/common-conditional.expr
index f6ffe291e59dd8507b39982d8b6a128790360d7b..9cacba2b7702bb2599ff971c3530c0d71f72e00f 100644
--- a/Cabal-tests/tests/ParserTests/regressions/common-conditional.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/common-conditional.expr
@@ -112,6 +112,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -187,6 +189,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -278,6 +282,8 @@ GenericPackageDescription {
                         [],
                       sharedOptions =
                       PerCompilerFlavor [] [],
+                      profSharedOptions =
+                      PerCompilerFlavor [] [],
                       staticOptions =
                       PerCompilerFlavor [] [],
                       customFieldsBI = [],
@@ -356,6 +362,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -432,6 +440,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -501,6 +511,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -593,6 +605,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
@@ -670,6 +684,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/common.expr b/Cabal-tests/tests/ParserTests/regressions/common.expr
index e0eb4a1dde7e9b352ae7d74f4e3267b7a476b97f..25abadef9e7b8b4729ab3102da444e6e5b491705 100644
--- a/Cabal-tests/tests/ParserTests/regressions/common.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/common.expr
@@ -110,6 +110,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -186,6 +188,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/common2.expr b/Cabal-tests/tests/ParserTests/regressions/common2.expr
index b3cb004eecb059086678cfe7c340da930a57b535..cd501d11cf22677252f10e9e9ce6120bd1c669d0 100644
--- a/Cabal-tests/tests/ParserTests/regressions/common2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/common2.expr
@@ -106,6 +106,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -205,6 +207,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -285,6 +289,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -386,6 +392,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -462,6 +470,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -562,6 +572,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -639,6 +651,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -716,6 +730,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/common3.expr b/Cabal-tests/tests/ParserTests/regressions/common3.expr
index 21b200baa7bf1072419fcbef070c6a7f9c03c7c8..fc1fc155c09af01dae5cf6a91b8bcd4ec94eb307 100644
--- a/Cabal-tests/tests/ParserTests/regressions/common3.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/common3.expr
@@ -110,6 +110,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -186,6 +188,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/elif.expr b/Cabal-tests/tests/ParserTests/regressions/elif.expr
index 1315d6894676372cd68f41d2ef5c795b93e39ce0..f17c1e17b88f5236c92aa1278f5d42ef367977d7 100644
--- a/Cabal-tests/tests/ParserTests/regressions/elif.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/elif.expr
@@ -105,6 +105,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -172,6 +174,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/elif2.expr b/Cabal-tests/tests/ParserTests/regressions/elif2.expr
index 61f2177cbaad94df4394100b1117bd102c2d48ed..ec01a92a79d582a8cd10bf3f6daae47f821842ae 100644
--- a/Cabal-tests/tests/ParserTests/regressions/elif2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/elif2.expr
@@ -105,6 +105,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -172,6 +174,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -245,6 +249,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -312,6 +318,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
@@ -385,6 +393,8 @@ GenericPackageDescription {
                             [],
                           sharedOptions =
                           PerCompilerFlavor [] [],
+                          profSharedOptions =
+                          PerCompilerFlavor [] [],
                           staticOptions =
                           PerCompilerFlavor [] [],
                           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/encoding-0.8.expr b/Cabal-tests/tests/ParserTests/regressions/encoding-0.8.expr
index e1b125e7a32ce1bf71eebf3408857ca0b34d311f..0d248029a3177611313fb1fc122005e17206503b 100644
--- a/Cabal-tests/tests/ParserTests/regressions/encoding-0.8.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/encoding-0.8.expr
@@ -114,6 +114,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/generics-sop.expr b/Cabal-tests/tests/ParserTests/regressions/generics-sop.expr
index 9084371a614b47b76379022116cd5c006af943e6..25786cdfad5225e4fe7fab56e20e964a1b0a03f5 100644
--- a/Cabal-tests/tests/ParserTests/regressions/generics-sop.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/generics-sop.expr
@@ -242,6 +242,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -373,6 +375,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -457,6 +461,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -561,6 +567,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -631,6 +639,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -702,6 +712,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [
@@ -798,6 +810,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/hasktorch.expr b/Cabal-tests/tests/ParserTests/regressions/hasktorch.expr
index 346af927d1bb0230c118b36104f54be2bca636b7..c68fac467e1458297c101184a40bd24eede4f5d7 100644
--- a/Cabal-tests/tests/ParserTests/regressions/hasktorch.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/hasktorch.expr
@@ -322,6 +322,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -642,6 +644,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -884,6 +888,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -1084,6 +1090,8 @@ GenericPackageDescription {
                         [],
                       sharedOptions =
                       PerCompilerFlavor [] [],
+                      profSharedOptions =
+                      PerCompilerFlavor [] [],
                       staticOptions =
                       PerCompilerFlavor [] [],
                       customFieldsBI = [],
@@ -1438,6 +1446,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -2740,6 +2750,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -2829,6 +2841,8 @@ GenericPackageDescription {
                       [],
                     sharedOptions =
                     PerCompilerFlavor [] [],
+                    profSharedOptions =
+                    PerCompilerFlavor [] [],
                     staticOptions =
                     PerCompilerFlavor [] [],
                     customFieldsBI = [],
@@ -5072,6 +5086,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -6424,6 +6440,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -6514,6 +6532,8 @@ GenericPackageDescription {
                       [],
                     sharedOptions =
                     PerCompilerFlavor [] [],
+                    profSharedOptions =
+                    PerCompilerFlavor [] [],
                     staticOptions =
                     PerCompilerFlavor [] [],
                     customFieldsBI = [],
@@ -8182,6 +8202,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -8670,6 +8692,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -9433,6 +9457,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -9554,6 +9580,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -9659,6 +9687,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -9764,6 +9794,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -9858,6 +9890,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -9978,6 +10012,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/hidden-main-lib.expr b/Cabal-tests/tests/ParserTests/regressions/hidden-main-lib.expr
index fba99528b537df3604a8ae419ca42ebe9cad7af8..b51b4adacb24c353657075fb9b86fa8bf9bce1e4 100644
--- a/Cabal-tests/tests/ParserTests/regressions/hidden-main-lib.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/hidden-main-lib.expr
@@ -97,6 +97,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/indentation.expr b/Cabal-tests/tests/ParserTests/regressions/indentation.expr
index e5b106dc5cd3fee1acebd96c630e246fc8de872c..c97630ddb006cf3df92411906a9efc5de14cc349 100644
--- a/Cabal-tests/tests/ParserTests/regressions/indentation.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/indentation.expr
@@ -106,6 +106,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/indentation2.expr b/Cabal-tests/tests/ParserTests/regressions/indentation2.expr
index 46f24105f0f654d16a945cf4583b7ae4aa855bb0..605cba525d1937a63d99e0b94d380d70a8d572a2 100644
--- a/Cabal-tests/tests/ParserTests/regressions/indentation2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/indentation2.expr
@@ -99,6 +99,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/indentation3.expr b/Cabal-tests/tests/ParserTests/regressions/indentation3.expr
index 0191d063f6e6a3152f252695cddd59d5087f17ad..55d0533c3feb3f9344025ecbc1da4bbdeef6380c 100644
--- a/Cabal-tests/tests/ParserTests/regressions/indentation3.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/indentation3.expr
@@ -101,6 +101,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-5055.expr b/Cabal-tests/tests/ParserTests/regressions/issue-5055.expr
index 07c04ec6cb9cbfde5e9652221dd7b66af76090eb..3b5092639e4dce394a1cefb10258f4aac17ec500 100644
--- a/Cabal-tests/tests/ParserTests/regressions/issue-5055.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/issue-5055.expr
@@ -100,6 +100,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -183,6 +185,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -267,6 +271,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-5846.expr b/Cabal-tests/tests/ParserTests/regressions/issue-5846.expr
index 2ff7de7917ed3a20a599eeacf48e2395874e37c4..61a7b7d2ca1247a74838db7eaf895e78af6711d8 100644
--- a/Cabal-tests/tests/ParserTests/regressions/issue-5846.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/issue-5846.expr
@@ -94,6 +94,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-6083-a.expr b/Cabal-tests/tests/ParserTests/regressions/issue-6083-a.expr
index 43c345dd1703f4df60fa9fec7c241c4d4d859eb4..c9c57785ac67c90b473f90a0b538fc897599175b 100644
--- a/Cabal-tests/tests/ParserTests/regressions/issue-6083-a.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/issue-6083-a.expr
@@ -94,6 +94,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -189,6 +191,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -255,6 +259,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -335,6 +341,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-6083-b.expr b/Cabal-tests/tests/ParserTests/regressions/issue-6083-b.expr
index e6606851627b5144545ceab5aa24b4c9f8dbc916..b0ed19062fc16d17bdcfbead5b122a64203c9fc4 100644
--- a/Cabal-tests/tests/ParserTests/regressions/issue-6083-b.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/issue-6083-b.expr
@@ -94,6 +94,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -189,6 +191,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -255,6 +259,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -345,6 +351,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-6083-c.expr b/Cabal-tests/tests/ParserTests/regressions/issue-6083-c.expr
index 7435b0d59b4854b31d571e0aebd4730805a3df62..c901eebc8ceb45414ccc40d39975b10e572bfdf6 100644
--- a/Cabal-tests/tests/ParserTests/regressions/issue-6083-c.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/issue-6083-c.expr
@@ -94,6 +94,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -189,6 +191,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-6083-pkg-pkg.expr b/Cabal-tests/tests/ParserTests/regressions/issue-6083-pkg-pkg.expr
index a221632efa45e2f0c044a0064781186b09f865b9..62ed5fd2fb93f8ac23d4be5eb5e509a2a193fff0 100644
--- a/Cabal-tests/tests/ParserTests/regressions/issue-6083-pkg-pkg.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/issue-6083-pkg-pkg.expr
@@ -94,6 +94,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/issue-774.expr b/Cabal-tests/tests/ParserTests/regressions/issue-774.expr
index e1ffb85dceb63ab5a17b8ec9348944c405a36e5d..2f58de4eb00e5fbfb48921e017685fccc13eb2d2 100644
--- a/Cabal-tests/tests/ParserTests/regressions/issue-774.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/issue-774.expr
@@ -108,6 +108,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/jaeger-flamegraph.expr b/Cabal-tests/tests/ParserTests/regressions/jaeger-flamegraph.expr
index c9e675ceb76c3ebd7487934f63be4b719452c348..9994c9b72c154dff7ffebc8ebdf5324a6af59960 100644
--- a/Cabal-tests/tests/ParserTests/regressions/jaeger-flamegraph.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/jaeger-flamegraph.expr
@@ -139,6 +139,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -238,6 +240,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -403,6 +407,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/leading-comma-2.expr b/Cabal-tests/tests/ParserTests/regressions/leading-comma-2.expr
index 0bb5556b2f41b3e0a1d1977acad04c87c220c284..99f7cddf881a550e066f779e42017504a6b75176 100644
--- a/Cabal-tests/tests/ParserTests/regressions/leading-comma-2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/leading-comma-2.expr
@@ -104,6 +104,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/leading-comma.expr b/Cabal-tests/tests/ParserTests/regressions/leading-comma.expr
index b1ba1b282f4fc13a73b63ae51d53381fbaa06da6..441fe75261da791f81e713fd0b69dcb9b9454b97 100644
--- a/Cabal-tests/tests/ParserTests/regressions/leading-comma.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/leading-comma.expr
@@ -97,6 +97,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/libpq1.expr b/Cabal-tests/tests/ParserTests/regressions/libpq1.expr
index 8906a91f63ba2d4a8aa35dc791a30b6a58c3d3d0..2e0bc309f9fa85b828d026205ec5ef788b9d802e 100644
--- a/Cabal-tests/tests/ParserTests/regressions/libpq1.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/libpq1.expr
@@ -190,6 +190,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -289,6 +291,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -373,6 +377,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -464,6 +470,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -529,6 +537,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -596,6 +606,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
@@ -661,6 +673,8 @@ GenericPackageDescription {
                             [],
                           sharedOptions =
                           PerCompilerFlavor [] [],
+                          profSharedOptions =
+                          PerCompilerFlavor [] [],
                           staticOptions =
                           PerCompilerFlavor [] [],
                           customFieldsBI = [],
@@ -728,6 +742,8 @@ GenericPackageDescription {
                                   [],
                                 sharedOptions =
                                 PerCompilerFlavor [] [],
+                                profSharedOptions =
+                                PerCompilerFlavor [] [],
                                 staticOptions =
                                 PerCompilerFlavor [] [],
                                 customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/libpq2.expr b/Cabal-tests/tests/ParserTests/regressions/libpq2.expr
index 3c26ece45ad0339d1d05aee1de0c998fe0b92c86..b74143af0b9f7fd4550dc8aa971705a294b4c477 100644
--- a/Cabal-tests/tests/ParserTests/regressions/libpq2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/libpq2.expr
@@ -195,6 +195,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -294,6 +296,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -378,6 +382,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -466,6 +472,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -531,6 +539,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -598,6 +608,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
@@ -663,6 +675,8 @@ GenericPackageDescription {
                             [],
                           sharedOptions =
                           PerCompilerFlavor [] [],
+                          profSharedOptions =
+                          PerCompilerFlavor [] [],
                           staticOptions =
                           PerCompilerFlavor [] [],
                           customFieldsBI = [],
@@ -730,6 +744,8 @@ GenericPackageDescription {
                                   [],
                                 sharedOptions =
                                 PerCompilerFlavor [] [],
+                                profSharedOptions =
+                                PerCompilerFlavor [] [],
                                 staticOptions =
                                 PerCompilerFlavor [] [],
                                 customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/mixin-1.expr b/Cabal-tests/tests/ParserTests/regressions/mixin-1.expr
index de8a15f04c04f198390ca7d5507c819a4586bbd1..77821302ddf4f07cdaa93c4b9f108156d01dcedf 100644
--- a/Cabal-tests/tests/ParserTests/regressions/mixin-1.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/mixin-1.expr
@@ -98,6 +98,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/mixin-2.expr b/Cabal-tests/tests/ParserTests/regressions/mixin-2.expr
index 3bf06bc9c3b2e338c118412915d8c176f4767af9..d8b58ff5a0be409471995de2609463435e6da4a0 100644
--- a/Cabal-tests/tests/ParserTests/regressions/mixin-2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/mixin-2.expr
@@ -98,6 +98,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/mixin-3.expr b/Cabal-tests/tests/ParserTests/regressions/mixin-3.expr
index 0c0fc57a8b8c079b30c83a82da5a4e32f192fc88..c0cbfe921adb253288afbc2a9f2839b98cadb764 100644
--- a/Cabal-tests/tests/ParserTests/regressions/mixin-3.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/mixin-3.expr
@@ -98,6 +98,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/monad-param.expr b/Cabal-tests/tests/ParserTests/regressions/monad-param.expr
index 28d57c1e3b0078653f9274d76c9bd16569c26809..e450672e86847f8842d3b6a6e8ade3f3199fc8bd 100644
--- a/Cabal-tests/tests/ParserTests/regressions/monad-param.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/monad-param.expr
@@ -120,6 +120,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.expr b/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.expr
index a8c6b0c0c4a7d23454d3dba61ab0e878b7bb515d..aa7d6954637865801ad889598646e975b076a107 100644
--- a/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/multiple-libs-2.expr
@@ -97,6 +97,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -175,6 +177,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/noVersion.expr b/Cabal-tests/tests/ParserTests/regressions/noVersion.expr
index 8187272c2c024b8ae811ddbea01d4ff1faed2290..dfe79d768fb3c7fe33876e13139d3e23e05dbbd4 100644
--- a/Cabal-tests/tests/ParserTests/regressions/noVersion.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/noVersion.expr
@@ -97,6 +97,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.expr b/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.expr
index 2f2663733c638ba75b9ccf2bc845e0f821ed358c..2ed17f6d5575f993ffd66217c1aeb3110c930588 100644
--- a/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/nothing-unicode.expr
@@ -112,6 +112,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -179,6 +181,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/shake.expr b/Cabal-tests/tests/ParserTests/regressions/shake.expr
index 8dd849d75bd29c965f7a467809529107b2681a6e..4dd37e84de05102d8680384254508e34d66c507e 100644
--- a/Cabal-tests/tests/ParserTests/regressions/shake.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/shake.expr
@@ -306,6 +306,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -519,6 +521,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -586,6 +590,8 @@ GenericPackageDescription {
                         [],
                       sharedOptions =
                       PerCompilerFlavor [] [],
+                      profSharedOptions =
+                      PerCompilerFlavor [] [],
                       staticOptions =
                       PerCompilerFlavor [] [],
                       customFieldsBI = [],
@@ -660,6 +666,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -727,6 +735,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
@@ -805,6 +815,8 @@ GenericPackageDescription {
                   [],
                 sharedOptions =
                 PerCompilerFlavor [] [],
+                profSharedOptions =
+                PerCompilerFlavor [] [],
                 staticOptions =
                 PerCompilerFlavor [] [],
                 customFieldsBI = [],
@@ -982,6 +994,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -1206,6 +1220,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -1271,6 +1287,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -1335,6 +1353,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
@@ -1406,6 +1426,8 @@ GenericPackageDescription {
                       [],
                     sharedOptions =
                     PerCompilerFlavor [] [],
+                    profSharedOptions =
+                    PerCompilerFlavor [] [],
                     staticOptions =
                     PerCompilerFlavor [] [],
                     customFieldsBI = [],
@@ -1470,6 +1492,8 @@ GenericPackageDescription {
                             [],
                           sharedOptions =
                           PerCompilerFlavor [] [],
+                          profSharedOptions =
+                          PerCompilerFlavor [] [],
                           staticOptions =
                           PerCompilerFlavor [] [],
                           customFieldsBI = [],
@@ -1545,6 +1569,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -1764,6 +1790,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -1992,6 +2020,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -2061,6 +2091,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -2130,6 +2162,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
@@ -2198,6 +2232,8 @@ GenericPackageDescription {
                           [],
                         sharedOptions =
                         PerCompilerFlavor [] [],
+                        profSharedOptions =
+                        PerCompilerFlavor [] [],
                         staticOptions =
                         PerCompilerFlavor [] [],
                         customFieldsBI = [],
@@ -2273,6 +2309,8 @@ GenericPackageDescription {
                       [],
                     sharedOptions =
                     PerCompilerFlavor [] [],
+                    profSharedOptions =
+                    PerCompilerFlavor [] [],
                     staticOptions =
                     PerCompilerFlavor [] [],
                     customFieldsBI = [],
@@ -2341,6 +2379,8 @@ GenericPackageDescription {
                             [],
                           sharedOptions =
                           PerCompilerFlavor [] [],
+                          profSharedOptions =
+                          PerCompilerFlavor [] [],
                           staticOptions =
                           PerCompilerFlavor [] [],
                           customFieldsBI = [],
@@ -2420,6 +2460,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/spdx-1.expr b/Cabal-tests/tests/ParserTests/regressions/spdx-1.expr
index 2ca07bf2322a34923b4dc9d40139a0a72792d5ff..ddeaf37cbe460795446f9217165689035ead54af 100644
--- a/Cabal-tests/tests/ParserTests/regressions/spdx-1.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/spdx-1.expr
@@ -95,6 +95,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/spdx-2.expr b/Cabal-tests/tests/ParserTests/regressions/spdx-2.expr
index 9c50edd486404e0f90b86481bac50a11cfb112ef..b865b1f31db9164a1edb9a1193f82d8638aac0db 100644
--- a/Cabal-tests/tests/ParserTests/regressions/spdx-2.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/spdx-2.expr
@@ -99,6 +99,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/spdx-3.expr b/Cabal-tests/tests/ParserTests/regressions/spdx-3.expr
index 944faa4c0c0d769472ed0db3e0661409b6caf48d..dc8f3f922b9ceca4309d82f63a62177b737d9ab8 100644
--- a/Cabal-tests/tests/ParserTests/regressions/spdx-3.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/spdx-3.expr
@@ -99,6 +99,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/th-lift-instances.expr b/Cabal-tests/tests/ParserTests/regressions/th-lift-instances.expr
index 8f2edf09a36e2294ee9dac768a6e8971f9bc6146..5e781597f30fc57b1d7b5508befee17e569a2259 100644
--- a/Cabal-tests/tests/ParserTests/regressions/th-lift-instances.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/th-lift-instances.expr
@@ -127,6 +127,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -298,6 +300,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -473,6 +477,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
@@ -577,6 +583,8 @@ GenericPackageDescription {
                     [],
                   sharedOptions =
                   PerCompilerFlavor [] [],
+                  profSharedOptions =
+                  PerCompilerFlavor [] [],
                   staticOptions =
                   PerCompilerFlavor [] [],
                   customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/version-sets.expr b/Cabal-tests/tests/ParserTests/regressions/version-sets.expr
index b134e4584ad5464c484a97aae927d60bfb88060f..3244bc1cc454190ad7660e47145e34f1f875c1d6 100644
--- a/Cabal-tests/tests/ParserTests/regressions/version-sets.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/version-sets.expr
@@ -121,6 +121,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
diff --git a/Cabal-tests/tests/ParserTests/regressions/wl-pprint-indef.expr b/Cabal-tests/tests/ParserTests/regressions/wl-pprint-indef.expr
index 03959b195c0fd09c09c78aadc6d8831340ce5756..6e718e3e685b535225ae57246f5870691286d028 100644
--- a/Cabal-tests/tests/ParserTests/regressions/wl-pprint-indef.expr
+++ b/Cabal-tests/tests/ParserTests/regressions/wl-pprint-indef.expr
@@ -114,6 +114,8 @@ GenericPackageDescription {
             [],
           sharedOptions =
           PerCompilerFlavor [] [],
+          profSharedOptions =
+          PerCompilerFlavor [] [],
           staticOptions =
           PerCompilerFlavor [] [],
           customFieldsBI = [],
@@ -202,6 +204,8 @@ GenericPackageDescription {
               [],
             sharedOptions =
             PerCompilerFlavor [] [],
+            profSharedOptions =
+            PerCompilerFlavor [] [],
             staticOptions =
             PerCompilerFlavor [] [],
             customFieldsBI = [],
diff --git a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs
index 54624a617c397fc07066c4f01d238906f3b6f0f1..d600a51fa05678731d96a0c787c3c6d7530faff5 100644
--- a/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs
+++ b/Cabal-tests/tests/UnitTests/Distribution/Utils/Structured.hs
@@ -33,15 +33,15 @@ md5Check proxy md5Int = structureHash proxy @?= md5FromInteger md5Int
 md5CheckGenericPackageDescription :: Proxy GenericPackageDescription -> Assertion
 md5CheckGenericPackageDescription proxy = md5Check proxy
 #if MIN_VERSION_base(4,19,0)
-    0x44f8430d7366cf849e09669627573040
+    0xe28f08e7ac644f836d8b3fe7f9428dcf
 #else
-    0x8ed837568017bde3abb4fcee244b9c9f
+    0x3442058190aa48c2f795b83ee995f702
 #endif
 
 md5CheckLocalBuildInfo :: Proxy LocalBuildInfo -> Assertion
 md5CheckLocalBuildInfo proxy = md5Check proxy
 #if MIN_VERSION_base(4,19,0)
-    0xdff58fe5e7f9568c67cd982eaba7edc2
+    0x31b94dc3e61eb01fea1a1c3c73d984ee
 #else
-    0x4e50a4a95779b862edde3d6696797251
+    0xdc2f5e7a9c696a4e0bd64f02a0140b74
 #endif
diff --git a/Cabal/Cabal.cabal b/Cabal/Cabal.cabal
index e6a978234c23b1f795bb5eb6ecaa5657b4a8ad77..deaad72cef1a4aa5afb29a61129b69d4569f9df6 100644
--- a/Cabal/Cabal.cabal
+++ b/Cabal/Cabal.cabal
@@ -101,6 +101,7 @@ library
     Distribution.Simple.BuildPaths
     Distribution.Simple.BuildTarget
     Distribution.Simple.BuildToolDepends
+    Distribution.Simple.BuildWay
     Distribution.Simple.CCompiler
     Distribution.Simple.Command
     Distribution.Simple.Compiler
diff --git a/Cabal/src/Distribution/Simple/BuildPaths.hs b/Cabal/src/Distribution/Simple/BuildPaths.hs
index 4c44bd380f21d92cb0786434ec97a3b98f4c2b11..05a9c6c190fee18f28b12786e19a95bea619c2b2 100644
--- a/Cabal/src/Distribution/Simple/BuildPaths.hs
+++ b/Cabal/src/Distribution/Simple/BuildPaths.hs
@@ -32,6 +32,7 @@ module Distribution.Simple.BuildPaths
   , mkProfLibName
   , mkGenericSharedLibName
   , mkSharedLibName
+  , mkProfSharedLibName
   , mkStaticLibName
   , mkGenericSharedBundledLibName
   , exeExtension
@@ -283,6 +284,10 @@ mkSharedLibName :: Platform -> CompilerId -> UnitId -> String
 mkSharedLibName platform comp lib =
   mkGenericSharedLibName platform comp (getHSLibraryName lib)
 
+mkProfSharedLibName :: Platform -> CompilerId -> UnitId -> String
+mkProfSharedLibName platform comp lib =
+  mkGenericSharedLibName platform comp (getHSLibraryName lib ++ "_p")
+
 -- Static libs are named the same as shared libraries, only with
 -- a different extension.
 mkStaticLibName :: Platform -> CompilerId -> UnitId -> String
diff --git a/Cabal/src/Distribution/Simple/BuildWay.hs b/Cabal/src/Distribution/Simple/BuildWay.hs
new file mode 100644
index 0000000000000000000000000000000000000000..614c229d462f1ecacf782fca3583fd34493f3a06
--- /dev/null
+++ b/Cabal/src/Distribution/Simple/BuildWay.hs
@@ -0,0 +1,14 @@
+{-# LANGUAGE LambdaCase #-}
+
+module Distribution.Simple.BuildWay where
+
+data BuildWay = StaticWay | DynWay | ProfWay | ProfDynWay
+  deriving (Eq, Ord, Show, Read, Enum)
+
+-- | Returns the object/interface extension prefix for the given build way (e.g. "dyn_" for 'DynWay')
+buildWayPrefix :: BuildWay -> String
+buildWayPrefix = \case
+  StaticWay -> ""
+  ProfWay -> "p_"
+  DynWay -> "dyn_"
+  ProfDynWay -> "p_dyn_"
diff --git a/Cabal/src/Distribution/Simple/Compiler.hs b/Cabal/src/Distribution/Simple/Compiler.hs
index ae8d1c051365e1ee7f412633dc9319b83966f540..7b9f2ac8059d8a432650072fac09a020a591ac8e 100644
--- a/Cabal/src/Distribution/Simple/Compiler.hs
+++ b/Cabal/src/Distribution/Simple/Compiler.hs
@@ -63,6 +63,11 @@ module Distribution.Simple.Compiler
   , unitIdSupported
   , coverageSupported
   , profilingSupported
+  , profilingDynamicSupported
+  , profilingDynamicSupportedOrUnknown
+  , profilingVanillaSupported
+  , profilingVanillaSupportedOrUnknown
+  , dynamicSupported
   , backpackSupported
   , arResponseFilesSupported
   , arDashLSupported
@@ -428,6 +433,49 @@ profilingSupported comp =
     GHCJS -> True
     _ -> False
 
+-- | Returns Just if we can certainly determine whether a way is supported
+-- if we don't know, return Nothing
+waySupported :: String -> Compiler -> Maybe Bool
+waySupported way comp =
+  case compilerFlavor comp of
+    GHC ->
+      -- Infomation about compiler ways is only accurately reported after
+      -- 9.10.1. Which is useful as this is before profiling dynamic support
+      -- was introduced. (See GHC #24881)
+      if compilerVersion comp >= mkVersion [9, 10, 1]
+        then case Map.lookup "RTS ways" (compilerProperties comp) of
+          Just ways -> Just (way `elem` words ways)
+          Nothing -> Just False
+        else Nothing
+    _ -> Nothing
+
+-- | Either profiling is definitely supported or we don't know (so assume
+-- it is)
+profilingVanillaSupportedOrUnknown :: Compiler -> Bool
+profilingVanillaSupportedOrUnknown comp = profilingVanillaSupported comp `elem` [Just True, Nothing]
+
+-- | Is the compiler distributed with profiling libraries
+profilingVanillaSupported :: Compiler -> Maybe Bool
+profilingVanillaSupported comp = waySupported "p" comp
+
+-- | Is the compiler distributed with profiling dynamic libraries
+profilingDynamicSupported :: Compiler -> Maybe Bool
+profilingDynamicSupported comp =
+  -- Certainly not before this version, as it was not implemented yet.
+  if compilerVersion comp <= mkVersion [9, 11, 0]
+    then Just False
+    else waySupported "p_dyn" comp
+
+-- | Either profiling dynamic is definitely supported or we don't know (so assume
+-- it is)
+profilingDynamicSupportedOrUnknown :: Compiler -> Bool
+profilingDynamicSupportedOrUnknown comp =
+  profilingDynamicSupported comp `elem` [Just True, Nothing]
+
+-- | Is the compiler distributed with dynamic libraries
+dynamicSupported :: Compiler -> Maybe Bool
+dynamicSupported comp = waySupported "dyn" comp
+
 -- | Does this compiler support a package database entry with:
 -- "visibility"?
 libraryVisibilitySupported :: Compiler -> Bool
diff --git a/Cabal/src/Distribution/Simple/Configure.hs b/Cabal/src/Distribution/Simple/Configure.hs
index 8d90b0d8822e106af4c56df5ee3bf977d1a25615..aa0e2a3a4381c2ad61894818e82fccb74fa307ae 100644
--- a/Cabal/src/Distribution/Simple/Configure.hs
+++ b/Cabal/src/Distribution/Simple/Configure.hs
@@ -81,6 +81,7 @@ import Distribution.PackageDescription.Configuration
 import Distribution.PackageDescription.PrettyPrint
 import Distribution.Simple.BuildTarget
 import Distribution.Simple.BuildToolDepends
+import Distribution.Simple.BuildWay
 import Distribution.Simple.Compiler
 import Distribution.Simple.LocalBuildInfo
 import Distribution.Simple.PackageIndex (InstalledPackageIndex, lookupUnitId)
@@ -709,7 +710,7 @@ computeLocalBuildConfig cfg comp programDb = do
             -- rely on them. By the time that bug was fixed, ghci had
             -- been changed to read shared libraries instead of archive
             -- files (see next code block).
-            not (GHC.isDynamic comp)
+            not (GHC.compilerBuildWay comp `elem` [DynWay, ProfDynWay])
           CompilerId GHCJS _ ->
             not (GHCJS.isDynamic comp)
           _ -> False
@@ -734,7 +735,7 @@ computeLocalBuildConfig cfg comp programDb = do
             CompilerId GHC _ ->
               -- if ghc is dynamic, then ghci needs a shared
               -- library, so we build one by default.
-              GHC.isDynamic comp
+              GHC.compilerBuildWay comp == DynWay
             CompilerId GHCJS _ ->
               GHCJS.isDynamic comp
             _ -> False
@@ -754,12 +755,6 @@ computeLocalBuildConfig cfg comp programDb = do
 
       withFullyStaticExe_ = fromFlag $ configFullyStaticExe cfg
 
-  when (withDynExe_ && not withSharedLib_) $
-    warn verbosity $
-      "Executables will use dynamic linking, but a shared library "
-        ++ "is not being built. Linking will fail if any executables "
-        ++ "depend on the library."
-
   setProfiling <- configureProfiling verbosity cfg comp
 
   setCoverage <- configureCoverage verbosity cfg comp
@@ -792,6 +787,7 @@ computeLocalBuildConfig cfg comp programDb = do
             , withDynExe = withDynExe_
             , withFullyStaticExe = withFullyStaticExe_
             , withProfLib = False
+            , withProfLibShared = False
             , withProfLibDetail = ProfDetailNone
             , withProfExe = False
             , withProfExeDetail = ProfDetailNone
@@ -807,6 +803,20 @@ computeLocalBuildConfig cfg comp programDb = do
             , relocatable = fromFlagOrDefault False $ configRelocatable cfg
             }
 
+  -- Dynamic executable, but no shared vanilla libraries
+  when (LBC.withDynExe buildOptions && not (LBC.withProfExe buildOptions) && not (LBC.withSharedLib buildOptions)) $
+    warn verbosity $
+      "Executables will use dynamic linking, but a shared library "
+        ++ "is not being built. Linking will fail if any executables "
+        ++ "depend on the library."
+
+  -- Profiled dynamic executable, but no shared profiling libraries
+  when (LBC.withDynExe buildOptions && LBC.withProfExe buildOptions && not (LBC.withProfLibShared buildOptions)) $
+    warn verbosity $
+      "Executables will use profiled dynamic linking, but a profiled shared library "
+        ++ "is not being built. Linking will fail if any executables "
+        ++ "depend on the library."
+
   return $
     LBC.LocalBuildConfig
       { extraConfigArgs = [] -- Currently configure does not
@@ -1732,7 +1742,7 @@ configureCoverage verbosity cfg comp = do
 --
 -- Note that @--enable-executable-profiling@ also affects profiling
 -- of benchmarks and (non-detailed) test suites.
-computeEffectiveProfiling :: ConfigFlags -> (Bool {- lib -}, Bool {- exe -})
+computeEffectiveProfiling :: ConfigFlags -> (Bool {- lib vanilla-}, Bool {- lib shared -}, Bool {- exe -})
 computeEffectiveProfiling cfg =
   -- The --profiling flag sets the default for both libs and exes,
   -- but can be overridden by --library-profiling, or the old deprecated
@@ -1740,15 +1750,20 @@ computeEffectiveProfiling cfg =
   --
   -- The --profiling-detail and --library-profiling-detail flags behave
   -- similarly
-  let tryExeProfiling =
+  let dynamicExe = fromFlagOrDefault False (configDynExe cfg)
+      tryExeProfiling =
         fromFlagOrDefault
           False
           (mappend (configProf cfg) (configProfExe cfg))
       tryLibProfiling =
         fromFlagOrDefault
-          tryExeProfiling
-          (mappend (configProf cfg) (configProfLib cfg))
-   in (tryLibProfiling, tryExeProfiling)
+          (tryExeProfiling && not dynamicExe)
+          (configProfLib cfg)
+      tryLibProfilingShared =
+        fromFlagOrDefault
+          (tryExeProfiling && dynamicExe)
+          (configProfShared cfg)
+   in (tryLibProfiling, tryLibProfilingShared, tryExeProfiling)
 
 -- | Select and apply profiling settings for the build based on the
 -- 'ConfigFlags' and 'Compiler'.
@@ -1758,7 +1773,7 @@ configureProfiling
   -> Compiler
   -> IO (LBC.BuildOptions -> LBC.BuildOptions)
 configureProfiling verbosity cfg comp = do
-  let (tryLibProfiling, tryExeProfiling) = computeEffectiveProfiling cfg
+  let (tryLibProfiling, tryLibProfilingShared, tryExeProfiling) = computeEffectiveProfiling cfg
 
       tryExeProfileLevel =
         fromFlagOrDefault
@@ -1785,8 +1800,8 @@ configureProfiling verbosity cfg comp = do
         return ProfDetailDefault
       checkProfileLevel other = return other
 
-  (exeProfWithoutLibProf, applyProfiling) <-
-    if profilingSupported comp
+  applyProfiling <-
+    if profilingSupported comp && (profilingVanillaSupportedOrUnknown comp || profilingDynamicSupportedOrUnknown comp)
       then do
         exeLevel <- checkProfileLevel tryExeProfileLevel
         libLevel <- checkProfileLevel tryLibProfileLevel
@@ -1797,11 +1812,46 @@ configureProfiling verbosity cfg comp = do
                 , LBC.withProfExe = tryExeProfiling
                 , LBC.withProfExeDetail = exeLevel
                 }
-        return (tryExeProfiling && not tryLibProfiling, apply)
+        let compilerSupportsProfilingDynamic = profilingDynamicSupportedOrUnknown comp
+        apply2 <-
+          if compilerSupportsProfilingDynamic
+            then -- Case 1: We support profiled shared libraries so turn on shared profiling
+            -- libraries if the user asked for it.
+            return $ \buildOptions -> apply buildOptions{LBC.withProfLibShared = tryLibProfilingShared}
+            else -- Case 2: Compiler doesn't support profiling shared so turn them off
+            do
+              -- If we wanted to enable profiling shared libraries.. tell the
+              -- user we couldn't.
+              when (profilingVanillaSupportedOrUnknown comp && tryLibProfilingShared) $
+                warn
+                  verbosity
+                  ( "The compiler "
+                      ++ showCompilerId comp
+                      ++ " does not support "
+                      ++ "profiling shared objects. Static profiled objects "
+                      ++ "will be built."
+                  )
+              return $ \buildOptions ->
+                let original_options = apply buildOptions
+                 in original_options
+                      { LBC.withProfLibShared = False
+                      , LBC.withProfLib = profilingVanillaSupportedOrUnknown comp && (tryLibProfilingShared || LBC.withProfLib original_options)
+                      , LBC.withDynExe = if LBC.withProfExe original_options then False else LBC.withDynExe original_options
+                      }
+
+        when (tryExeProfiling && not (tryLibProfiling || tryLibProfilingShared)) $ do
+          warn
+            verbosity
+            ( "Executables will be built with profiling, but library "
+                ++ "profiling is disabled. Linking will fail if any executables "
+                ++ "depend on the library."
+            )
+        return apply2
       else do
         let apply buildOptions =
               buildOptions
                 { LBC.withProfLib = False
+                , LBC.withProfLibShared = False
                 , LBC.withProfLibDetail = ProfDetailNone
                 , LBC.withProfExe = False
                 , LBC.withProfExeDetail = ProfDetailNone
@@ -1814,15 +1864,7 @@ configureProfiling verbosity cfg comp = do
                 ++ " does not support "
                 ++ "profiling. Profiling has been disabled."
             )
-        return (False, apply)
-
-  when exeProfWithoutLibProf $
-    warn
-      verbosity
-      ( "Executables will be built with profiling, but library "
-          ++ "profiling is disabled. Linking will fail if any executables "
-          ++ "depend on the library."
-      )
+        return apply
 
   return applyProfiling
 
diff --git a/Cabal/src/Distribution/Simple/GHC.hs b/Cabal/src/Distribution/Simple/GHC.hs
index 095e657264eec9ec11ca78c2013050b8bc435c8f..8d7dda4de34368359d34efb634db804000117b7e 100644
--- a/Cabal/src/Distribution/Simple/GHC.hs
+++ b/Cabal/src/Distribution/Simple/GHC.hs
@@ -61,7 +61,7 @@ module Distribution.Simple.GHC
   , Internal.componentCcGhcOptions
   , getGhcAppDir
   , getLibDir
-  , isDynamic
+  , compilerBuildWay
   , getGlobalPackageDB
   , pkgRoot
 
@@ -98,6 +98,7 @@ import Distribution.Simple.BuildPaths
 import Distribution.Simple.Compiler
 import Distribution.Simple.Errors
 import qualified Distribution.Simple.GHC.Build as GHC
+import Distribution.Simple.GHC.Build.Modules (BuildWay (..))
 import Distribution.Simple.GHC.Build.Utils
 import Distribution.Simple.GHC.EnvironmentParser
 import Distribution.Simple.GHC.ImplInfo
@@ -747,11 +748,28 @@ libAbiHash verbosity _pkg_descr lbi lib clbi = do
           , ghcOptObjSuffix = toFlag "p_o"
           , ghcOptExtra = hcProfOptions GHC libBi
           }
-    ghcArgs
-      | withVanillaLib lbi = vanillaArgs
-      | withSharedLib lbi = sharedArgs
-      | withProfLib lbi = profArgs
-      | otherwise = error "libAbiHash: Can't find an enabled library way"
+    profDynArgs =
+      vanillaArgs
+        `mappend` mempty
+          { ghcOptProfilingMode = toFlag True
+          , ghcOptProfilingAuto =
+              Internal.profDetailLevelFlag
+                True
+                (withProfLibDetail lbi)
+          , ghcOptDynLinkMode = toFlag GhcDynamicOnly
+          , ghcOptFPic = toFlag True
+          , ghcOptHiSuffix = toFlag "p_dyn_hi"
+          , ghcOptObjSuffix = toFlag "p_dyn_o"
+          , ghcOptExtra = hcProfSharedOptions GHC libBi
+          }
+    ghcArgs =
+      let (libWays, _, _) = buildWays lbi
+       in case libWays (componentIsIndefinite clbi) of
+            (ProfDynWay : _) -> profDynArgs
+            (ProfWay : _) -> profArgs
+            (StaticWay : _) -> vanillaArgs
+            (DynWay : _) -> sharedArgs
+            _ -> error "libAbiHash: Can't find an enabled library way"
 
   (ghcProg, _) <- requireProgram verbosity ghcProgram (withPrograms lbi)
 
@@ -870,75 +888,90 @@ installLib
   -> ComponentLocalBuildInfo
   -> IO ()
 installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do
+  let
+    (wantedLibWays, _, _) = buildWays lbi
+    isIndef = componentIsIndefinite clbi
+    libWays = wantedLibWays isIndef
+
+  info verbosity ("Wanted install ways: " ++ show libWays)
+
   -- copy .hi files over:
-  whenVanilla $ copyModuleFiles $ Suffix "hi"
-  whenProf $ copyModuleFiles $ Suffix "p_hi"
-  whenShared $ copyModuleFiles $ Suffix "dyn_hi"
+  forM_ (wantedLibWays isIndef) $ \w -> case w of
+    StaticWay -> copyModuleFiles (Suffix "hi")
+    DynWay -> copyModuleFiles (Suffix "dyn_hi")
+    ProfWay -> copyModuleFiles (Suffix "p_hi")
+    ProfDynWay -> copyModuleFiles (Suffix "p_dyn_hi")
 
   -- copy extra compilation artifacts that ghc plugins may produce
   copyDirectoryIfExists extraCompilationArtifacts
 
   -- copy the built library files over:
-  whenHasCode $ do
-    whenVanilla $ do
-      sequence_
-        [ installOrdinary
+  when (has_code && hasLib) $ do
+    forM_ libWays $ \w -> case w of
+      StaticWay -> do
+        sequence_
+          [ installOrdinary
+            builtDir
+            targetDir
+            (mkGenericStaticLibName (l ++ f))
+          | l <-
+              getHSLibraryName
+                (componentUnitId clbi)
+                : (extraBundledLibs (libBuildInfo lib))
+          , f <- "" : extraLibFlavours (libBuildInfo lib)
+          ]
+        whenGHCi $ installOrdinary builtDir targetDir ghciLibName
+      ProfWay -> do
+        installOrdinary builtDir targetDir profileLibName
+        whenGHCi $ installOrdinary builtDir targetDir ghciProfLibName
+      ProfDynWay -> do
+        installShared
           builtDir
-          targetDir
-          (mkGenericStaticLibName (l ++ f))
-        | l <-
-            getHSLibraryName
-              (componentUnitId clbi)
-              : (extraBundledLibs (libBuildInfo lib))
-        , f <- "" : extraLibFlavours (libBuildInfo lib)
-        ]
-      whenGHCi $ installOrdinary builtDir targetDir ghciLibName
-    whenProf $ do
-      installOrdinary builtDir targetDir profileLibName
-      whenGHCi $ installOrdinary builtDir targetDir ghciProfLibName
-    whenShared $
-      if
-          -- The behavior for "extra-bundled-libraries" changed in version 2.5.0.
-          -- See ghc issue #15837 and Cabal PR #5855.
-          | specVersion pkg < CabalSpecV3_0 -> do
-              sequence_
-                [ installShared
-                  builtDir
-                  dynlibTargetDir
-                  (mkGenericSharedLibName platform compiler_id (l ++ f))
-                | l <- getHSLibraryName uid : extraBundledLibs (libBuildInfo lib)
-                , f <- "" : extraDynLibFlavours (libBuildInfo lib)
-                ]
-          | otherwise -> do
-              sequence_
-                [ installShared
-                  builtDir
-                  dynlibTargetDir
-                  ( mkGenericSharedLibName
-                      platform
-                      compiler_id
-                      (getHSLibraryName uid ++ f)
-                  )
-                | f <- "" : extraDynLibFlavours (libBuildInfo lib)
-                ]
-              sequence_
-                [ do
-                  files <- getDirectoryContents (i builtDir)
-                  let l' =
-                        mkGenericSharedBundledLibName
-                          platform
-                          compiler_id
-                          l
-                  forM_ files $ \file ->
-                    when (l' `isPrefixOf` file) $ do
-                      isFile <- doesFileExist (i $ builtDir </> makeRelativePathEx file)
-                      when isFile $ do
-                        installShared
-                          builtDir
-                          dynlibTargetDir
-                          file
-                | l <- extraBundledLibs (libBuildInfo lib)
-                ]
+          dynlibTargetDir
+          (mkProfSharedLibName platform compiler_id uid)
+      DynWay -> do
+        if
+            -- The behavior for "extra-bundled-libraries" changed in version 2.5.0.
+            -- See ghc issue #15837 and Cabal PR #5855.
+            | specVersion pkg < CabalSpecV3_0 -> do
+                sequence_
+                  [ installShared
+                    builtDir
+                    dynlibTargetDir
+                    (mkGenericSharedLibName platform compiler_id (l ++ f))
+                  | l <- getHSLibraryName uid : extraBundledLibs (libBuildInfo lib)
+                  , f <- "" : extraDynLibFlavours (libBuildInfo lib)
+                  ]
+            | otherwise -> do
+                sequence_
+                  [ installShared
+                    builtDir
+                    dynlibTargetDir
+                    ( mkGenericSharedLibName
+                        platform
+                        compiler_id
+                        (getHSLibraryName uid ++ f)
+                    )
+                  | f <- "" : extraDynLibFlavours (libBuildInfo lib)
+                  ]
+                sequence_
+                  [ do
+                    files <- getDirectoryContents (i builtDir)
+                    let l' =
+                          mkGenericSharedBundledLibName
+                            platform
+                            compiler_id
+                            l
+                    forM_ files $ \file ->
+                      when (l' `isPrefixOf` file) $ do
+                        isFile <- doesFileExist (i $ builtDir </> makeRelativePathEx file)
+                        when isFile $ do
+                          installShared
+                            builtDir
+                            dynlibTargetDir
+                            file
+                  | l <- extraBundledLibs (libBuildInfo lib)
+                  ]
   where
     -- See Note [Symbolic paths] in Distribution.Utils.Path
     i = interpretSymbolicPathLBI lbi
@@ -997,11 +1030,7 @@ installLib verbosity lbi targetDir dynlibTargetDir _builtDir pkg lib clbi = do
       Platform JavaScript _ -> True
       _ -> False
     has_code = not (componentIsIndefinite clbi)
-    whenHasCode = when has_code
-    whenVanilla = when (hasLib && withVanillaLib lbi)
-    whenProf = when (hasLib && withProfLib lbi && has_code)
     whenGHCi = when (hasLib && withGHCiLib lbi && has_code)
-    whenShared = when (hasLib && withSharedLib lbi && has_code)
 
 -- -----------------------------------------------------------------------------
 -- Registering
diff --git a/Cabal/src/Distribution/Simple/GHC/Build.hs b/Cabal/src/Distribution/Simple/GHC/Build.hs
index 51f7d650338cd1225bbdfcc03670d59f5feb10b0..1f88f07552bf976e4f120bfaaaa288c5adcb050c 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build.hs
@@ -6,19 +6,17 @@ import Distribution.Compat.Prelude
 import Prelude ()
 
 import Control.Monad.IO.Class
-import qualified Data.Set as Set
 import Distribution.PackageDescription as PD hiding (buildInfo)
 import Distribution.Simple.Build.Inputs
 import Distribution.Simple.Flag (Flag)
 import Distribution.Simple.GHC.Build.ExtraSources
 import Distribution.Simple.GHC.Build.Link
 import Distribution.Simple.GHC.Build.Modules
-import Distribution.Simple.GHC.Build.Utils (withDynFLib)
 import Distribution.Simple.LocalBuildInfo
 import Distribution.Simple.Program.Builtin (ghcProgram)
 import Distribution.Simple.Program.Db (requireProgram)
 import Distribution.Simple.Utils
-import Distribution.Types.ComponentLocalBuildInfo (componentIsIndefinite)
+import Distribution.Types.ComponentLocalBuildInfo
 import Distribution.Types.ParStrat
 import Distribution.Utils.NubList (fromNubListR)
 import Distribution.Utils.Path
@@ -70,10 +68,10 @@ build
 build numJobs pkg_descr pbci = do
   let
     verbosity = buildVerbosity pbci
-    component = buildComponent pbci
     isLib = buildIsLib pbci
     lbi = localBuildInfo pbci
     clbi = buildCLBI pbci
+    isIndef = componentIsIndefinite clbi
     mbWorkDir = mbWorkDirLBI lbi
     i = interpretSymbolicPathLBI lbi -- See Note [Symbolic paths] in Distribution.Utils.Path
 
@@ -110,41 +108,14 @@ build numJobs pkg_descr pbci = do
 
   (ghcProg, _) <- liftIO $ requireProgram verbosity ghcProgram (withPrograms lbi)
 
-  -- Determine in which ways we want to build the component
-  let
-    wantVanilla = if isLib then withVanillaLib lbi else False
-    -- Arguably, wantStatic should be "withFullyStaticExe lbi" for executables,
-    -- but it was not before the refactor.
-    wantStatic = if isLib then withStaticLib lbi else not (wantDynamic || wantProf)
-    wantDynamic = case component of
-      CLib{} -> withSharedLib lbi
-      CFLib flib -> withDynFLib flib
-      CExe{} -> withDynExe lbi
-      CTest{} -> withDynExe lbi
-      CBench{} -> withDynExe lbi
-    wantProf = if isLib then withProfLib lbi else withProfExe lbi
-
-    -- See also Note [Building Haskell Modules accounting for TH] in Distribution.Simple.GHC.Build.Modules
-    -- We build static by default if no other way is wanted.
-    -- For executables and foreign libraries, there should only be one wanted way.
-    wantedWays =
-      Set.fromList $
-        -- If building a library, we accumulate all the ways,
-        -- otherwise, we take just one.
-        (if isLib then id else take 1) $
-          [ProfWay | wantProf]
-            -- I don't see why we shouldn't build with dynamic
-            -- indefinite components.
-            <> [DynWay | wantDynamic && not (componentIsIndefinite clbi)]
-            <> [StaticWay | wantStatic || wantVanilla || not (wantDynamic || wantProf)]
-
-  liftIO $ info verbosity ("Wanted build ways: " ++ show (Set.toList wantedWays))
+  let wantedWays@(wantedLibWays, _, wantedExeWay) = buildWays lbi
 
+  liftIO $ info verbosity ("Wanted build ways(" ++ show isLib ++ "): " ++ show (if isLib then wantedLibWays isIndef else [wantedExeWay]))
   -- We need a separate build and link phase, and C sources must be compiled
   -- after Haskell modules, because C sources may depend on stub headers
   -- generated from compiling Haskell modules (#842, #3294).
-  buildOpts <- buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci
-  extraSources <- buildAllExtraSources ghcProg buildTargetDir pbci
+  buildOpts <- buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir (wantedLibWays isIndef) pbci
+  extraSources <- buildAllExtraSources ghcProg buildTargetDir wantedWays pbci
   linkOrLoadComponent
     ghcProg
     pkg_descr
diff --git a/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs b/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs
index fc204cda30a8bad7350c0712cf50c9fb7609dc1a..83bcf9a6bca30e92a802a509a91e63d2a29ee139 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build/ExtraSources.hs
@@ -19,6 +19,7 @@ import Distribution.Types.Component
 import Distribution.Types.TargetInfo
 
 import Distribution.Simple.Build.Inputs
+import Distribution.Simple.GHC.Build.Modules
 import Distribution.Simple.GHC.Build.Utils
 import Distribution.Simple.LocalBuildInfo
 import Distribution.Simple.Program.Types
@@ -35,6 +36,8 @@ buildAllExtraSources
   -- ^ The GHC configured program
   -> SymbolicPath Pkg (Dir Artifacts)
   -- ^ The build directory for this target
+  -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)
+  -- ^ Needed build ways
   -> PreBuildComponentInputs
   -- ^ The context and component being built in it.
   -> IO (NubListR (SymbolicPath Pkg File))
@@ -57,6 +60,8 @@ buildCSources
     -- ^ The GHC configured program
     -> SymbolicPath Pkg (Dir Artifacts)
     -- ^ The build directory for this target
+    -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)
+    -- ^ Needed build ways
     -> PreBuildComponentInputs
     -- ^ The context and component being built in it.
     -> IO (NubListR (SymbolicPath Pkg File))
@@ -65,7 +70,6 @@ buildCSources =
   buildExtraSources
     "C Sources"
     Internal.componentCcGhcOptions
-    True
     ( \c -> do
         let cFiles = cSources (componentBuildInfo c)
         case c of
@@ -81,7 +85,6 @@ buildCxxSources =
   buildExtraSources
     "C++ Sources"
     Internal.componentCxxGhcOptions
-    True
     ( \c -> do
         let cxxFiles = cxxSources (componentBuildInfo c)
         case c of
@@ -93,13 +96,12 @@ buildCxxSources =
           -- is relative to the package.
           _otherwise -> cxxFiles
     )
-buildJsSources ghcProg buildTargetDir = do
+buildJsSources ghcProg buildTargetDir neededWays = do
   Platform hostArch _ <- hostPlatform <$> localBuildInfo
   let hasJsSupport = hostArch == JavaScript
   buildExtraSources
     "JS Sources"
     Internal.componentJsGhcOptions
-    False
     ( \c ->
         if hasJsSupport
           then -- JS files are C-like with GHC's JS backend: they are
@@ -111,17 +113,16 @@ buildJsSources ghcProg buildTargetDir = do
     )
     ghcProg
     buildTargetDir
+    neededWays
 buildAsmSources =
   buildExtraSources
     "Assembler Sources"
     Internal.componentAsmGhcOptions
-    True
     (asmSources . componentBuildInfo)
 buildCmmSources =
   buildExtraSources
     "C-- Sources"
     Internal.componentCmmGhcOptions
-    True
     (cmmSources . componentBuildInfo)
 
 -- | Create 'PreBuildComponentRules' for a given type of extra build sources
@@ -142,10 +143,6 @@ buildExtraSources
   -- invocation of GHC when compiling these extra sources (e.g.
   -- @'Internal.componentCxxGhcOptions'@,
   -- @'Internal.componentCmmGhcOptions'@)
-  -> Bool
-  -- ^ Some types of build sources should not be built in the dynamic way, namely, JS sources.
-  -- I'm not entirely sure this remains true after we migrate to supporting GHC's JS backend rather than GHCJS.
-  -- Boolean for "do we allow building these sources the dynamic way?"
   -> (Component -> [SymbolicPath Pkg File])
   -- ^ View the extra sources of a component, typically from
   -- the build info (e.g. @'asmSources'@, @'cSources'@).
@@ -156,108 +153,109 @@ buildExtraSources
   -- ^ The GHC configured program
   -> SymbolicPath Pkg (Dir Artifacts)
   -- ^ The build directory for this target
+  -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)
+  -- ^ Needed build ways
   -> PreBuildComponentInputs
   -- ^ The context and component being built in it.
   -> IO (NubListR (SymbolicPath Pkg File))
   -- ^ Returns the list of extra sources that were built
-buildExtraSources description componentSourceGhcOptions wantDyn viewSources ghcProg buildTargetDir =
-  \PreBuildComponentInputs{buildingWhat, localBuildInfo = lbi, targetInfo} -> do
-    let
-      bi = componentBuildInfo (targetComponent targetInfo)
-      verbosity = buildingWhatVerbosity buildingWhat
-      clbi = targetCLBI targetInfo
-      mbWorkDir = mbWorkDirLBI lbi
-      i = interpretSymbolicPath mbWorkDir
-      sources = viewSources (targetComponent targetInfo)
-      comp = compiler lbi
-      platform = hostPlatform lbi
-      -- Instead of keeping this logic here, we really just want to
-      -- receive as an input the `neededWays` from GHC/Build.build and build
-      -- accordingly, since we've already determined the extra needed ways
-      -- needed for e.g. template haskell. Although we'd have to account for 'wantDyn'.
-      isGhcDynamic = isDynamic comp
-      doingTH = usesTemplateHaskellOrQQ bi
-      forceSharedLib = doingTH && isGhcDynamic
-      runGhcProg = runGHC verbosity ghcProg comp platform
+buildExtraSources
+  description
+  componentSourceGhcOptions
+  viewSources
+  ghcProg
+  buildTargetDir
+  (neededLibWays, neededFLibWay, neededExeWay) =
+    \PreBuildComponentInputs{buildingWhat, localBuildInfo = lbi, targetInfo} -> do
+      let
+        bi = componentBuildInfo (targetComponent targetInfo)
+        verbosity = buildingWhatVerbosity buildingWhat
+        clbi = targetCLBI targetInfo
+        isIndef = componentIsIndefinite clbi
+        mbWorkDir = mbWorkDirLBI lbi
+        i = interpretSymbolicPath mbWorkDir
+        sources = viewSources (targetComponent targetInfo)
+        comp = compiler lbi
+        platform = hostPlatform lbi
+        runGhcProg = runGHC verbosity ghcProg comp platform
 
-      buildAction :: SymbolicPath Pkg File -> IO ()
-      buildAction sourceFile = do
-        let baseSrcOpts =
-              componentSourceGhcOptions
-                verbosity
-                lbi
-                bi
-                clbi
-                buildTargetDir
-                sourceFile
-            vanillaSrcOpts
-              -- Dynamic GHC requires C sources to be built
-              -- with -fPIC for REPL to work. See #2207.
-              | isGhcDynamic && wantDyn = baseSrcOpts{ghcOptFPic = toFlag True}
-              | otherwise = baseSrcOpts
-            profSrcOpts =
-              vanillaSrcOpts
-                `mappend` mempty
-                  { ghcOptProfilingMode = toFlag True
-                  }
-            sharedSrcOpts =
-              vanillaSrcOpts
-                `mappend` mempty
-                  { ghcOptFPic = toFlag True
-                  , ghcOptDynLinkMode = toFlag GhcDynamicOnly
-                  }
-            -- TODO: Placing all Haskell, C, & C++ objects in a single directory
-            --       Has the potential for file collisions. In general we would
-            --       consider this a user error. However, we should strive to
-            --       add a warning if this occurs.
-            odir = fromFlag (ghcOptObjDir vanillaSrcOpts)
+        buildAction :: SymbolicPath Pkg File -> IO ()
+        buildAction sourceFile = do
+          let baseSrcOpts =
+                componentSourceGhcOptions
+                  verbosity
+                  lbi
+                  bi
+                  clbi
+                  buildTargetDir
+                  sourceFile
+              vanillaSrcOpts =
+                -- -fPIC is used in case you are using the repl
+                -- of a dynamically linked GHC
+                baseSrcOpts{ghcOptFPic = toFlag True}
+              profSrcOpts =
+                vanillaSrcOpts
+                  `mappend` mempty
+                    { ghcOptProfilingMode = toFlag True
+                    }
+              sharedSrcOpts =
+                vanillaSrcOpts
+                  `mappend` mempty
+                    { ghcOptFPic = toFlag True
+                    , ghcOptDynLinkMode = toFlag GhcDynamicOnly
+                    }
+              profSharedSrcOpts =
+                vanillaSrcOpts
+                  `mappend` mempty
+                    { ghcOptProfilingMode = toFlag True
+                    , ghcOptFPic = toFlag True
+                    , ghcOptDynLinkMode = toFlag GhcDynamicOnly
+                    }
+              -- TODO: Placing all Haskell, C, & C++ objects in a single directory
+              --       Has the potential for file collisions. In general we would
+              --       consider this a user error. However, we should strive to
+              --       add a warning if this occurs.
+              odir = fromFlag (ghcOptObjDir vanillaSrcOpts)
 
-            compileIfNeeded :: GhcOptions -> IO ()
-            compileIfNeeded opts = do
-              needsRecomp <- checkNeedsRecompilation mbWorkDir sourceFile opts
-              when needsRecomp $ runGhcProg mbWorkDir opts
+              compileIfNeeded :: GhcOptions -> IO ()
+              compileIfNeeded opts = do
+                needsRecomp <- checkNeedsRecompilation mbWorkDir sourceFile opts
+                when needsRecomp $ runGhcProg mbWorkDir opts
 
-        -- TODO: This whole section can be streamlined to the
-        -- wantedWays+neededWays logic used in Build/Modules.hs
-        createDirectoryIfMissingVerbose verbosity True (i odir)
-        case targetComponent targetInfo of
-          -- For libraries, we compile extra objects in the three ways: vanilla, shared, and profiled.
-          -- We suffix shared objects with .dyn_o and profiled ones with .p_o.
-          CLib _lib
-            -- Unless for repl, in which case we only need the vanilla way
-            | BuildRepl _ <- buildingWhat ->
-                compileIfNeeded vanillaSrcOpts
-            | otherwise ->
-                do
+          createDirectoryIfMissingVerbose verbosity True (i odir)
+          case targetComponent targetInfo of
+            -- For libraries, we compile extra objects in the four ways: vanilla, shared, profiled and profiled shared.
+            -- We suffix shared objects with `.dyn_o`, profiled ones with `.p_o` and profiled shared ones with `.p_dyn_o`.
+            CLib _lib
+              -- Unless for repl, in which case we only need the vanilla way
+              | BuildRepl _ <- buildingWhat ->
                   compileIfNeeded vanillaSrcOpts
-                  when (wantDyn && (forceSharedLib || withSharedLib lbi)) $
-                    compileIfNeeded sharedSrcOpts{ghcOptObjSuffix = toFlag "dyn_o"}
-                  when (withProfLib lbi) $
-                    compileIfNeeded profSrcOpts{ghcOptObjSuffix = toFlag "p_o"}
-
-          -- For foreign libraries, we determine with which options to build the
-          -- objects (vanilla vs shared vs profiled)
-          CFLib flib
-            | withProfExe lbi -> -- It doesn't sound right to query "ProfExe" for a foreign library...
-                compileIfNeeded profSrcOpts
-            | withDynFLib flib && wantDyn ->
-                compileIfNeeded sharedSrcOpts
-            | otherwise ->
-                compileIfNeeded vanillaSrcOpts
-          -- For the remaining component types (Exec, Test, Bench), we also
-          -- determine with which options to build the objects (vanilla vs shared vs
-          -- profiled), but predicate is the same for the three kinds.
-          _exeLike
-            | withProfExe lbi ->
-                compileIfNeeded profSrcOpts
-            | withDynExe lbi && wantDyn ->
-                compileIfNeeded sharedSrcOpts
-            | otherwise ->
-                compileIfNeeded vanillaSrcOpts
-    -- build any sources
-    if (null sources || componentIsIndefinite clbi)
-      then return mempty
-      else do
-        info verbosity ("Building " ++ description ++ "...")
-        traverse_ buildAction sources
-        return (toNubListR sources)
+              | otherwise ->
+                  do
+                    forM_ (neededLibWays isIndef) $ \case
+                      StaticWay -> compileIfNeeded vanillaSrcOpts
+                      DynWay -> compileIfNeeded sharedSrcOpts{ghcOptObjSuffix = toFlag "dyn_o"}
+                      ProfWay -> compileIfNeeded profSrcOpts{ghcOptObjSuffix = toFlag "p_o"}
+                      ProfDynWay -> compileIfNeeded profSharedSrcOpts{ghcOptObjSuffix = toFlag "p_dyn_o"}
+            CFLib flib ->
+              case neededFLibWay (withDynFLib flib) of
+                StaticWay -> compileIfNeeded vanillaSrcOpts
+                DynWay -> compileIfNeeded sharedSrcOpts
+                ProfWay -> compileIfNeeded profSrcOpts
+                ProfDynWay -> compileIfNeeded profSharedSrcOpts
+            -- For the remaining component types (Exec, Test, Bench), we also
+            -- determine with which options to build the objects (vanilla vs shared vs
+            -- profiled), but predicate is the same for the three kinds.
+            _exeLike ->
+              case neededExeWay of
+                StaticWay -> compileIfNeeded vanillaSrcOpts
+                DynWay -> compileIfNeeded sharedSrcOpts
+                ProfWay -> compileIfNeeded profSrcOpts
+                ProfDynWay -> compileIfNeeded profSharedSrcOpts
+      -- build any sources
+      if (null sources || componentIsIndefinite clbi)
+        then return mempty
+        else do
+          info verbosity ("Building " ++ description ++ "...")
+          traverse_ buildAction sources
+          return (toNubListR sources)
diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Link.hs b/Cabal/src/Distribution/Simple/GHC/Build/Link.hs
index ee0f21ffa6d49c2f7978d708a5381177b3bb1ca0..3f9f00c9d28134ac98754ac580548467d4257a01 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build/Link.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build/Link.hs
@@ -8,8 +8,6 @@ module Distribution.Simple.GHC.Build.Link where
 import Distribution.Compat.Prelude
 import Prelude ()
 
-import Control.Exception (assert)
-import Control.Monad (forM_)
 import Control.Monad.IO.Class
 import qualified Data.ByteString.Lazy.Char8 as BS
 import qualified Data.Set as Set
@@ -76,128 +74,148 @@ linkOrLoadComponent
   -> (SymbolicPath Pkg (Dir Artifacts), SymbolicPath Pkg (Dir Build))
   -- ^ The build target dir, and the target dir.
   -- See Note [Build Target Dir vs Target Dir] in Distribution.Simple.GHC.Build
-  -> (Set.Set BuildWay, BuildWay -> GhcOptions)
+  -> ((Bool -> [BuildWay], Bool -> BuildWay, BuildWay), BuildWay -> GhcOptions)
   -- ^ The set of build ways wanted based on the user opts, and a function to
   -- convert a build way into the set of ghc options that were used to build
   -- that way.
   -> PreBuildComponentInputs
   -- ^ The context and component being built in it.
   -> IO ()
-linkOrLoadComponent ghcProg pkg_descr extraSources (buildTargetDir, targetDir) (wantedWays, buildOpts) pbci = do
-  let
-    verbosity = buildVerbosity pbci
-    target = targetInfo pbci
-    component = buildComponent pbci
-    what = buildingWhat pbci
-    lbi = localBuildInfo pbci
-    bi = buildBI pbci
-    clbi = buildCLBI pbci
-    mbWorkDir = mbWorkDirLBI lbi
+linkOrLoadComponent
+  ghcProg
+  pkg_descr
+  extraSources
+  (buildTargetDir, targetDir)
+  ((wantedLibWays, wantedFLibWay, wantedExeWay), buildOpts)
+  pbci = do
+    let
+      verbosity = buildVerbosity pbci
+      target = targetInfo pbci
+      component = buildComponent pbci
+      what = buildingWhat pbci
+      lbi = localBuildInfo pbci
+      bi = buildBI pbci
+      clbi = buildCLBI pbci
+      isIndef = componentIsIndefinite clbi
+      mbWorkDir = mbWorkDirLBI lbi
 
-    -- See Note [Symbolic paths] in Distribution.Utils.Path
-    i = interpretSymbolicPathLBI lbi
+      -- See Note [Symbolic paths] in Distribution.Utils.Path
+      i = interpretSymbolicPathLBI lbi
 
-  -- ensure extra lib dirs exist before passing to ghc
-  cleanedExtraLibDirs <- liftIO $ filterM (doesDirectoryExist . i) (extraLibDirs bi)
-  cleanedExtraLibDirsStatic <- liftIO $ filterM (doesDirectoryExist . i) (extraLibDirsStatic bi)
+    -- ensure extra lib dirs exist before passing to ghc
+    cleanedExtraLibDirs <- liftIO $ filterM (doesDirectoryExist . i) (extraLibDirs bi)
+    cleanedExtraLibDirsStatic <- liftIO $ filterM (doesDirectoryExist . i) (extraLibDirsStatic bi)
 
-  let
-    extraSourcesObjs :: [RelativePath Artifacts File]
-    extraSourcesObjs =
-      [ makeRelativePathEx $ getSymbolicPath src `replaceExtension` objExtension
-      | src <- extraSources
-      ]
-
-    -- TODO: Shouldn't we use withStaticLib for libraries and something else
-    -- for foreign libs in the three cases where we use `withFullyStaticExe` below?
-    linkerOpts rpaths =
-      mempty
-        { ghcOptLinkOptions =
-            PD.ldOptions bi
-              ++ [ "-static"
-                 | withFullyStaticExe lbi
-                 ]
-              -- Pass extra `ld-options` given
-              -- through to GHC's linker.
-              ++ maybe
-                []
-                programOverrideArgs
-                (lookupProgram ldProgram (withPrograms lbi))
-        , ghcOptLinkLibs =
-            if withFullyStaticExe lbi
-              then extraLibsStatic bi
-              else extraLibs bi
-        , ghcOptLinkLibPath =
-            toNubListR $
+    let
+      extraSourcesObjs :: [RelativePath Artifacts File]
+      extraSourcesObjs =
+        [ makeRelativePathEx $ getSymbolicPath src `replaceExtension` objExtension
+        | src <- extraSources
+        ]
+
+      -- TODO: Shouldn't we use withStaticLib for libraries and something else
+      -- for foreign libs in the three cases where we use `withFullyStaticExe` below?
+      linkerOpts rpaths =
+        mempty
+          { ghcOptLinkOptions =
+              PD.ldOptions bi
+                ++ [ "-static"
+                   | withFullyStaticExe lbi
+                   ]
+                -- Pass extra `ld-options` given
+                -- through to GHC's linker.
+                ++ maybe
+                  []
+                  programOverrideArgs
+                  (lookupProgram ldProgram (withPrograms lbi))
+          , ghcOptLinkLibs =
               if withFullyStaticExe lbi
-                then cleanedExtraLibDirsStatic
-                else cleanedExtraLibDirs
-        , ghcOptLinkFrameworks = toNubListR $ map getSymbolicPath $ PD.frameworks bi
-        , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs bi
-        , ghcOptInputFiles =
-            toNubListR
-              [ coerceSymbolicPath $ buildTargetDir </> obj
-              | obj <- extraSourcesObjs
-              ]
-        , ghcOptNoLink = Flag False
-        , ghcOptRPaths = rpaths
-        }
-  case what of
-    BuildRepl replFlags -> liftIO $ do
-      let
-        -- For repl we use the vanilla (static) ghc options
-        staticOpts = buildOpts StaticWay
-        replOpts =
-          staticOpts
-            { -- Repl options use Static as the base, but doesn't need to pass -static.
-              -- However, it maybe should, for uniformity.
-              ghcOptDynLinkMode = NoFlag
-            , ghcOptExtra =
-                Internal.filterGhciFlags
-                  (ghcOptExtra staticOpts)
-                  <> replOptionsFlags (replReplOptions replFlags)
-            , ghcOptInputModules = replNoLoad (replReplOptions replFlags) (ghcOptInputModules staticOpts)
-            , ghcOptInputFiles = replNoLoad (replReplOptions replFlags) (ghcOptInputFiles staticOpts)
-            }
-            -- For a normal compile we do separate invocations of ghc for
-            -- compiling as for linking. But for repl we have to do just
-            -- the one invocation, so that one has to include all the
-            -- linker stuff too, like -l flags and any .o files from C
-            -- files etc.
-            --
-            -- TODO: The repl doesn't use the runtime paths from linkerOpts
-            -- (ghcOptRPaths), which looks like a bug. After the refactor we
-            -- can fix this.
-            `mappend` linkerOpts mempty
-            `mappend` mempty
-              { ghcOptMode = toFlag GhcModeInteractive
-              , ghcOptOptimisation = toFlag GhcNoOptimisation
+                then extraLibsStatic bi
+                else extraLibs bi
+          , ghcOptLinkLibPath =
+              toNubListR $
+                if withFullyStaticExe lbi
+                  then cleanedExtraLibDirsStatic
+                  else cleanedExtraLibDirs
+          , ghcOptLinkFrameworks = toNubListR $ map getSymbolicPath $ PD.frameworks bi
+          , ghcOptLinkFrameworkDirs = toNubListR $ PD.extraFrameworkDirs bi
+          , ghcOptInputFiles =
+              toNubListR
+                [ coerceSymbolicPath $ buildTargetDir </> obj
+                | obj <- extraSourcesObjs
+                ]
+          , ghcOptNoLink = Flag False
+          , ghcOptRPaths = rpaths
+          }
+
+    case what of
+      BuildRepl replFlags -> liftIO $ do
+        let
+          -- For repl we use the vanilla (static) ghc options
+          staticOpts = buildOpts StaticWay
+          replOpts =
+            staticOpts
+              { -- Repl options use Static as the base, but doesn't need to pass -static.
+                -- However, it maybe should, for uniformity.
+                ghcOptDynLinkMode = NoFlag
+              , ghcOptExtra =
+                  Internal.filterGhciFlags
+                    (ghcOptExtra staticOpts)
+                    <> replOptionsFlags (replReplOptions replFlags)
+              }
+              -- For a normal compile we do separate invocations of ghc for
+              -- compiling as for linking. But for repl we have to do just
+              -- the one invocation, so that one has to include all the
+              -- linker stuff too, like -l flags and any .o files from C
+              -- files etc.
+              --
+              -- TODO: The repl doesn't use the runtime paths from linkerOpts
+              -- (ghcOptRPaths), which looks like a bug. After the refactor we
+              -- can fix this.
+              `mappend` linkerOpts mempty
+              `mappend` mempty
+                { ghcOptMode = toFlag GhcModeInteractive
+                , ghcOptOptimisation = toFlag GhcNoOptimisation
+                }
+          replOpts_final =
+            replOpts
+              { ghcOptInputModules = replNoLoad (replReplOptions replFlags) (ghcOptInputModules replOpts)
+              , ghcOptInputFiles = replNoLoad (replReplOptions replFlags) (ghcOptInputFiles replOpts)
               }
 
-      -- TODO: problem here is we need the .c files built first, so we can load them
-      -- with ghci, but .c files can depend on .h files generated by ghc by ffi
-      -- exports.
-      when (case component of CLib lib -> null (allLibModules lib clbi); _ -> False) $
-        warn verbosity "No exposed modules"
-      runReplOrWriteFlags ghcProg lbi replFlags replOpts (pkgName (PD.package pkg_descr)) target
-    _otherwise ->
-      let
-        runGhcProg = runGHC verbosity ghcProg comp platform mbWorkDir
-        platform = hostPlatform lbi
-        comp = compiler lbi
-       in
-        when (not $ componentIsIndefinite clbi) $ do
-          -- If not building dynamically, we don't pass any runtime paths.
-          rpaths <- if DynWay `Set.member` wantedWays then getRPaths pbci else return (toNubListR [])
-          liftIO $ do
-            info verbosity "Linking..."
-            let linkExeLike name = linkExecutable (linkerOpts rpaths) (wantedWays, buildOpts) targetDir name runGhcProg lbi
-            case component of
-              CLib lib -> linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths wantedWays
-              CFLib flib -> linkFLib flib bi lbi (linkerOpts rpaths) (wantedWays, buildOpts) targetDir runGhcProg
-              CExe exe -> linkExeLike (exeName exe)
-              CTest test -> linkExeLike (testName test)
-              CBench bench -> linkExeLike (benchmarkName bench)
+        -- TODO: problem here is we need the .c files built first, so we can load them
+        -- with ghci, but .c files can depend on .h files generated by ghc by ffi
+        -- exports.
+        when (case component of CLib lib -> null (allLibModules lib clbi); _ -> False) $
+          warn verbosity "No exposed modules"
+        runReplOrWriteFlags ghcProg lbi replFlags replOpts_final (pkgName (PD.package pkg_descr)) target
+      _otherwise ->
+        let
+          runGhcProg = runGHC verbosity ghcProg comp platform mbWorkDir
+          platform = hostPlatform lbi
+          comp = compiler lbi
+          get_rpaths ways =
+            if DynWay `Set.member` ways then getRPaths pbci else return (toNubListR [])
+         in
+          when (not $ componentIsIndefinite clbi) $ do
+            -- If not building dynamically, we don't pass any runtime paths.
+            liftIO $ do
+              info verbosity "Linking..."
+              let linkExeLike name = do
+                    rpaths <- get_rpaths (Set.singleton wantedExeWay)
+                    linkExecutable (linkerOpts rpaths) (wantedExeWay, buildOpts) targetDir name runGhcProg lbi
+              case component of
+                CLib lib -> do
+                  let libWays = wantedLibWays isIndef
+                  rpaths <- get_rpaths (Set.fromList libWays)
+                  linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths libWays
+                CFLib flib -> do
+                  let flib_way = wantedFLibWay (withDynFLib flib)
+                  rpaths <- get_rpaths (Set.singleton flib_way)
+                  linkFLib flib bi lbi (linkerOpts rpaths) (flib_way, buildOpts) targetDir runGhcProg
+                CExe exe -> linkExeLike (exeName exe)
+                CTest test -> linkExeLike (testName test)
+                CBench bench -> linkExeLike (benchmarkName bench)
 
 -- | Link a library component
 linkLibrary
@@ -217,7 +235,7 @@ linkLibrary
   -- ^ Extra build sources (that were compiled to objects)
   -> NubListR FilePath
   -- ^ A list with the runtime-paths (rpaths), or empty if not linking dynamically
-  -> Set.Set BuildWay
+  -> [BuildWay]
   -- ^ Wanted build ways and corresponding build options
   -> IO ()
 linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg lib lbi clbi extraSources rpaths wantedWays = do
@@ -237,6 +255,9 @@ linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg li
     sharedLibFilePath =
       buildTargetDir
         </> makeRelativePathEx (mkSharedLibName (hostPlatform lbi) compiler_id uid)
+    profSharedLibFilePath =
+      buildTargetDir
+        </> makeRelativePathEx (mkProfSharedLibName (hostPlatform lbi) compiler_id uid)
     staticLibFilePath =
       buildTargetDir
         </> makeRelativePathEx (mkStaticLibName (hostPlatform lbi) compiler_id uid)
@@ -252,6 +273,9 @@ linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg li
     sharedLibInstallPath =
       libInstallPath
         </> mkSharedLibName (hostPlatform lbi) compiler_id uid
+    profSharedLibInstallPath =
+      libInstallPath
+        </> mkProfSharedLibName (hostPlatform lbi) compiler_id uid
 
     getObjFiles :: BuildWay -> IO [SymbolicPath Pkg File]
     getObjFiles way =
@@ -358,6 +382,32 @@ linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg li
             toNubListR $ PD.extraFrameworkDirs libBi
         , ghcOptRPaths = rpaths
         }
+    ghcProfSharedLinkArgs pdynObjectFiles =
+      ghcBaseLinkArgs
+        { ghcOptShared = toFlag True
+        , ghcOptProfilingMode = toFlag True
+        , ghcOptProfilingAuto =
+            Internal.profDetailLevelFlag
+              True
+              (withProfLibDetail lbi)
+        , ghcOptDynLinkMode = toFlag GhcDynamicOnly
+        , ghcOptInputFiles = toNubListR pdynObjectFiles
+        , ghcOptOutputFile = toFlag profSharedLibFilePath
+        , -- For dynamic libs, Mac OS/X needs to know the install location
+          -- at build time. This only applies to GHC < 7.8 - see the
+          -- discussion in #1660.
+          ghcOptDylibName =
+            if hostOS == OSX
+              && ghcVersion < mkVersion [7, 8]
+              then toFlag profSharedLibInstallPath
+              else mempty
+        , ghcOptLinkLibs = extraLibs libBi
+        , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs
+        , ghcOptLinkFrameworks = toNubListR $ map getSymbolicPath $ PD.frameworks libBi
+        , ghcOptLinkFrameworkDirs =
+            toNubListR $ PD.extraFrameworkDirs libBi
+        , ghcOptRPaths = rpaths
+        }
     ghcStaticLinkArgs staticObjectFiles =
       ghcBaseLinkArgs
         { ghcOptStaticLib = toFlag True
@@ -371,6 +421,7 @@ linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg li
   staticObjectFiles <- getObjFiles StaticWay
   profObjectFiles <- getObjFiles ProfWay
   dynamicObjectFiles <- getObjFiles DynWay
+  profDynamicObjectFiles <- getObjFiles ProfDynWay
 
   let
     linkWay = \case
@@ -384,6 +435,8 @@ linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg li
             ldProg
             ghciProfLibFilePath
             profObjectFiles
+      ProfDynWay -> do
+        runGhcProg $ ghcProfSharedLinkArgs profDynamicObjectFiles
       DynWay -> do
         runGhcProg $ ghcSharedLinkArgs dynamicObjectFiles
       StaticWay -> do
@@ -413,7 +466,7 @@ linkLibrary buildTargetDir cleanedExtraLibDirs pkg_descr verbosity runGhcProg li
 linkExecutable
   :: (GhcOptions)
   -- ^ The linker-specific GHC options
-  -> (Set.Set BuildWay, BuildWay -> GhcOptions)
+  -> (BuildWay, BuildWay -> GhcOptions)
   -- ^ The wanted build ways and corresponding GhcOptions that were
   -- used to compile the modules in that way.
   -> SymbolicPath Pkg (Dir Build)
@@ -425,30 +478,27 @@ linkExecutable
   -- ^ Run the configured GHC program
   -> LocalBuildInfo
   -> IO ()
-linkExecutable linkerOpts (wantedWays, buildOpts) targetDir targetName runGhcProg lbi = do
-  -- When building an executable, we should only "want" one build way.
-  assert (Set.size wantedWays == 1) $
-    forM_ wantedWays $ \way -> do
-      let baseOpts = buildOpts way
-          linkOpts =
-            baseOpts
-              `mappend` linkerOpts
-              `mappend` mempty
-                { -- If there are no input Haskell files we pass -no-hs-main, and
-                  -- assume there is a main function in another non-haskell object
-                  ghcOptLinkNoHsMain = toFlag (ghcOptInputFiles baseOpts == mempty && ghcOptInputScripts baseOpts == mempty)
-                }
-          comp = compiler lbi
+linkExecutable linkerOpts (way, buildOpts) targetDir targetName runGhcProg lbi = do
+  let baseOpts = buildOpts way
+      linkOpts =
+        baseOpts
+          `mappend` linkerOpts
+          `mappend` mempty
+            { -- If there are no input Haskell files we pass -no-hs-main, and
+              -- assume there is a main function in another non-haskell object
+              ghcOptLinkNoHsMain = toFlag (ghcOptInputFiles baseOpts == mempty && ghcOptInputScripts baseOpts == mempty)
+            }
+      comp = compiler lbi
 
-      -- Work around old GHCs not relinking in this
-      -- situation, see #3294
-      let target =
-            targetDir </> makeRelativePathEx (exeTargetName (hostPlatform lbi) targetName)
-      when (compilerVersion comp < mkVersion [7, 7]) $ do
-        let targetPath = interpretSymbolicPathLBI lbi target
-        e <- doesFileExist targetPath
-        when e (removeFile targetPath)
-      runGhcProg linkOpts{ghcOptOutputFile = toFlag target}
+  -- Work around old GHCs not relinking in this
+  -- situation, see #3294
+  let target =
+        targetDir </> makeRelativePathEx (exeTargetName (hostPlatform lbi) targetName)
+  when (compilerVersion comp < mkVersion [7, 7]) $ do
+    let targetPath = interpretSymbolicPathLBI lbi target
+    e <- doesFileExist targetPath
+    when e (removeFile targetPath)
+  runGhcProg linkOpts{ghcOptOutputFile = toFlag target}
 
 -- | Link a foreign library component
 linkFLib
@@ -457,7 +507,7 @@ linkFLib
   -> LocalBuildInfo
   -> (GhcOptions)
   -- ^ The linker-specific GHC options
-  -> (Set.Set BuildWay, BuildWay -> GhcOptions)
+  -> (BuildWay, BuildWay -> GhcOptions)
   -- ^ The wanted build ways and corresponding GhcOptions that were
   -- used to compile the modules in that way.
   -> SymbolicPath Pkg (Dir Build)
@@ -466,7 +516,7 @@ linkFLib
   -> (GhcOptions -> IO ())
   -- ^ Run the configured GHC program
   -> IO ()
-linkFLib flib bi lbi linkerOpts (wantedWays, buildOpts) targetDir runGhcProg = do
+linkFLib flib bi lbi linkerOpts (way, buildOpts) targetDir runGhcProg = do
   let
     comp = compiler lbi
 
@@ -498,8 +548,8 @@ linkFLib flib bi lbi linkerOpts (wantedWays, buildOpts) targetDir runGhcProg = d
                   else statRtsVanillaLib (rtsStaticInfo rtsInfo)
           ]
 
-    linkOpts :: BuildWay -> GhcOptions
-    linkOpts way = case foreignLibType flib of
+    linkOpts :: GhcOptions
+    linkOpts = case foreignLibType flib of
       ForeignLibNativeShared ->
         (buildOpts way)
           `mappend` linkerOpts
@@ -521,13 +571,10 @@ linkFLib flib bi lbi linkerOpts (wantedWays, buildOpts) targetDir runGhcProg = d
   -- soname on supported platforms.  See also the note for
   -- @flibBuildName@.
   let buildName = flibBuildName lbi flib
-  -- There should not be more than one wanted way when building an flib
-  assert (Set.size wantedWays == 1) $
-    forM_ wantedWays $ \way -> do
-      let outFile = targetDir </> makeRelativePathEx buildName
-      runGhcProg (linkOpts way){ghcOptOutputFile = toFlag outFile}
-      let i = interpretSymbolicPathLBI lbi
-      renameFile (i outFile) (i targetDir </> flibTargetName lbi flib)
+  let outFile = targetDir </> makeRelativePathEx buildName
+  runGhcProg linkOpts{ghcOptOutputFile = toFlag outFile}
+  let i = interpretSymbolicPathLBI lbi
+  renameFile (i outFile) (i targetDir </> flibTargetName lbi flib)
 
 -- | Calculate the RPATHs for the component we are building.
 --
diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs b/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs
index 9c9e55a03bffddcf1f60cd521ee0ceebc9d41bec..0c89d860a1bfe049f1013de877834946f3c8bea5 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build/Modules.hs
@@ -17,6 +17,7 @@ import Distribution.ModuleName (ModuleName)
 import qualified Distribution.PackageDescription as PD
 import Distribution.Pretty
 import Distribution.Simple.Build.Inputs
+import Distribution.Simple.BuildWay
 import Distribution.Simple.Compiler
 import Distribution.Simple.GHC.Build.Utils
 import qualified Distribution.Simple.GHC.Internal as Internal
@@ -102,8 +103,8 @@ buildHaskellModules
   -> SymbolicPath Pkg ('Dir Artifacts)
   -- ^ The path to the build directory for this target, which
   -- has already been created.
-  -> Set.Set BuildWay
-  -- ^ The set of wanted build ways according to user options
+  -> [BuildWay]
+  -- ^ The set of needed build ways according to user options
   -> PreBuildComponentInputs
   -- ^ The context and component being built in it.
   -> IO (BuildWay -> GhcOptions)
@@ -111,7 +112,7 @@ buildHaskellModules
   -- invocation used to compile the component in that 'BuildWay'.
   -- This can be useful in, eg, a linker invocation, in which we want to use the
   -- same options and list the same inputs as those used for building.
-buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci = do
+buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir neededLibWays pbci = do
   -- See Note [Building Haskell Modules accounting for TH]
 
   let
@@ -147,9 +148,6 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci = d
     runGhcProg = runGHC verbosity ghcProg comp platform mbWorkDir
     platform = hostPlatform lbi
 
-    -- See Note [Building Haskell Modules accounting for TH]
-    doingTH = usesTemplateHaskellOrQQ bi
-
     -- We define the base opts which are shared across different build ways in
     -- 'buildHaskellModules'
     baseOpts way =
@@ -200,6 +198,18 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci = d
               (if isLib then True else False)
               ((if isLib then withProfLibDetail else withProfExeDetail) lbi)
         }
+    profDynOpts =
+      (baseOpts ProfDynWay)
+        { ghcOptDynLinkMode = toFlag GhcDynamicOnly -- use -dynamic
+        , -- TODO: Does it hurt to set -fPIC for executables?
+          ghcOptFPic = toFlag True -- use -fPIC
+        , ghcOptProfilingMode = toFlag True
+        , ghcOptProfilingAuto =
+            Internal.profDetailLevelFlag
+              (if isLib then True else False)
+              ((if isLib then withProfLibDetail else withProfExeDetail) lbi)
+        }
+
     -- Options for building both static and dynamic way at the same time, using
     -- the GHC flag -static and -dynamic-too
     dynTooOpts =
@@ -212,45 +222,84 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci = d
         -- (Note that `baseOtps StaticWay = hcStaticOptions`, not hcSharedOpts)
         }
 
+    profDynTooOpts =
+      (baseOpts ProfWay)
+        { ghcOptDynLinkMode = toFlag GhcStaticAndDynamic -- use -dynamic-too
+        , -- TODO: Does it hurt to set -fPIC for executables?
+          ghcOptFPic = toFlag True -- use -fPIC
+        , ghcOptProfilingMode = toFlag True
+        , ghcOptProfilingAuto =
+            Internal.profDetailLevelFlag
+              (if isLib then True else False)
+              ((if isLib then withProfLibDetail else withProfExeDetail) lbi)
+        , ghcOptDynHiSuffix = toFlag (buildWayPrefix ProfDynWay ++ "hi")
+        , ghcOptDynObjSuffix = toFlag (buildWayPrefix ProfDynWay ++ "o")
+        , ghcOptHPCDir = hpcdir Hpc.ProfDyn
+        -- Should we pass hcSharedOpts in the -dynamic-too ghc invocation?
+        -- (Note that `baseOtps StaticWay = hcStaticOptions`, not hcSharedOpts)
+        }
+
     -- Determines how to build for each way, also serves as the base options
     -- for loading modules in 'linkOrLoadComponent'
     buildOpts way = case way of
       StaticWay -> staticOpts
       DynWay -> dynOpts
       ProfWay -> profOpts
-
-    defaultGhcWay = if isDynamic comp then DynWay else StaticWay
+      ProfDynWay -> profDynOpts
 
   -- If there aren't modules, or if we're loading the modules in repl, don't build.
   unless (forRepl || (null inputFiles && null inputModules)) $ liftIO $ do
     -- See Note [Building Haskell Modules accounting for TH]
     let
-      neededWays =
-        wantedWays
-          <> Set.fromList
-            -- TODO: You also don't need to build the GHC way when doing TH if
-            -- you are using an external interpreter!!
-            [defaultGhcWay | doingTH && defaultGhcWay `Set.notMember` wantedWays]
+      neededLibWaysSet = Set.fromList neededLibWays
 
       -- If we need both static and dynamic, use dynamic-too instead of
       -- compiling twice (if we support it)
       useDynamicToo =
-        StaticWay `Set.member` neededWays
-          && DynWay `Set.member` neededWays
+        StaticWay `Set.member` neededLibWaysSet
+          && DynWay `Set.member` neededLibWaysSet
+          && supportsDynamicToo comp
+          && null (hcSharedOptions GHC bi)
+
+      useProfDynamicToo =
+        ProfWay `Set.member` neededLibWaysSet
+          && ProfDynWay `Set.member` neededLibWaysSet
           && supportsDynamicToo comp
           && null (hcSharedOptions GHC bi)
 
+      defaultGhcWay = compilerBuildWay comp
+
+      order w
+        | w == defaultGhcWay = 0
+        | otherwise = fromEnum w + 1
+
       -- The ways we'll build, in order
       orderedBuilds
-        -- If we can use dynamic-too, do it first. The default GHC way can only
-        -- be static or dynamic, so, if we build both right away, any modules
-        -- possibly needed by TH later (e.g. if building profiled) are already built.
+        -- We need to make sure that the way which is the way the compiler is built
+        -- is built first so that Template Haskell works.
+        | useProfDynamicToo && useDynamicToo =
+            if defaultGhcWay `elem` [ProfDynWay, ProfWay]
+              then [buildProfAndProfDynamicToo, buildStaticAndDynamicToo]
+              else [buildStaticAndDynamicToo, buildProfAndProfDynamicToo]
+        | useProfDynamicToo && not useDynamicToo =
+            if defaultGhcWay `elem` [ProfDynWay, ProfWay]
+              then
+                [buildProfAndProfDynamicToo]
+                  ++ (runGhcProg . buildOpts <$> neededLibWays \\ [ProfDynWay, ProfWay])
+              else
+                (runGhcProg . buildOpts <$> neededLibWays \\ [ProfDynWay, ProfWay])
+                  ++ [buildProfAndProfDynamicToo]
         | useDynamicToo =
-            [buildStaticAndDynamicToo]
-              ++ (runGhcProg . buildOpts <$> Set.toList neededWays \\ [StaticWay, DynWay])
+            if defaultGhcWay `elem` [StaticWay, DynWay]
+              then
+                [buildStaticAndDynamicToo]
+                  ++ (runGhcProg . buildOpts <$> neededLibWays \\ [StaticWay, DynWay])
+              else
+                (runGhcProg . buildOpts <$> neededLibWays \\ [StaticWay, DynWay])
+                  ++ [buildStaticAndDynamicToo]
         -- Otherwise, we need to ensure the defaultGhcWay is built first
         | otherwise =
-            runGhcProg . buildOpts <$> sortOn (\w -> if w == defaultGhcWay then 0 else fromEnum w + 1) (Set.toList neededWays)
+            runGhcProg . buildOpts <$> sortOn order neededLibWays
 
       buildStaticAndDynamicToo = do
         runGhcProg dynTooOpts
@@ -264,27 +313,31 @@ buildHaskellModules numJobs ghcProg pkg_descr buildTargetDir wantedWays pbci = d
             -- both ways.
             copyDirectoryRecursive verbosity (i dynDir) (i vanillaDir)
           _ -> return ()
+
+      buildProfAndProfDynamicToo = do
+        runGhcProg profDynTooOpts
+        case (hpcdir Hpc.ProfDyn, hpcdir Hpc.Prof) of
+          (Flag profDynDir, Flag profDir) ->
+            -- When the vanilla and shared library builds are done
+            -- in one pass, only one set of HPC module interfaces
+            -- are generated. This set should suffice for both
+            -- static and dynamically linked executables. We copy
+            -- the modules interfaces so they are available under
+            -- both ways.
+            copyDirectoryRecursive verbosity (i profDynDir) (i profDir)
+          _ -> return ()
      in
       -- REVIEW:ADD? info verbosity "Building Haskell Sources..."
       sequence_ orderedBuilds
   return buildOpts
 
-data BuildWay = StaticWay | DynWay | ProfWay
-  deriving (Eq, Ord, Show, Enum)
-
--- | Returns the object/interface extension prefix for the given build way (e.g. "dyn_" for 'DynWay')
-buildWayPrefix :: BuildWay -> String
-buildWayPrefix = \case
-  StaticWay -> ""
-  ProfWay -> "p_"
-  DynWay -> "dyn_"
-
 -- | Returns the corresponding 'Hpc.Way' for a 'BuildWay'
 buildWayHpcWay :: BuildWay -> Hpc.Way
 buildWayHpcWay = \case
   StaticWay -> Hpc.Vanilla
   ProfWay -> Hpc.Prof
   DynWay -> Hpc.Dyn
+  ProfDynWay -> Hpc.ProfDyn
 
 -- | Returns a function to extract the extra haskell compiler options from a
 -- 'BuildInfo' and 'CompilerFlavor'
@@ -293,6 +346,7 @@ buildWayExtraHcOptions = \case
   StaticWay -> hcStaticOptions
   ProfWay -> hcProfOptions
   DynWay -> hcSharedOptions
+  ProfDynWay -> hcProfSharedOptions
 
 -- | Returns a pair of the Haskell input files and Haskell modules of the
 -- component being built.
diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs b/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs
index fb8bd21351a3281945e573c3333d324a0778b36a..c87d074c2020ae0756239417791a36832640b44d 100644
--- a/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs
+++ b/Cabal/src/Distribution/Simple/GHC/Build/Utils.hs
@@ -13,6 +13,7 @@ import qualified Distribution.ModuleName as ModuleName
 import Distribution.PackageDescription as PD
 import Distribution.PackageDescription.Utils (cabalBug)
 import Distribution.Simple.BuildPaths
+import Distribution.Simple.BuildWay
 import Distribution.Simple.Compiler
 import qualified Distribution.Simple.GHC.Internal as Internal
 import Distribution.Simple.Program.GHC
@@ -47,10 +48,21 @@ findExecutableMain verbosity mbWorkDir buildDir (bnfo, modPath) =
 supportsDynamicToo :: Compiler -> Bool
 supportsDynamicToo = Internal.ghcLookupProperty "Support dynamic-too"
 
+compilerBuildWay :: Compiler -> BuildWay
+compilerBuildWay c =
+  case (isDynamic c, isProfiled c) of
+    (True, True) -> ProfDynWay
+    (True, False) -> DynWay
+    (False, True) -> ProfWay
+    (False, False) -> StaticWay
+
 -- | Is this compiler's RTS dynamically linked?
 isDynamic :: Compiler -> Bool
 isDynamic = Internal.ghcLookupProperty "GHC Dynamic"
 
+isProfiled :: Compiler -> Bool
+isProfiled = Internal.ghcLookupProperty "GHC Profiled"
+
 -- | Should we dynamically link the foreign library, based on its 'foreignLibType'?
 withDynFLib :: ForeignLib -> Bool
 withDynFLib flib =
diff --git a/Cabal/src/Distribution/Simple/Hpc.hs b/Cabal/src/Distribution/Simple/Hpc.hs
index ea1c1368057dffe4619a7166e698955162f41a08..4198d7a66ba6353bda508c5f609ed45a367fb9ab 100644
--- a/Cabal/src/Distribution/Simple/Hpc.hs
+++ b/Cabal/src/Distribution/Simple/Hpc.hs
@@ -58,7 +58,7 @@ import System.Directory (createDirectoryIfMissing, doesFileExist)
 -- -------------------------------------------------------------------------
 -- Haskell Program Coverage
 
-data Way = Vanilla | Prof | Dyn
+data Way = Vanilla | Prof | Dyn | ProfDyn
   deriving (Bounded, Enum, Eq, Read, Show)
 
 hpcDir
@@ -73,6 +73,7 @@ hpcDir distPref way = distPref </> makeRelativePathEx ("hpc" </> wayDir)
       Vanilla -> "vanilla"
       Prof -> "prof"
       Dyn -> "dyn"
+      ProfDyn -> "prof_dyn"
 
 mixDir
   :: SymbolicPath Pkg (Dir Dist)
diff --git a/Cabal/src/Distribution/Simple/LocalBuildInfo.hs b/Cabal/src/Distribution/Simple/LocalBuildInfo.hs
index 35681ee590825a20cfcfbdd0b8be1bc023545a52..dce6ff0f8bb3ccb6f5a9b4b08ea2bd42992e1685 100644
--- a/Cabal/src/Distribution/Simple/LocalBuildInfo.hs
+++ b/Cabal/src/Distribution/Simple/LocalBuildInfo.hs
@@ -36,6 +36,7 @@ module Distribution.Simple.LocalBuildInfo
   , interpretSymbolicPathLBI
   , mbWorkDirLBI
   , absoluteWorkingDirLBI
+  , buildWays
 
     -- * Buildable package components
   , Component (..)
diff --git a/Cabal/src/Distribution/Simple/Setup/Config.hs b/Cabal/src/Distribution/Simple/Setup/Config.hs
index 14e76c7d76900132cd6087c7fbdaeb7a9a4fc4fa..88c970e162f1ef2636db6dc9ca78c3328d89c6f6 100644
--- a/Cabal/src/Distribution/Simple/Setup/Config.hs
+++ b/Cabal/src/Distribution/Simple/Setup/Config.hs
@@ -127,6 +127,8 @@ data ConfigFlags = ConfigFlags
   , configProf :: Flag Bool
   -- ^ Enable profiling in the library
   --  and executables.
+  , configProfShared :: Flag Bool
+  -- ^ Enable shared profiling objects
   , configProfDetail :: Flag ProfDetailLevel
   -- ^ Profiling detail level
   --   in the library and executables.
@@ -286,6 +288,7 @@ instance Eq ConfigFlags where
       && equal configProfExe
       && equal configProf
       && equal configProfDetail
+      && equal configProfShared
       && equal configProfLibDetail
       && equal configConfigureArgs
       && equal configOptimization
@@ -518,6 +521,13 @@ configureOptions showOrParseArgs =
           configProf
           (\v flags -> flags{configProf = v})
           (boolOpt [] [])
+       , option
+          ""
+          ["profiling-shared"]
+          "Build profiling shared libraries"
+          configProfShared
+          (\v flags -> flags{configProfShared = v})
+          (boolOpt [] [])
        , option
           ""
           ["executable-profiling"]
diff --git a/Cabal/src/Distribution/Types/LocalBuildConfig.hs b/Cabal/src/Distribution/Types/LocalBuildConfig.hs
index 9126d92f1ebdcb6fe2faf8d419713da38755859a..ce9064b2f434797d60df7f7ee26b1d0cff12884f 100644
--- a/Cabal/src/Distribution/Types/LocalBuildConfig.hs
+++ b/Cabal/src/Distribution/Types/LocalBuildConfig.hs
@@ -151,6 +151,8 @@ data BuildOptions = BuildOptions
   { withVanillaLib :: Bool
   -- ^ Whether to build normal libs.
   , withProfLib :: Bool
+  -- ^ Whether to build normal libs.
+  , withProfLibShared :: Bool
   -- ^ Whether to build profiling versions of libs.
   , withSharedLib :: Bool
   -- ^ Whether to build shared versions of libs.
@@ -211,6 +213,7 @@ buildOptionsConfigFlags (BuildOptions{..}) =
     , configGHCiLib = toFlag $ withGHCiLib
     , configProfExe = toFlag $ withProfExe
     , configProfLib = toFlag $ withProfLib
+    , configProfShared = toFlag $ withProfLibShared
     , configProf = mempty
     , -- configProfDetail is for exe+lib, but overridden by configProfLibDetail
       -- so we specify both so we can specify independently
diff --git a/Cabal/src/Distribution/Types/LocalBuildInfo.hs b/Cabal/src/Distribution/Types/LocalBuildInfo.hs
index 3f9d8d742682675e87a362a51fcbd7c06ce7f432..f6af8c29c775ab14a03bbe6560c07cc6d5f696b7 100644
--- a/Cabal/src/Distribution/Types/LocalBuildInfo.hs
+++ b/Cabal/src/Distribution/Types/LocalBuildInfo.hs
@@ -28,11 +28,12 @@ module Distribution.Types.LocalBuildInfo
       , withPackageDB
       , withVanillaLib
       , withProfLib
-      , withSharedLib
-      , withStaticLib
+      , withProfLibShared
       , withDynExe
       , withFullyStaticExe
       , withProfExe
+      , withSharedLib
+      , withStaticLib
       , withProfLibDetail
       , withProfExeDetail
       , withOptimization
@@ -82,6 +83,7 @@ module Distribution.Types.LocalBuildInfo
   , neededTargetsInBuildOrder'
   , withNeededTargetsInBuildOrder'
   , testCoverage
+  , buildWays
 
     -- * Functions you SHOULD NOT USE (yet), but are defined here to
 
@@ -111,6 +113,7 @@ import Distribution.Utils.Path
 
 import Distribution.PackageDescription
 import Distribution.Pretty
+import Distribution.Simple.BuildWay
 import Distribution.Simple.Compiler
 import Distribution.Simple.Flag
 import Distribution.Simple.InstallDirs hiding
@@ -169,6 +172,7 @@ pattern LocalBuildInfo
   -> Bool
   -> Bool
   -> Bool
+  -> Bool
   -> ProfDetailLevel
   -> ProfDetailLevel
   -> OptimisationLevel
@@ -201,6 +205,7 @@ pattern LocalBuildInfo
   , withPackageDB
   , withVanillaLib
   , withProfLib
+  , withProfLibShared
   , withSharedLib
   , withStaticLib
   , withDynExe
@@ -252,6 +257,7 @@ pattern LocalBuildInfo
           LBC.BuildOptions
             { withVanillaLib
             , withProfLib
+            , withProfLibShared
             , withSharedLib
             , withStaticLib
             , withDynExe
@@ -429,6 +435,49 @@ testCoverage :: LocalBuildInfo -> Bool
 testCoverage (LocalBuildInfo{exeCoverage = exes, libCoverage = libs}) =
   exes && libs
 
+-- | Returns a list of ways, in the order which they should be built, and the
+-- way we build executable and foreign library components.
+--
+-- Ideally all this info should be fixed at configure time and not dependent on
+-- additional info but `LocalBuildInfo` is per package (not per component) so it's
+-- currently not possible to configure components to be built in certain ways.
+buildWays :: LocalBuildInfo -> (Bool -> [BuildWay], Bool -> BuildWay, BuildWay)
+buildWays lbi =
+  let
+    -- enable-library-profiling (enable (static profiling way)) .p_o
+    -- enable-shared (enabled dynamic way)  .dyn_o
+    -- enable-profiling-shared (enable dyanmic profilng way) .p_dyn_o
+    -- enable-library-vanilla (enable vanilla way) .o
+    --
+    -- enable-executable-dynamic => build dynamic executables
+    -- => --enable-profiling + --enable-executable-dynamic => build dynamic profiled executables
+    -- => --enable-profiling => build vanilla profiled executables
+
+    wantedLibWays is_indef =
+      [ProfDynWay | withProfLibShared lbi && not is_indef]
+        <> [ProfWay | withProfLib lbi]
+        -- I don't see why we shouldn't build with dynamic-- indefinite components.
+        <> [DynWay | withSharedLib lbi && not is_indef]
+        -- MP: Ideally we should have `BuildOptions` on a per component basis, in
+        -- which case this `is_indef` check could be moved to configure time.
+        <> [StaticWay | withVanillaLib lbi || withStaticLib lbi]
+
+    wantedFLibWay is_dyn_flib =
+      case (is_dyn_flib, withProfExe lbi) of
+        (True, True) -> ProfDynWay
+        (False, True) -> ProfWay
+        (True, False) -> DynWay
+        (False, False) -> StaticWay
+
+    wantedExeWay =
+      case (withDynExe lbi, withProfExe lbi) of
+        (True, True) -> ProfDynWay
+        (True, False) -> DynWay
+        (False, True) -> ProfWay
+        (False, False) -> StaticWay
+   in
+    (wantedLibWays, wantedFLibWay, wantedExeWay)
+
 -------------------------------------------------------------------------------
 -- Stub functions to prevent someone from accidentally defining them
 
diff --git a/cabal-install-solver/src/Distribution/Solver/Types/ConstraintSource.hs b/cabal-install-solver/src/Distribution/Solver/Types/ConstraintSource.hs
index 3fdf64bde8933702979c9d1a2d3bc1937b1625cd..55b35212d3ceefc3c6bc48a4735e715229c13a3f 100644
--- a/cabal-install-solver/src/Distribution/Solver/Types/ConstraintSource.hs
+++ b/cabal-install-solver/src/Distribution/Solver/Types/ConstraintSource.hs
@@ -41,6 +41,10 @@ data ConstraintSource =
   -- from Cabal >= 3.11
   | ConstraintSourceMultiRepl
 
+  | ConstraintSourceProfiledDynamic
+  -- | Constraint introduced by --enable-profiling-shared, which requires features
+  -- from Cabal >= 3.13
+
   -- | The source of the constraint is not specified.
   | ConstraintSourceUnknown
 
@@ -72,6 +76,8 @@ showConstraintSource ConstraintSourceConfigFlagOrTarget =
     "config file, command line flag, or user target"
 showConstraintSource ConstraintSourceMultiRepl =
     "--enable-multi-repl"
+showConstraintSource ConstraintSourceProfiledDynamic =
+    "--enable-profiling-shared"
 showConstraintSource ConstraintSourceUnknown = "unknown source"
 showConstraintSource ConstraintSetupCabalMinVersion =
     "minimum version of Cabal used by Setup.hs"
diff --git a/cabal-install/src/Distribution/Client/Config.hs b/cabal-install/src/Distribution/Client/Config.hs
index d9b91c959d023e6ac83710b4aa199a6ea878c2d5..5930ca98c1358dcde57b8d745150efeb1841243a 100644
--- a/cabal-install/src/Distribution/Client/Config.hs
+++ b/cabal-install/src/Distribution/Client/Config.hs
@@ -490,6 +490,7 @@ instance Semigroup SavedConfig where
           , configVanillaLib = combine configVanillaLib
           , configProfLib = combine configProfLib
           , configProf = combine configProf
+          , configProfShared = combine configProfShared
           , configSharedLib = combine configSharedLib
           , configStaticLib = combine configStaticLib
           , configDynExe = combine configDynExe
diff --git a/cabal-install/src/Distribution/Client/Dependency.hs b/cabal-install/src/Distribution/Client/Dependency.hs
index 3f6a7fea32a8864fe2bd5beb4e2399f79ecb204b..2949b4d21d1989791a66aeb98091cd56adb64bc9 100644
--- a/cabal-install/src/Distribution/Client/Dependency.hs
+++ b/cabal-install/src/Distribution/Client/Dependency.hs
@@ -64,6 +64,7 @@ module Distribution.Client.Dependency
   , addDefaultSetupDependencies
   , addSetupCabalMinVersionConstraint
   , addSetupCabalMaxVersionConstraint
+  , addSetupCabalProfiledDynamic
   ) where
 
 import Distribution.Client.Compat.Prelude
@@ -671,6 +672,22 @@ addSetupCabalMaxVersionConstraint maxVersion =
   where
     cabalPkgname = mkPackageName "Cabal"
 
+-- | Add an a lower bound @setup.Cabal >= 3.13@ labeled with 'ConstraintSourceProfiledDynamic'
+addSetupCabalProfiledDynamic
+  :: DepResolverParams
+  -> DepResolverParams
+addSetupCabalProfiledDynamic =
+  addConstraints
+    [ LabeledPackageConstraint
+        ( PackageConstraint
+            (ScopeAnySetupQualifier cabalPkgname)
+            (PackagePropertyVersion $ orLaterVersion (mkVersion [3, 13, 0]))
+        )
+        ConstraintSourceProfiledDynamic
+    ]
+  where
+    cabalPkgname = mkPackageName "Cabal"
+
 upgradeDependencies :: DepResolverParams -> DepResolverParams
 upgradeDependencies = setPreferenceDefault PreferAllLatest
 
diff --git a/cabal-install/src/Distribution/Client/ProjectConfig.hs b/cabal-install/src/Distribution/Client/ProjectConfig.hs
index 99dde932037b886c65320227a8dc923b461704a8..cec000b6a9bd1b3cc6277ecd29bde8243691fad7 100644
--- a/cabal-install/src/Distribution/Client/ProjectConfig.hs
+++ b/cabal-install/src/Distribution/Client/ProjectConfig.hs
@@ -102,9 +102,8 @@ import Distribution.Client.HttpUtils
 import Distribution.Client.Types
 import Distribution.Client.Utils.Parsec (renderParseError)
 
+import Distribution.Solver.Types.ConstraintSource
 import Distribution.Solver.Types.PackageConstraint
-  ( PackageProperty (..)
-  )
 import Distribution.Solver.Types.Settings
 import Distribution.Solver.Types.SourcePackage
 
@@ -116,6 +115,7 @@ import Distribution.Client.Setup
 import Distribution.Client.SrcDist
   ( packageDirToSdist
   )
+import Distribution.Client.Targets
 import Distribution.Client.Types.SourceRepo
   ( SourceRepoList
   , SourceRepositoryPackage (..)
@@ -136,11 +136,6 @@ import Distribution.Fields
   , showPWarning
   )
 import Distribution.Package
-  ( PackageId
-  , PackageName
-  , UnitId
-  , packageId
-  )
 import Distribution.PackageDescription.Parsec
   ( parseGenericPackageDescription
   )
@@ -195,8 +190,6 @@ import Distribution.Verbosity
   , verbose
   )
 import Distribution.Version
-  ( Version
-  )
 
 import qualified Codec.Archive.Tar as Tar
 import qualified Codec.Archive.Tar.Entry as Tar
@@ -317,9 +310,34 @@ resolveSolverSettings
     where
       -- TODO: [required eventually] some of these settings need validation, e.g.
       -- the flag assignments need checking.
+      cabalPkgname = mkPackageName "Cabal"
+
+      profilingDynamicConstraint =
+        ( UserConstraint
+            (UserAnySetupQualifier cabalPkgname)
+            (PackagePropertyVersion $ orLaterVersion (mkVersion [3, 13, 0]))
+        , ConstraintSourceProfiledDynamic
+        )
+
+      profDynEnabledGlobally = fromFlagOrDefault False (packageConfigProfShared projectConfigLocalPackages)
+
+      profDynEnabledAnyLocally =
+        or
+          [ fromFlagOrDefault False (packageConfigProfShared ppc)
+          | (_, ppc) <- Map.toList (getMapMappend projectConfigSpecificPackage)
+          ]
+
+      -- Add a setup.Cabal >= 3.13 constraint if prof+dyn is enabled globally
+      -- or any package in the project enables it.
+      -- Ideally we'd apply this constraint only on the closure of packages requiring prof+dyn,
+      -- but that would require another solver run for marginal advantages that
+      -- will further shrink as 3.13 is adopted.
+      solverCabalLibConstraints =
+        [profilingDynamicConstraint | profDynEnabledGlobally || profDynEnabledAnyLocally]
+
       solverSettingRemoteRepos = fromNubList projectConfigRemoteRepos
       solverSettingLocalNoIndexRepos = fromNubList projectConfigLocalNoIndexRepos
-      solverSettingConstraints = projectConfigConstraints
+      solverSettingConstraints = solverCabalLibConstraints ++ projectConfigConstraints
       solverSettingPreferences = projectConfigPreferences
       solverSettingFlagAssignment = packageConfigFlagAssignment projectConfigLocalPackages
       solverSettingFlagAssignments =
diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs
index ddb6f6152649f66a3f2b62d986a411708cda1c31..3d4dc29d8a0f7d218e67a2f1cdbe450c1818c79f 100644
--- a/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs
+++ b/cabal-install/src/Distribution/Client/ProjectConfig/Legacy.hs
@@ -768,6 +768,7 @@ convertLegacyPerPackageFlags
         , configFullyStaticExe = packageConfigFullyStaticExe
         , configProfExe = packageConfigProfExe
         , configProf = packageConfigProf
+        , configProfShared = packageConfigProfShared
         , configProfDetail = packageConfigProfDetail
         , configProfLibDetail = packageConfigProfLibDetail
         , configConfigureArgs = packageConfigConfigureArgs
@@ -1074,6 +1075,7 @@ convertToLegacyAllPackageConfig
           , configFullyStaticExe = mempty
           , configProfExe = mempty
           , configProf = mempty
+          , configProfShared = mempty
           , configProfDetail = mempty
           , configProfLibDetail = mempty
           , configConfigureArgs = mempty
@@ -1150,6 +1152,7 @@ convertToLegacyPerPackageConfig PackageConfig{..} =
         , configFullyStaticExe = packageConfigFullyStaticExe
         , configProfExe = packageConfigProfExe
         , configProf = packageConfigProf
+        , configProfShared = packageConfigProfShared
         , configProfDetail = packageConfigProfDetail
         , configProfLibDetail = packageConfigProfLibDetail
         , configConfigureArgs = packageConfigConfigureArgs
@@ -1545,11 +1548,13 @@ legacyPackageConfigFieldDescrs =
         , "program-suffix"
         , "library-vanilla"
         , "library-profiling"
+        , "library-vanilla"
         , "shared"
         , "static"
         , "executable-dynamic"
         , "executable-static"
         , "profiling"
+        , "profiling-shared"
         , "executable-profiling"
         , "profiling-detail"
         , "library-profiling-detail"
diff --git a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs
index 2a6f9589cbb5104453952d5d13de6e20c6463a24..08c27b00a3dd8a516fbffa7a215809ba2d8b0dd2 100644
--- a/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs
+++ b/cabal-install/src/Distribution/Client/ProjectConfig/Types.hs
@@ -265,6 +265,7 @@ data PackageConfig = PackageConfig
   , packageConfigFullyStaticExe :: Flag Bool
   , packageConfigProf :: Flag Bool -- TODO: [code cleanup] sort out
   , packageConfigProfLib :: Flag Bool --      this duplication
+  , packageConfigProfShared :: Flag Bool
   , packageConfigProfExe :: Flag Bool --      and consistency
   , packageConfigProfDetail :: Flag ProfDetailLevel
   , packageConfigProfLibDetail :: Flag ProfDetailLevel
diff --git a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs
index 2d963b0e07ff14e3497e48f0f40e62b64cc47533..7f26ac123825bbbc4a9c24041eac0d70689b0ce0 100644
--- a/cabal-install/src/Distribution/Client/ProjectOrchestration.hs
+++ b/cabal-install/src/Distribution/Client/ProjectOrchestration.hs
@@ -1061,7 +1061,7 @@ printPlan
             nubFlag x (Setup.Flag x') | x == x' = Setup.NoFlag
             nubFlag _ f = f
 
-            (tryLibProfiling, tryExeProfiling) =
+            (tryLibProfiling, tryLibProfilingShared, tryExeProfiling) =
               computeEffectiveProfiling fullConfigureFlags
 
             partialConfigureFlags =
@@ -1072,7 +1072,8 @@ printPlan
                     nubFlag tryExeProfiling (configProfExe fullConfigureFlags)
                 , configProfLib =
                     nubFlag tryLibProfiling (configProfLib fullConfigureFlags)
-                    -- Maybe there are more we can add
+                , configProfShared =
+                    nubFlag tryLibProfilingShared (configProfShared fullConfigureFlags)
                 }
          in -- Not necessary to "escape" it, it's just for user output
             unwords . ("" :) $
diff --git a/cabal-install/src/Distribution/Client/ProjectPlanning.hs b/cabal-install/src/Distribution/Client/ProjectPlanning.hs
index efc4ebbd1e4cdd35429c531506a321e246c62067..d0f696be957bfbcb0f807687519c193da3386dcc 100644
--- a/cabal-install/src/Distribution/Client/ProjectPlanning.hs
+++ b/cabal-install/src/Distribution/Client/ProjectPlanning.hs
@@ -165,6 +165,8 @@ import Distribution.Simple.LocalBuildInfo
   , componentName
   , pkgComponents
   )
+
+import Distribution.Simple.BuildWay
 import Distribution.Simple.PackageIndex (InstalledPackageIndex)
 import Distribution.Simple.Program
 import Distribution.Simple.Program.Db
@@ -1627,13 +1629,18 @@ elaborateInstallPlan
                 (map fst src_comps)
             let whyNotPerComp = why_not_per_component src_comps
             case NE.nonEmpty whyNotPerComp of
-              Nothing -> return comps
+              Nothing -> do
+                elaborationWarnings
+                return comps
               Just notPerCompReasons -> do
                 checkPerPackageOk comps notPerCompReasons
-                return
-                  [ elaborateSolverToPackage notPerCompReasons spkg g $
-                      comps ++ maybeToList setupComponent
-                  ]
+                pkgComp <-
+                  elaborateSolverToPackage
+                    notPerCompReasons
+                    spkg
+                    g
+                    (comps ++ maybeToList setupComponent)
+                return [pkgComp]
           Left cns ->
             dieProgress $
               hang
@@ -1696,7 +1703,7 @@ elaborateInstallPlan
                   <+> fsep (punctuate comma $ map (text . whyNotPerComponent) $ toList reasons)
           -- TODO: Maybe exclude Backpack too
 
-          elab0 = elaborateSolverToCommon spkg
+          (elab0, elaborationWarnings) = elaborateSolverToCommon spkg
           pkgid = elabPkgSourceId elab0
           pd = elabPkgDescription elab0
 
@@ -1992,7 +1999,7 @@ elaborateInstallPlan
         -> SolverPackage UnresolvedPkgLoc
         -> ComponentsGraph
         -> [ElaboratedConfiguredPackage]
-        -> ElaboratedConfiguredPackage
+        -> LogProgress ElaboratedConfiguredPackage
       elaborateSolverToPackage
         pkgWhyNotPerComponent
         pkg@( SolverPackage
@@ -2003,13 +2010,14 @@ elaborateInstallPlan
                 _exe_deps0
               )
         compGraph
-        comps =
+        comps = do
           -- Knot tying: the final elab includes the
           -- pkgInstalledId, which is calculated by hashing many
           -- of the other fields of the elaboratedPackage.
-          elab
+          elaborationWarnings
+          return elab
           where
-            elab0@ElaboratedConfiguredPackage{..} =
+            (elab0@ElaboratedConfiguredPackage{..}, elaborationWarnings) =
               elaborateSolverToCommon pkg
 
             elab1 =
@@ -2095,7 +2103,7 @@ elaborateInstallPlan
 
       elaborateSolverToCommon
         :: SolverPackage UnresolvedPkgLoc
-        -> ElaboratedConfiguredPackage
+        -> (ElaboratedConfiguredPackage, LogProgress ())
       elaborateSolverToCommon
         pkg@( SolverPackage
                 (SourcePackage pkgid gdesc srcloc descOverride)
@@ -2104,7 +2112,7 @@ elaborateInstallPlan
                 deps0
                 _exe_deps0
               ) =
-          elaboratedPackage
+          (elaboratedPackage, wayWarnings pkgid)
           where
             elaboratedPackage = ElaboratedConfiguredPackage{..}
 
@@ -2212,13 +2220,14 @@ elaborateInstallPlan
             elabBuildOptions =
               LBC.BuildOptions
                 { withVanillaLib = perPkgOptionFlag pkgid True packageConfigVanillaLib -- TODO: [required feature]: also needs to be handled recursively
-                , withSharedLib = pkgid `Set.member` pkgsUseSharedLibrary
+                , withSharedLib = canBuildSharedLibs && pkgid `Set.member` pkgsUseSharedLibrary
                 , withStaticLib = perPkgOptionFlag pkgid False packageConfigStaticLib
                 , withDynExe = perPkgOptionFlag pkgid False packageConfigDynExe
                 , withFullyStaticExe = perPkgOptionFlag pkgid False packageConfigFullyStaticExe
                 , withGHCiLib = perPkgOptionFlag pkgid False packageConfigGHCiLib -- TODO: [required feature] needs to default to enabled on windows still
                 , withProfExe = perPkgOptionFlag pkgid False packageConfigProf
-                , withProfLib = pkgid `Set.member` pkgsUseProfilingLibrary
+                , withProfLib = canBuildProfilingLibs && pkgid `Set.member` pkgsUseProfilingLibrary
+                , withProfLibShared = canBuildProfilingSharedLibs && pkgid `Set.member` pkgsUseProfilingLibraryShared
                 , exeCoverage = perPkgOptionFlag pkgid False packageConfigCoverage
                 , libCoverage = perPkgOptionFlag pkgid False packageConfigCoverage
                 , withOptimization = perPkgOptionFlag pkgid NormalOptimisation packageConfigOptimization
@@ -2377,35 +2386,112 @@ elaborateInstallPlan
       pkgsUseSharedLibrary :: Set PackageId
       pkgsUseSharedLibrary =
         packagesWithLibDepsDownwardClosedProperty needsSharedLib
+
+      needsSharedLib pkgid =
+        fromMaybe
+          compilerShouldUseSharedLibByDefault
+          -- Case 1: --enable-shared or --disable-shared is passed explicitly, honour that.
+          ( case pkgSharedLib of
+              Just v -> Just v
+              Nothing -> case pkgDynExe of
+                -- case 2: If --enable-executable-dynamic is passed then turn on
+                -- shared library generation.
+                Just True ->
+                  -- Case 3: If --enable-profiling is passed, then we are going to
+                  -- build profiled dynamic, so no need for shared libraries.
+                  case pkgProf of
+                    Just True -> if canBuildProfilingSharedLibs then Nothing else Just True
+                    _ -> Just True
+                -- But don't necessarily turn off shared library generation if
+                -- --disable-executable-dynamic is passed. The shared objects might
+                -- be needed for something different.
+                _ -> Nothing
+          )
         where
-          needsSharedLib pkg =
-            fromMaybe
-              compilerShouldUseSharedLibByDefault
-              (liftM2 (||) pkgSharedLib pkgDynExe)
-            where
-              pkgid = packageId pkg
-              pkgSharedLib = perPkgOptionMaybe pkgid packageConfigSharedLib
-              pkgDynExe = perPkgOptionMaybe pkgid packageConfigDynExe
+          pkgSharedLib = perPkgOptionMaybe pkgid packageConfigSharedLib
+          pkgDynExe = perPkgOptionMaybe pkgid packageConfigDynExe
+          pkgProf = perPkgOptionMaybe pkgid packageConfigProf
 
       -- TODO: [code cleanup] move this into the Cabal lib. It's currently open
       -- coded in Distribution.Simple.Configure, but should be made a proper
       -- function of the Compiler or CompilerInfo.
       compilerShouldUseSharedLibByDefault =
         case compilerFlavor compiler of
-          GHC -> GHC.isDynamic compiler
+          GHC -> GHC.compilerBuildWay compiler == DynWay && canBuildSharedLibs
           GHCJS -> GHCJS.isDynamic compiler
           _ -> False
 
+      compilerShouldUseProfilingLibByDefault =
+        case compilerFlavor compiler of
+          GHC -> GHC.compilerBuildWay compiler == ProfWay && canBuildProfilingLibs
+          _ -> False
+
+      compilerShouldUseProfilingSharedLibByDefault =
+        case compilerFlavor compiler of
+          GHC -> GHC.compilerBuildWay compiler == ProfDynWay && canBuildProfilingSharedLibs
+          _ -> False
+
+      -- Returns False if we definitely can't build shared libs
+      canBuildWayLibs predicate = case predicate compiler of
+        Just can_build -> can_build
+        -- If we don't know for certain, just assume we can
+        -- which matches behaviour in previous cabal releases
+        Nothing -> True
+
+      canBuildSharedLibs = canBuildWayLibs dynamicSupported
+      canBuildProfilingLibs = canBuildWayLibs profilingVanillaSupported
+      canBuildProfilingSharedLibs = canBuildWayLibs profilingDynamicSupported
+
+      wayWarnings pkg = do
+        when
+          (needsProfilingLib pkg && not canBuildProfilingLibs)
+          (warnProgress (text "Compiler does not support building p libraries, profiling is disabled"))
+        when
+          (needsSharedLib pkg && not canBuildSharedLibs)
+          (warnProgress (text "Compiler does not support building dyn libraries, dynamic libraries are disabled"))
+        when
+          (needsProfilingLibShared pkg && not canBuildProfilingSharedLibs)
+          (warnProgress (text "Compiler does not support building p_dyn libraries, profiling dynamic libraries are disabled."))
+
       pkgsUseProfilingLibrary :: Set PackageId
       pkgsUseProfilingLibrary =
         packagesWithLibDepsDownwardClosedProperty needsProfilingLib
+
+      needsProfilingLib pkg =
+        fromFlagOrDefault compilerShouldUseProfilingLibByDefault (profBothFlag <> profLibFlag)
         where
-          needsProfilingLib pkg =
-            fromFlagOrDefault False (profBothFlag <> profLibFlag)
-            where
-              pkgid = packageId pkg
-              profBothFlag = lookupPerPkgOption pkgid packageConfigProf
-              profLibFlag = lookupPerPkgOption pkgid packageConfigProfLib
+          pkgid = packageId pkg
+          profBothFlag = lookupPerPkgOption pkgid packageConfigProf
+          profLibFlag = lookupPerPkgOption pkgid packageConfigProfLib
+
+      pkgsUseProfilingLibraryShared :: Set PackageId
+      pkgsUseProfilingLibraryShared =
+        packagesWithLibDepsDownwardClosedProperty needsProfilingLibShared
+
+      needsProfilingLibShared pkg =
+        fromMaybe
+          compilerShouldUseProfilingSharedLibByDefault
+          -- case 1: If --enable-profiling-shared is passed explicitly, honour that
+          ( case profLibSharedFlag of
+              Just v -> Just v
+              Nothing -> case pkgDynExe of
+                Just True ->
+                  case pkgProf of
+                    -- case 2: --enable-executable-dynamic + --enable-profiling
+                    -- turn on shared profiling libraries
+                    Just True -> if canBuildProfilingSharedLibs then Just True else Nothing
+                    _ -> Nothing
+                -- But don't necessarily turn off shared library generation is
+                -- --disable-executable-dynamic is passed. The shared objects might
+                -- be needed for something different.
+                _ -> Nothing
+          )
+        where
+          pkgid = packageId pkg
+          profLibSharedFlag = perPkgOptionMaybe pkgid packageConfigProfShared
+          pkgDynExe = perPkgOptionMaybe pkgid packageConfigDynExe
+          pkgProf = perPkgOptionMaybe pkgid packageConfigProf
+
       -- TODO: [code cleanup] unused: the old deprecated packageConfigProfExe
 
       libDepGraph =
@@ -2422,7 +2508,7 @@ elaborateInstallPlan
             libDepGraph
             [ Graph.nodeKey pkg
             | pkg <- SolverInstallPlan.toList solverPlan
-            , property pkg -- just the packages that satisfy the property
+            , property (packageId pkg) -- just the packages that satisfy the property
             -- TODO: [nice to have] this does not check the config consistency,
             -- e.g. a package explicitly turning off profiling, but something
             -- depending on it that needs profiling. This really needs a separate
@@ -3837,7 +3923,7 @@ setupHsConfigureFlags
     sanityCheckElaboratedConfiguredPackage
       sharedConfig
       elab
-      (Cabal.ConfigFlags{..})
+      Cabal.ConfigFlags{..}
     where
       Cabal.ConfigFlags
         { configVanillaLib
@@ -3848,6 +3934,7 @@ setupHsConfigureFlags
         , configGHCiLib
         , -- , configProfExe -- overridden
         configProfLib
+        , configProfShared
         , -- , configProf -- overridden
         configProfDetail
         , configProfLibDetail
diff --git a/cabal-install/src/Distribution/Client/Setup.hs b/cabal-install/src/Distribution/Client/Setup.hs
index 8fea76bae3b99bd9cd55a7dbad21940b5419de6a..0df20fb456955e0bbc9c5328f738e5e9f294f55b 100644
--- a/cabal-install/src/Distribution/Client/Setup.hs
+++ b/cabal-install/src/Distribution/Client/Setup.hs
@@ -679,7 +679,7 @@ filterConfigureFlags' :: ConfigFlags -> Version -> ConfigFlags
 filterConfigureFlags' flags cabalLibVersion
   -- NB: we expect the latest version to be the most common case,
   -- so test it first.
-  | cabalLibVersion >= mkVersion [3, 11, 0] = flags_latest
+  | cabalLibVersion >= mkVersion [3, 13, 0] = flags_latest
   -- The naming convention is that flags_version gives flags with
   -- all flags *introduced* in version eliminated.
   -- It is NOT the latest version of Cabal library that
@@ -701,6 +701,7 @@ filterConfigureFlags' flags cabalLibVersion
   | cabalLibVersion < mkVersion [2, 5, 0] = flags_2_5_0
   | cabalLibVersion < mkVersion [3, 7, 0] = flags_3_7_0
   | cabalLibVersion < mkVersion [3, 11, 0] = flags_3_11_0
+  | cabalLibVersion < mkVersion [3, 13, 0] = flags_3_13_0
   | otherwise = error "the impossible just happened" -- see first guard
   where
     flags_latest =
@@ -712,8 +713,15 @@ filterConfigureFlags' flags cabalLibVersion
           configConstraints = []
         }
 
-    flags_3_11_0 =
+    flags_3_13_0 =
+      -- Earlier Cabal versions don't understand about ..
       flags_latest
+        { -- Building profiled shared libraries
+          configProfShared = NoFlag
+        }
+
+    flags_3_11_0 =
+      flags_3_13_0
         { -- It's too late to convert configPromisedDependencies to anything
           -- meaningful, so we just assert that it's empty.
           -- We add a Cabal>=3.11 constraint before solving when multi-repl is
@@ -783,7 +791,7 @@ filterConfigureFlags' flags cabalLibVersion
     -- Cabal < 1.23 doesn't know about '--profiling-detail'.
     -- Cabal < 1.23 has a hacked up version of 'enable-profiling'
     -- which we shouldn't use.
-    (tryLibProfiling, tryExeProfiling) = computeEffectiveProfiling flags
+    (tryLibProfiling, _tryLibProfilingShared, tryExeProfiling) = computeEffectiveProfiling flags
     flags_1_23_0 =
       flags_1_25_0
         { configProfDetail = NoFlag
diff --git a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs
index 946e0bf48fdba46321ed2182f5adb7caa7cd1548..2c4de05a9a27558179b6a274687516469e860462 100644
--- a/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs
+++ b/cabal-install/tests/UnitTests/Distribution/Client/ProjectConfig.hs
@@ -683,6 +683,7 @@ instance Arbitrary PackageConfig where
       <*> arbitrary
       <*> arbitrary
       <*> arbitrary
+      <*> arbitrary
       <*> shortListOf 5 arbitraryShortToken
       <*> arbitrary
       <*> arbitrary
@@ -751,6 +752,7 @@ instance Arbitrary PackageConfig where
       , packageConfigFullyStaticExe = x50
       , packageConfigProf = x07
       , packageConfigProfLib = x08
+      , packageConfigProfShared = x08_1
       , packageConfigProfExe = x09
       , packageConfigProfDetail = x10
       , packageConfigProfLibDetail = x11
@@ -814,6 +816,7 @@ instance Arbitrary PackageConfig where
         , packageConfigFullyStaticExe = x50'
         , packageConfigProf = x07'
         , packageConfigProfLib = x08'
+        , packageConfigProfShared = x08_1'
         , packageConfigProfExe = x09'
         , packageConfigProfDetail = x10'
         , packageConfigProfLibDetail = x11'
@@ -866,7 +869,7 @@ instance Arbitrary PackageConfig where
         , packageConfigBenchmarkOptions = x52'
         }
       | ( ( (x00', x01', x02', x03', x04')
-            , (x05', x42', x06', x50', x07', x08', x09')
+            , (x05', x42', x06', x50', x07', x08', x08_1', x09')
             , (x10', x11', x12', x13', x14')
             , (x15', x16', x53', x17', x18', x19')
             )
@@ -883,7 +886,7 @@ instance Arbitrary PackageConfig where
           shrink
             (
               ( (preShrink_Paths x00, preShrink_Args x01, x02, x03, x04)
-              , (x05, x42, x06, x50, x07, x08, x09)
+              , (x05, x42, x06, x50, x07, x08, x08_1, x09)
               , (x10, x11, map NonEmpty x12, x13, x14)
               ,
                 ( x15
diff --git a/cabal-testsuite/PackageTests/ProfShared/Lib.hs b/cabal-testsuite/PackageTests/ProfShared/Lib.hs
new file mode 100644
index 0000000000000000000000000000000000000000..516d174a825cc691c1db5bcf9bc533c1204bcb8a
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfShared/Lib.hs
@@ -0,0 +1,3 @@
+module Lib where
+
+lib = 10
diff --git a/cabal-testsuite/PackageTests/ProfShared/exe/Prof.hs b/cabal-testsuite/PackageTests/ProfShared/exe/Prof.hs
new file mode 100644
index 0000000000000000000000000000000000000000..200915ffefa94c943fb97332c7ce8405ecabd10b
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfShared/exe/Prof.hs
@@ -0,0 +1,5 @@
+module Main where
+
+import Lib
+
+main = print lib
diff --git a/cabal-testsuite/PackageTests/ProfShared/profShared.cabal b/cabal-testsuite/PackageTests/ProfShared/profShared.cabal
new file mode 100644
index 0000000000000000000000000000000000000000..ef348cfecc64ead04370cf6b0358b8f8886434f1
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfShared/profShared.cabal
@@ -0,0 +1,13 @@
+Cabal-Version: 3.8
+Name: prof-shared
+Version: 0.1
+Build-Type: Simple
+
+library
+    exposed-modules: Lib
+    Build-Depends: base
+
+executable Prof
+  main-is: Prof.hs
+  hs-source-dirs: exe
+  build-depends: base, prof-shared
diff --git a/cabal-testsuite/PackageTests/ProfShared/setup.test.hs b/cabal-testsuite/PackageTests/ProfShared/setup.test.hs
new file mode 100644
index 0000000000000000000000000000000000000000..754ff7a290db52b8b1af25fb3c0bccfe889faa97
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfShared/setup.test.hs
@@ -0,0 +1,145 @@
+import Test.Cabal.Prelude
+import Data.List
+import Data.Bifunctor
+
+data BuildWay = StaticWay | DynWay | ProfWay | ProfDynWay
+        deriving (Eq, Ord, Show, Read, Enum)
+
+-- Test building with profiling shared support
+main = do
+    setupTest $ recordMode DoNotRecord $ do
+        has_prof_shared <- hasProfiledSharedLibraries
+        has_shared <- hasSharedLibraries
+        -- Tests are not robust against missing dynamic libraries yet. Would
+        -- be better to fix this.
+        skipUnless "Missing shared libraries" has_shared
+
+    let analyse_result expected r = do
+
+          let ls = lines (resultOutput r)
+
+              library_prefix = "Wanted build ways(True): "
+              executable_prefix = "Wanted build ways(False): "
+
+              get_ways prefix = map (drop (length prefix)) (filter (prefix `isPrefixOf`) ls)
+              library_ways = read_ways (get_ways library_prefix)
+              executable_ways = read_ways (get_ways executable_prefix)
+
+              read_ways raw_ways =
+                case raw_ways of
+                  -- There should only be one
+                  [x] -> (read :: String -> [BuildWay]) x
+                  -- Unless there are none, when we don't built the executable for example
+                  [] -> []
+                  xs -> error "Unexpected number of log lines"
+
+              way = (library_ways, executable_ways)
+
+          unless (bimap (nub . sort) (nub . sort) expected == bimap (nub . sort) (nub . sort) way) $
+            assertFailure $ "Expected:" ++ show expected ++ "\n" ++ "Got:" ++ show way
+
+          requireSuccess r
+    setupTest $ recordMode DoNotRecord $ do
+
+        has_prof_shared <- hasProfiledSharedLibraries
+        has_shared <- hasSharedLibraries
+
+        let v = [ StaticWay ]
+            dyn = [ DynWay | has_shared ]
+            p_dyn = if has_prof_shared then [ProfDynWay] else p
+            p = [ ProfWay ]
+            none = []
+
+        let run_test args expected =  do
+              setup "configure" args
+              res <- setup' "build" []
+              analyse_result expected res
+              setup "clean" []
+
+
+        run_test []
+          (v <> dyn, v)
+
+
+        run_test ["--disable-library-vanilla", "--enable-executable-dynamic"]
+          (dyn, dyn)
+
+        run_test ["--enable-profiling-shared"]
+          (v <> dyn <> p_dyn, v)
+
+        run_test ["--enable-profiling-shared", "--enable-executable-dynamic"]
+          (v <> dyn <> p_dyn, dyn)
+
+        run_test ["--enable-executable-dynamic", "--disable-library-vanilla"]
+          (dyn, dyn)
+
+        run_test ["--enable-profiling"]
+          (v <> dyn <> p, p)
+
+        run_test ["--enable-executable-profiling"]
+          (v <> dyn <> p, p)
+
+        run_test ["--enable-executable-profiling", "--enable-executable-dynamic"]
+          (v <> dyn <> p_dyn, p_dyn)
+
+        run_test ["--enable-profiling", "--enable-executable-dynamic"]
+          (v <> dyn <> p_dyn, p_dyn)
+
+        --v dyn p (p exe)
+        run_test ["--enable-library-profiling", "--enable-executable-profiling"]
+          (v <> dyn <> p, p)
+
+        run_test ["prof-shared", "--enable-profiling-shared", "--disable-library-vanilla", "--disable-shared"]
+          (p_dyn, none)
+
+        -- p p_dyn
+        run_test ["prof-shared", "--enable-profiling-shared", "--enable-library-profiling", "--disable-library-vanilla", "--disable-shared"]
+          (p <> p_dyn, [])
+
+        -- v p p_dyn
+        run_test ["prof-shared","--enable-profiling-shared", "--enable-library-profiling", "--enable-library-vanilla", "--disable-shared"]
+          (v <> p <> p_dyn, none)
+
+        -- v dyn p p_dyn
+        run_test ["prof-shared", "--enable-profiling-shared", "--enable-library-profiling", "--enable-library-vanilla", "--enable-shared"]
+          (v <> dyn <> p <> p_dyn, none)
+
+    let run_cabal_test args expected =  cabalTest $ recordMode DoNotRecord $ do
+          has_prof_shared <- hasProfiledSharedLibraries
+          has_shared <- hasSharedLibraries
+          -- See GHC commit e400b9babdcf11669f963aeec20078fe7ccfca0d
+          -- Only installing profiled library is broken on very old ghc-pkg versions
+          broken_ghc_pkg <- isGhcVersion "<= 8.6.5"
+
+          let cvt_l StaticWay = [ StaticWay ]
+              cvt_l DynWay = [ DynWay | has_shared ]
+              cvt_l ProfDynWay = [ProfDynWay | has_prof_shared ]
+              cvt_l ProfWay = [ ProfWay ]
+
+          let cvt_e StaticWay =  StaticWay
+              cvt_e DynWay = if has_shared then DynWay else error "DynWay"
+              cvt_e ProfDynWay = if has_prof_shared then ProfDynWay else ProfWay
+              cvt_e ProfWay = ProfWay
+
+          unless (broken_ghc_pkg && (fst expected == [ProfWay])) $ do
+            res <- cabal' "v2-build" args
+            void $ analyse_result (bimap (concatMap cvt_l) (map cvt_e) expected) res
+
+    run_cabal_test ["--disable-shared"] ([StaticWay], [StaticWay])
+    run_cabal_test ["--disable-shared", "--disable-executable-dynamic"] ([StaticWay], [StaticWay])
+    run_cabal_test ["--enable-shared"] ([DynWay, StaticWay], [StaticWay])
+    run_cabal_test ["--enable-executable-dynamic"] ([DynWay, StaticWay], [DynWay])
+    run_cabal_test ["--enable-shared", "--disable-library-vanilla", "--enable-executable-dynamic"] ([DynWay], [DynWay])
+
+    run_cabal_test ["--disable-shared", "--disable-library-vanilla", "--enable-profiling"] ([ProfWay], [ProfWay])
+
+    run_cabal_test ["--disable-shared", "--enable-profiling"] ([ProfWay, StaticWay], [ProfWay])
+
+    run_cabal_test ["--disable-shared", "--enable-profiling-shared", "--enable-profiling"] ([ProfDynWay, ProfWay, StaticWay], [ProfWay])
+
+    run_cabal_test ["--disable-shared", "--enable-profiling", "--enable-profiling-shared", "--enable-executable-dynamic"] ([ProfWay, ProfDynWay, StaticWay], [ProfDynWay])
+
+    run_cabal_test ["--enable-profiling", "--enable-executable-dynamic"] ([ProfDynWay, ProfWay, DynWay, StaticWay], [ProfDynWay])
+
+    run_cabal_test ["prof-shared", "--disable-library-profiling", "--enable-profiling", "--enable-executable-dynamic"] ([ProfDynWay, DynWay, StaticWay], [])
+
diff --git a/cabal-testsuite/PackageTests/ProfSharedWarning/Lib.hs b/cabal-testsuite/PackageTests/ProfSharedWarning/Lib.hs
new file mode 100644
index 0000000000000000000000000000000000000000..516d174a825cc691c1db5bcf9bc533c1204bcb8a
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfSharedWarning/Lib.hs
@@ -0,0 +1,3 @@
+module Lib where
+
+lib = 10
diff --git a/cabal-testsuite/PackageTests/ProfSharedWarning/cabal.project b/cabal-testsuite/PackageTests/ProfSharedWarning/cabal.project
new file mode 100644
index 0000000000000000000000000000000000000000..e6fdbadb4398bc0e333947b5fb8021778310d943
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfSharedWarning/cabal.project
@@ -0,0 +1 @@
+packages: .
diff --git a/cabal-testsuite/PackageTests/ProfSharedWarning/exe/Prof.hs b/cabal-testsuite/PackageTests/ProfSharedWarning/exe/Prof.hs
new file mode 100644
index 0000000000000000000000000000000000000000..200915ffefa94c943fb97332c7ce8405ecabd10b
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfSharedWarning/exe/Prof.hs
@@ -0,0 +1,5 @@
+module Main where
+
+import Lib
+
+main = print lib
diff --git a/cabal-testsuite/PackageTests/ProfSharedWarning/profShared.cabal b/cabal-testsuite/PackageTests/ProfSharedWarning/profShared.cabal
new file mode 100644
index 0000000000000000000000000000000000000000..ef348cfecc64ead04370cf6b0358b8f8886434f1
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfSharedWarning/profShared.cabal
@@ -0,0 +1,13 @@
+Cabal-Version: 3.8
+Name: prof-shared
+Version: 0.1
+Build-Type: Simple
+
+library
+    exposed-modules: Lib
+    Build-Depends: base
+
+executable Prof
+  main-is: Prof.hs
+  hs-source-dirs: exe
+  build-depends: base, prof-shared
diff --git a/cabal-testsuite/PackageTests/ProfSharedWarning/setup.out b/cabal-testsuite/PackageTests/ProfSharedWarning/setup.out
new file mode 100644
index 0000000000000000000000000000000000000000..665127128376e52344183ba376c65529bd4d7162
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfSharedWarning/setup.out
@@ -0,0 +1,3 @@
+# Setup configure
+Configuring prof-shared-0.1...
+Warning: Executables will use dynamic linking, but a shared library is not being built. Linking will fail if any executables depend on the library.
diff --git a/cabal-testsuite/PackageTests/ProfSharedWarning/setup_prof.out b/cabal-testsuite/PackageTests/ProfSharedWarning/setup_prof.out
new file mode 100644
index 0000000000000000000000000000000000000000..ad201b3b3912895a6796f90b133f6b50d418b25e
--- /dev/null
+++ b/cabal-testsuite/PackageTests/ProfSharedWarning/setup_prof.out
@@ -0,0 +1,4 @@
+# Setup configure
+Configuring prof-shared-0.1...
+Warning: The flag --enable-executable-profiling is deprecated. Please use --enable-profiling instead.
+Warning: Executables will use profiled dynamic linking, but a profiled shared library is not being built. Linking will fail if any executables depend on the library.
diff --git a/cabal-testsuite/src/Test/Cabal/Prelude.hs b/cabal-testsuite/src/Test/Cabal/Prelude.hs
index b72e427c91bcd130052990538cf26171a5d9a9a0..d110bd9f433ba577378fee992dabd4b972a4000f 100644
--- a/cabal-testsuite/src/Test/Cabal/Prelude.hs
+++ b/cabal-testsuite/src/Test/Cabal/Prelude.hs
@@ -834,22 +834,22 @@ getScriptCacheDirectory script = do
 ------------------------------------------------------------------------
 -- * Skipping tests
 
-hasSharedLibraries  :: TestM Bool
-hasSharedLibraries = do
-    shared_libs_were_removed <- isGhcVersion ">= 7.8"
-    return (not (buildOS == Windows && shared_libs_were_removed))
-
-hasProfiledLibraries :: TestM Bool
-hasProfiledLibraries = do
+testCompilerWithArgs :: [String] -> TestM Bool
+testCompilerWithArgs args = do
     env <- getTestEnv
     ghc_path <- programPathM ghcProgram
     let prof_test_hs = testWorkDir env </> "Prof.hs"
     liftIO $ writeFile prof_test_hs "module Prof where"
     r <- liftIO $ run (testVerbosity env) (Just $ testCurrentDir env)
-                      (testEnvironment env) ghc_path ["-prof", "-c", prof_test_hs]
+                      (testEnvironment env) ghc_path (["-c", prof_test_hs] ++ args)
                       Nothing
     return (resultExitCode r == ExitSuccess)
 
+hasProfiledLibraries, hasProfiledSharedLibraries, hasSharedLibraries :: TestM Bool
+hasProfiledLibraries = testCompilerWithArgs ["-prof"]
+hasProfiledSharedLibraries = testCompilerWithArgs ["-prof", "-dynamic"]
+hasSharedLibraries = testCompilerWithArgs ["-dynamic"]
+
 -- | Check if the GHC that is used for compiling package tests has
 -- a shared library of the cabal library under test in its database.
 --
diff --git a/changelog.d/issue-4816 b/changelog.d/issue-4816
new file mode 100644
index 0000000000000000000000000000000000000000..e0ac7700b7e49f661af3503ef6eb2bd26d41b1b5
--- /dev/null
+++ b/changelog.d/issue-4816
@@ -0,0 +1,23 @@
+synopsis: Add support for building profiled dynamic way
+packages: Cabal Cabal-syntax cabal-install
+prs: #9900
+issues: #4816
+
+description: {
+Add support for profiled dynamic way
+
+New options for cabal.project and ./Setup interface:
+
+* `profiling-shared`: Enable building profiling dynamic way
+* Passing `--enable-profiling` and `--enable-executable-dynamic` builds
+  profiled dynamic executables.
+
+Support for using `profiling-shared` is guarded behind a constraint
+which ensures you are using `Cabal >= 3.13`.
+
+In the cabal file:
+
+* `ghc-prof-shared-options`, for passing options when building in
+  profiling dynamic way
+
+}
diff --git a/changelog.d/issue-4816-2 b/changelog.d/issue-4816-2
new file mode 100644
index 0000000000000000000000000000000000000000..96307c3f83eec458de1d2328dc718b7a5f75c4a0
--- /dev/null
+++ b/changelog.d/issue-4816-2
@@ -0,0 +1,26 @@
+synopsis: Fix interaction of `--*-shared` and `--*-executable-dynamic` options.
+packages: cabal-install
+prs: #9900
+issues: #10050
+
+description: {
+
+If you explicitly request `--disable-shared` it should disable the building of
+a shared library and override any automatic ways this option is turned on.
+
+Passing `--enable-executable-dynamic` turns on `--enable-shared` if the option is
+not specified explicitly.
+
+Before this patch, writing `--disable-shared` on its own would not disable the building of shared libraries. Writing `--disable-shared` and `--disable-executable-dynamic` would disable shared library
+creation (despite `--disable-executable-dynamic` being the default).
+
+Now:
+
+* If you specify `--enable-shared` then shared objects are built.
+* If you specify `--disabled-shared` then shared objects are not built.
+* If you don't explicitly specify whether you want to build shared libraries then
+  * `--enable-executable-dynamic` will automatically turn on building shared libraries
+  * `--enable-executable-dynamic --enable-profiling` will automatically turn on building
+    shared profiling libraries (if supported by your compiler).
+
+}
diff --git a/doc/buildinfo-fields-reference.rst b/doc/buildinfo-fields-reference.rst
index c1ccf418f81726496dad069e2c74df11c3129e1e..cfabe5ee448e959363fbe693a775f9d21549f40d 100644
--- a/doc/buildinfo-fields-reference.rst
+++ b/doc/buildinfo-fields-reference.rst
@@ -387,6 +387,14 @@ ghc-prof-options
     .. math::
         {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet}
 
+ghc-prof-shared-options
+    * Monoidal field
+    * Available since ``cabal-version: 3.14``.
+    * Documentation of :pkg-field:`library:ghc-prof-shared-options`
+
+    .. math::
+        {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet}
+
 ghc-shared-options
     * Monoidal field
     * Documentation of :pkg-field:`library:ghc-shared-options`
@@ -408,6 +416,14 @@ ghcjs-prof-options
     .. math::
         {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet}
 
+ghcjs-prof-shared-options
+    * Monoidal field
+    * Available since ``cabal-version: 3.14``.
+    * Documentation of :pkg-field:`library:ghcjs-prof-shared-options`
+
+    .. math::
+        {\left\{ \mathop{\mathit{hs\text{-}string}}\mid{{[\mathop{\mathord{``}\mathtt{\ }\mathord{"}}]^c}}^+_{} \right\}}^\ast_{\bullet}
+
 ghcjs-shared-options
     * Monoidal field
     * Documentation of :pkg-field:`library:ghcjs-shared-options`
diff --git a/doc/cabal-package-description-file.rst b/doc/cabal-package-description-file.rst
index 450ddc0c0d3a5ec544e2e6f73bbea743232fc543..d560b69e05d93b75586ac49cfa8061ac292ce850 100644
--- a/doc/cabal-package-description-file.rst
+++ b/doc/cabal-package-description-file.rst
@@ -1930,6 +1930,13 @@ system-dependent values for these fields.
     ones specified via :pkg-field:`ghc-options`, and are passed to GHC during
     both the compile and link phases.
 
+.. pkg-field:: ghc-prof-shared-options: token list
+
+    Additional options for GHC when the package is built as shared profiling
+    library. The options specified via this field are combined with the
+    ones specified via :pkg-field:`ghc-options`, and are passed to GHC during
+    both the compile and link phases.
+
 .. pkg-field:: ghcjs-options: token list
 
    Like :pkg-field:`ghc-options` but applies to GHCJS
@@ -1942,6 +1949,10 @@ system-dependent values for these fields.
 
    Like :pkg-field:`ghc-shared-options` but applies to GHCJS
 
+.. pkg-field:: ghcjs-prof-shared-options: token list
+
+   Like :pkg-field:`ghc-prof-shared-options` but applies to GHCJS
+
 .. pkg-field:: includes: filename list
 
     A list of header files to be included in any compilations via C.
diff --git a/doc/setup-commands.rst b/doc/setup-commands.rst
index 20bdafabfae5a702aa1ecb829262c989dfbde306..5ed8077f46bf1066b18fd67b357c2085ba9a3608 100644
--- a/doc/setup-commands.rst
+++ b/doc/setup-commands.rst
@@ -795,10 +795,21 @@ Miscellaneous options
     Build shared library. This implies a separate compiler run to
     generate position independent code as required on most platforms.
 
+    ``--enable-shared`` is enabled automatically if GHC is dynamically linked or
+    you request to build dynamic executables.
+
 .. option:: --disable-shared
 
     (default) Do not build shared library.
 
+.. option:: --enable-profiling-shared
+
+   Build a profiling shared library.
+
+.. option:: --disable-profiling-shared
+
+   (default) Do not built a profiling shared library.
+
 .. option:: --enable-static
 
    Build a static library. This passes ``-staticlib`` to GHC (available