diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,9 @@
+## 0.4.0
+
+* Command line uses optparse-applicative with additional options
+* Library profiling support during build
+* Remove cfGlobalFlags (just use package-specific flags)
+
 ## 0.3.1
 
 * Added `justCheck` and `stackage check` command line.
diff --git a/Stackage/BuildConstraints.hs b/Stackage/BuildConstraints.hs
--- a/Stackage/BuildConstraints.hs
+++ b/Stackage/BuildConstraints.hs
@@ -88,12 +88,13 @@
     }
 
 data PackageConstraints = PackageConstraints
-    { pcVersionRange    :: VersionRange
-    , pcMaintainer      :: Maybe Maintainer
-    , pcTests           :: TestState
-    , pcHaddocks        :: TestState
-    , pcBuildBenchmarks :: Bool
-    , pcFlagOverrides   :: Map FlagName Bool
+    { pcVersionRange     :: VersionRange
+    , pcMaintainer       :: Maybe Maintainer
+    , pcTests            :: TestState
+    , pcHaddocks         :: TestState
+    , pcBuildBenchmarks  :: Bool
+    , pcFlagOverrides    :: Map FlagName Bool
+    , pcEnableLibProfile :: Bool
     }
     deriving (Show, Eq)
 instance ToJSON PackageConstraints where
@@ -103,6 +104,7 @@
         , "haddocks" .= pcHaddocks
         , "build-benchmarks" .= pcBuildBenchmarks
         , "flags" .= Map.mapKeysWith const unFlagName pcFlagOverrides
+        , "library-profiling" .= pcEnableLibProfile
         ]
       where
         addMaintainer = maybe id (\m -> (("maintainer" .= m):)) pcMaintainer
@@ -115,6 +117,7 @@
         pcBuildBenchmarks <- o .: "build-benchmarks"
         pcFlagOverrides <- Map.mapKeysWith const mkFlagName <$> o .: "flags"
         pcMaintainer <- o .:? "maintainer"
+        pcEnableLibProfile <- fmap (fromMaybe False) (o .:? "library-profiling")
         return PackageConstraints {..}
 
 -- | The proposed plan from the requirements provided by contributors.
@@ -144,24 +147,24 @@
     siArch = Distribution.System.X86_64
 
 data ConstraintFile = ConstraintFile
