diff --git a/Shakefile.hs b/Shakefile.hs
--- a/Shakefile.hs
+++ b/Shakefile.hs
@@ -16,11 +16,11 @@
 main :: IO ()
 main = shakeMain $ do
   let pats =
-        [ "stack.yaml"
+        [ "stack*.yaml"
         , "Shakefile.hs"
         , "src//*.hs"
         ]
-      pats' = delete "stack.yaml" pats
+      pats' = delete "stack*.yaml" pats
 
   -- | Haskell rules.
   --
diff --git a/shakers.cabal b/shakers.cabal
--- a/shakers.cabal
+++ b/shakers.cabal
@@ -1,5 +1,5 @@
 name: shakers
-version: 0.0.27
+version: 0.0.28
 cabal-version: >=1.22
 build-type: Simple
 license: MIT
@@ -23,7 +23,9 @@
     build-depends:
         base >=4.8 && <5,
         basic-prelude >=0.5.2,
+        deepseq >=1.4.1.1,
         directory >=1.2.2.0,
+        regex-compat >=0.95.1,
         shake >=0.15.11
     default-language: Haskell2010
     hs-source-dirs: src
@@ -33,7 +35,7 @@
     main-is: Shakefile.hs
     build-depends:
         base >=4.8.2.0,
-        shakers >=0.0.27
+        shakers
     default-language: Haskell2010
     ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall
 
diff --git a/src/Development/Shakers.hs b/src/Development/Shakers.hs
--- a/src/Development/Shakers.hs
+++ b/src/Development/Shakers.hs
@@ -6,6 +6,8 @@
 module Development.Shakers
   ( module Exports
   , (<:>)
+  , (<->)
+  , (<=>)
   , timestamp
   , buildFile
   , fakeFile
@@ -55,16 +57,28 @@
   ) where
 
 import BasicPrelude               as Exports hiding ((*>))
+import Control.DeepSeq
 import Data.Char
 import Development.Shake          as Exports
 import Development.Shake.FilePath
 import System.Directory
+import Text.Regex
 
 -- | Join strings with ":"
 --
 (<:>) :: (IsString m, Monoid m) => m -> m -> m
 (<:>) = (<>) . (<> ":")
 
+-- | Join strings with "-"
+--
+(<->) :: (IsString m, Monoid m) => m -> m -> m
+(<->) = (<>) . (<> "-")
+
+-- | Join strings with "="
+--
+(<=>) :: (IsString m, Monoid m) => m -> m -> m
+(<=>) = (<>) . (<> "=")
+
 -- | Unix timestamp.
 --
 timestamp :: Action String
@@ -205,6 +219,11 @@
 m4 :: [String] -> Action String
 m4 = cmdArgs "m4"
 
+-- | tar command.
+--
+tar_ :: FilePath -> [String] -> Action ()
+tar_ d = cmdArgsDir_ d "tar"
+
 -- | AWS command.
 --
 aws :: [String] -> Action String
@@ -336,7 +355,7 @@
 preprocess target file macros =
   target %> \out -> do
     alwaysRerun
-    let f k v = "-D" <> k <> "=" <> v
+    let f k v = "-D" <> k <=> v
     macros' <- macros
     content <- m4 $ file : (uncurry f <$> macros')
     writeFileChanged out content
@@ -502,6 +521,25 @@
   phony "publish" $ do
     need [ file ]
     stack_ dir [ "upload", dir, "--no-signature" ]
+
+  phony "publish-lower" $ do
+    need [file, metaFile "cabalVersion" ]
+    version <- gitVersion dir
+    yaml    <- fromMaybe "stack.yaml" <$> getEnv "STACK_YAML"
+    dist    <- stack dir [ "path", "--dist-dir" ]
+    stack_ dir [ "sdist", dir, "--pvp-bounds", "lower" ]
+    let pkg = dropExtension file
+        hkg = pkg <-> version
+    [sdist] <- getDirectoryFiles dist [ hkg <.> "tar.gz" ]
+    withTempDir $ \d -> do
+      tar_ dist [ "xzf", sdist, "-C", d ]
+      let e = d </> hkg
+          f = e </> file
+      contents <- readFile' f
+      let contents' = subRegex (mkRegex $ pkg <> " >=" <> version) contents pkg
+      contents' `deepseq` writeFile' f contents'
+      copyFile' yaml $ e </> yaml
+      stack_ e [ "upload", e, "--no-signature" ]
 
 -- | Database rules
 --