-    { cfGlobalFlags             :: Map FlagName Bool
-    , cfPackageFlags            :: Map PackageName (Map FlagName Bool)
+    { cfPackageFlags            :: Map PackageName (Map FlagName Bool)
     , cfSkippedTests            :: Set PackageName
     , cfExpectedTestFailures    :: Set PackageName
     , cfExpectedHaddockFailures :: Set PackageName
     , cfSkippedBenchmarks       :: Set PackageName
     , cfPackages                :: Map Maintainer (Vector Dependency)
     , cfGithubUsers             :: Map Text (Set Text)
+    , cfSkippedLibProfiling     :: Set PackageName
     }
 
 instance FromJSON ConstraintFile where
     parseJSON = withObject "ConstraintFile" $ \o -> do
-        cfGlobalFlags <- goFlagMap <$> o .: "global-flags"
         cfPackageFlags <- (goPackageMap . fmap goFlagMap) <$> o .: "package-flags"
         cfSkippedTests <- getPackages o "skipped-tests"
         cfExpectedTestFailures <- getPackages o "expected-test-failures"
         cfExpectedHaddockFailures <- getPackages o "expected-haddock-failures"
         cfSkippedBenchmarks <- getPackages o "skipped-benchmarks"
+        cfSkippedLibProfiling <- getPackages o "skipped-profiling"
         cfPackages <- o .: "packages"
                   >>= mapM (mapM toDep)
                     . Map.mapKeysWith const Maintainer
@@ -196,6 +199,7 @@
         mpair = lookup name revmap
         pcMaintainer = fmap fst mpair
         pcVersionRange = maybe anyVersion snd mpair
+        pcEnableLibProfile = not (name `member` cfSkippedLibProfiling)
         pcTests
             | name `member` cfSkippedTests = Don'tBuild
             | name `member` cfExpectedTestFailures = ExpectFailure
@@ -205,7 +209,6 @@
             | name `member` cfExpectedHaddockFailures = ExpectFailure
 
             | otherwise = ExpectSuccess
-        pcFlagOverrides = fromMaybe mempty (lookup name cfPackageFlags) ++
-                          cfGlobalFlags
+        pcFlagOverrides = fromMaybe mempty $ lookup name cfPackageFlags
 
     bcGithubUsers = cfGithubUsers
diff --git a/Stackage/CompleteBuild.hs b/Stackage/CompleteBuild.hs
--- a/Stackage/CompleteBuild.hs
+++ b/Stackage/CompleteBuild.hs
@@ -4,6 +4,7 @@
 module Stackage.CompleteBuild
     ( BuildType (..)
     , BumpType (..)
+    , BuildFlags (..)
     , completeBuild
     , justCheck
     ) where
@@ -24,6 +25,14 @@
 import Stackage.Upload
 import System.IO                 (BufferMode (LineBuffering), hSetBuffering)
 
+-- | Flags passed in from the command line.
+data BuildFlags = BuildFlags
+    { bfEnableTests      :: !Bool
+    , bfDoUpload         :: !Bool
+    , bfEnableLibProfile :: !Bool
+    , bfVerbose          :: !Bool
+    } deriving (Show)
+
 data BuildType = Nightly | LTS BumpType
     deriving (Show, Read, Eq, Ord)
 
@@ -149,12 +158,14 @@
 
     putStrLn "Plan seems valid!"
 
-completeBuild :: BuildType -> IO ()
-completeBuild buildType = withManager tlsManagerSettings $ \man -> do
+-- | Make a complete plan, build, test and upload bundle, docs and
+-- distro.
+completeBuild :: BuildType -> BuildFlags -> IO ()
+completeBuild buildType buildFlags = withManager tlsManagerSettings $ \man -> do
     hSetBuffering stdout LineBuffering
 
     putStrLn $ "Loading settings for: " ++ tshow buildType
-    Settings {..} <- getSettings man buildType
+    settings@Settings {..} <- getSettings man buildType
 
     putStrLn $ "Writing build plan to: " ++ fpToText planFile
     encodeFile (fpToString planFile) plan
@@ -170,9 +181,19 @@
             , pbLog = hPut stdout
             , pbJobs = 8
             , pbGlobalInstall = False
+            , pbEnableTests = bfEnableTests buildFlags
+            , pbEnableLibProfiling = bfEnableLibProfile buildFlags
+            , pbVerbose = bfVerbose buildFlags
             }
     performBuild pb >>= mapM_ putStrLn
 
+    when (bfDoUpload buildFlags) $
+        finallyUpload settings man pb
+
+-- | The final part of the complete build process: uploading a bundle,
+-- docs and a distro to hackage.
+finallyUpload :: Settings -> Manager -> PerformBuild -> IO ()
+finallyUpload Settings{..} man pb = do
     putStrLn "Uploading bundle to Stackage Server"
     token <- readFile "/auth-token"
     now <- epochTime
diff --git a/Stackage/PerformBuild.hs b/Stackage/PerformBuild.hs
--- a/Stackage/PerformBuild.hs
+++ b/Stackage/PerformBuild.hs
@@ -61,6 +61,9 @@
     , pbJobs          :: Int
     , pbGlobalInstall :: Bool
     -- ^ Register packages in the global database
+    , pbEnableTests        :: Bool
+    , pbEnableLibProfiling :: Bool
+    , pbVerbose            :: Bool
     }
 
 data PackageInfo = PackageInfo
@@ -298,6 +301,8 @@
         tell' $ "--datadir=" ++ fpToText (pbDataDir pb)
         tell' $ "--docdir=" ++ fpToText (pbDocDir pb)
         tell' $ "--flags=" ++ flags
+        when (pbEnableLibProfiling && pcEnableLibProfile) $
+            tell' "--enable-library-profiling"
       where
         tell' x = tell (x:)
 
@@ -312,7 +317,8 @@
     PackageConstraints {..} = ppConstraints $ piPlan sbPackageInfo
 
     buildLibrary = wf libOut $ \outH -> do
-        let run = runChild outH
+        let run a b = do when pbVerbose $ log' (unwords (a : b))
+                         runChild outH a b
         log' $ "Unpacking " ++ namever
         runParent outH "cabal" ["unpack", namever]
 
@@ -378,7 +384,7 @@
     runTests = wf testOut $ \outH -> do
         let run = runChild outH
 
-        when (pcTests /= Don'tBuild) $ do
+        when (pbEnableTests && pcTests /= Don'tBuild) $ do
             log' $ "Test configure " ++ namever
             run "cabal" $ "configure" : "--enable-tests" : configArgs
 
diff --git a/Stackage/UpdateBuildPlan.hs b/Stackage/UpdateBuildPlan.hs
--- a/Stackage/UpdateBuildPlan.hs
+++ b/Stackage/UpdateBuildPlan.hs
@@ -33,6 +33,7 @@
         , pcHaddocks = maybe ExpectSuccess pcHaddocks moldPC
         , pcBuildBenchmarks = maybe True pcBuildBenchmarks moldPC
         , pcFlagOverrides = maybe mempty pcFlagOverrides moldPC
+        , pcEnableLibProfile = maybe False pcEnableLibProfile moldPC
         }
       where
         moldBP = lookup name bpPackages
diff --git a/app/stackage.hs b/app/stackage.hs
--- a/app/stackage.hs
+++ b/app/stackage.hs
@@ -1,16 +1,75 @@
+{-# LANGUAGE TupleSections #-}
+
+module Main where
+
+import Control.Monad
+import Data.Monoid
+import Data.Version
+import Options.Applicative
+import Paths_stackage (version)
 import Stackage.CompleteBuild
-import System.Environment (getArgs)
 
 main :: IO ()
-main = do
-    args <- getArgs
-    case args of
-        [x] | Just y <- lookup x m -> y
-        _ -> error $ "Expected one argument, one of: " ++ unwords (map fst m)
+main =
+    join $
+    execParser $
+    info
+        (helpOption <*> versionOption <*> config)
+        (header "Stackage" <>
+         fullDesc)
   where
-    m =
-        [ ("nightly", completeBuild Nightly)
-        , ("lts-major", completeBuild $ LTS Major)
-        , ("lts-minor", completeBuild $ LTS Minor)
-        , ("check", justCheck)
-        ]
+    helpOption =
+        abortOption ShowHelpText $
+        long "help" <>
+        help "Show this help text"
+    versionOption =
+        infoOption
+            ("fpbuild version " ++ showVersion version)
+            (long "version" <>
+             help "Show fpbuild version")
+    config =
+        subparser $
+        mconcat
+            [ cmnd
+                  (uncurry completeBuild)
+                  (fmap (Nightly, ) buildFlags)
+                  "nightly"
+                  "Build, test and upload the Nightly snapshot"
+            , cmnd
+                  (uncurry completeBuild)
+                  (fmap (LTS Major, ) buildFlags)
+                  "lts-major"
+                  "Build, test and upload the LTS (major) snapshot"
+            , cmnd
+                  (uncurry completeBuild)
+                  (fmap (LTS Minor, ) buildFlags)
+                  "lts-minor"
+                  "Build, test and upload the LTS (minor) snapshot"
+            , cmnd
+                  (const justCheck)
+                  (pure ())
+                  "check"
+                  "Just check that the build plan is ok"]
+    cmnd exec parse name desc =
+        command name $
+        info
+            (fmap exec parse)
+            (progDesc desc)
+    buildFlags =
+        BuildFlags <$>
+        fmap
+            not
+            (switch
+                 (long "skip-tests" <>
+                  help "Skip build and running the test suites")) <*>
+        fmap
+            not
+            (switch
+                 (long "skip-upload" <>
+                  help "Skip uploading bundle, docs, etc.")) <*>
+        switch
+            (long "enable-library-profiling" <>
+             help "Enable profiling when building") <*>
+        switch
+            (long "verbose" <> short 'v' <>
+             help "Output verbose detail about the build steps")
diff --git a/stackage.cabal b/stackage.cabal
--- a/stackage.cabal
+++ b/stackage.cabal
@@ -1,5 +1,5 @@
 name:                stackage
-version:             0.3.1
+version:             0.4.0
 synopsis:            "Stable Hackage," tools for creating a vetted set of packages from Hackage.
 description:         Please see <http://www.stackage.org/package/stackage> for a description and documentation.
 homepage:            https://github.com/fpco/stackage
@@ -68,6 +68,7 @@
   main-is:             stackage.hs
   build-depends:       base
                      , stackage
+                     , optparse-applicative >= 0.11
   ghc-options:         -rtsopts -threaded -with-rtsopts=-N
 
 test-suite spec
