diff --git a/cabal-flatpak.cabal b/cabal-flatpak.cabal
--- a/cabal-flatpak.cabal
+++ b/cabal-flatpak.cabal
@@ -1,6 +1,6 @@
 Cabal-Version:  2.2
 Name:           cabal-flatpak
-Version:        0.1.2
+Version:        0.1.3
 License:        BSD-3-Clause
 License-File:   LICENSE
 Author:         Henning Thielemann <haskell@henning-thielemann.de>
@@ -20,12 +20,14 @@
 Build-Type:     Simple
 Extra-Source-Files:
   Makefile
+  flatpak.cabal.json
+
+Extra-Doc-Files:
   ReadMe.md
   Changes.md
-  flatpak.cabal.json
 
 Source-Repository this
-  Tag:         0.1.2
+  Tag:         0.1.3
   Type:        darcs
   Location:    https://hub.darcs.net/thielema/cabal-flatpak/
 
@@ -38,20 +40,20 @@
     cabal-plan >=0.5 && <0.8,
     cryptohash-sha256 >=0.11 && <0.12,
     zlib >=0.5.3 && <0.8,
-    tar >=0.5.0.3 && <0.7,
-    http-client-tls >=0.3.5.3 && <0.4,
+    tar >=0.5.0.3 && <0.8,
+    http-client-tls >=0.3.5.3 && <0.5,
     http-client >=0.5.12 && <0.8,
     http-types >=0.10 && <0.13,
     aeson-pretty >=0.8.7 && <0.9,
-    aeson >=2.0 && <2.3,
+    aeson >=2.0 && <2.4,
     yaml >=0.11 && <0.12,
     shell-utility >=0.1 && <0.2,
-    optparse-applicative >=0.11 && <0.19,
+    optparse-applicative >=0.11 && <0.20,
     pathtype >=0.8 && <0.9,
     directory >=1.2.3 && <1.4,
     text >=1.2 && <2.2,
     bytestring >=0.9 && <0.13,
-    containers >=0.5 && <0.8,
+    containers >=0.5 && <0.9,
     utility-ht >=0.0.12 && <0.1,
     base >=4.5 && <5
 
diff --git a/src/Flatpak.hs b/src/Flatpak.hs
--- a/src/Flatpak.hs
+++ b/src/Flatpak.hs
@@ -118,6 +118,7 @@
       typ :: SourceType,
       url :: Maybe String,
       destFilename :: Maybe String,
+      dest :: Maybe String,
       sha256 :: Maybe Plan.Sha256
    } deriving (Show)
 
@@ -127,6 +128,7 @@
          <*> (parseSourceType o =<< o .: "type")
          <*> o .:? ("url", Nothing)
          <*> o .:? ("dest-filename", Nothing)
+         <*> o .:? ("dest", Nothing)
          <*> o .:? ("sha256", Nothing)
 
 instance ToJSON Source where
@@ -134,6 +136,7 @@
       (pairsFromSourceType . typ) <>
       ("url" .=? (url, Nothing)) <>
       ("dest-filename" .=? (destFilename, Nothing)) <>
+      ("dest" .=? (dest, Nothing)) <>
       ("sha256" .=? (sha256, Nothing)) <>
       mempty
 
diff --git a/src/Generate.hs b/src/Generate.hs
--- a/src/Generate.hs
+++ b/src/Generate.hs
@@ -12,6 +12,7 @@
 import qualified Data.Text as Text
 import Data.Foldable (foldMap)
 import Data.Map (Map)
+import Data.Maybe.HT (toMaybe)
 import Data.Bool.HT (if')
 
 import Text.Printf (printf)
@@ -31,6 +32,9 @@
 projectMain project =
    (Flatpak.mainPackage project, Flatpak.mainSources project)
 
+projectMainExe :: Flatpak.Cabal -> String
+projectMainExe = Flatpak.command . Flatpak.base
+
 matchName :: String -> Plan.Unit -> Bool
 matchName expected unit =
    case Plan.uPId unit of
@@ -109,13 +113,14 @@
                   Just $
                   ghcDirUrl compiler ++ ghcArchive compiler arch,
                Flatpak.destFilename = Nothing,
+               Flatpak.dest = Nothing,
                Flatpak.sha256 = Just hash
              }]
       }
 
 type RevisedUnit = (Plan.Unit, Package.Revision)
 
-packageURLs :: RevisedUnit -> (String, String, String)
+packageURLs :: RevisedUnit -> (String, String, String, String)
 packageURLs (pkg, revision) =
    let pkgId@(Plan.PkgId (Plan.PkgName name) _version) = Plan.uPId pkg
        pkgName = Text.unpack name
@@ -124,24 +129,31 @@
          pkgNameVer pkgNameVer,
        printf "https://hackage.haskell.org/package/%s/revision/%d.cabal"
          pkgNameVer revision,
+       pkgNameVer,
        printf "%s.cabal" pkgName)
 
+reviseToSubdir :: Flatpak.SourceType -> Bool
+reviseToSubdir (Flatpak.Archive n) = n == 0
+reviseToSubdir _ = False
+
 packageSources ::
    (String, [Flatpak.Source]) -> Flatpak.SourceType ->
    RevisedUnit -> [Flatpak.Source]
 packageSources (mainPkg, mainSrcs) typ pkgRev@(pkg,_) =
-   let (pkgUrl, cabalUrl, cabalPath) = packageURLs pkgRev
+   let (pkgUrl, cabalUrl, cabalDest, cabalPath) = packageURLs pkgRev
    in if' (matchName mainPkg pkg && not (null mainSrcs)) mainSrcs $
       Flatpak.Source {
          Flatpak.typ = typ,
          Flatpak.url = Just pkgUrl,
          Flatpak.destFilename = Nothing,
+         Flatpak.dest = Nothing,
          Flatpak.sha256 = Plan.uSha256 pkg
       } :
       Flatpak.Source {
          Flatpak.typ = Flatpak.File,
          Flatpak.url = Just cabalUrl,
          Flatpak.destFilename = Just cabalPath,
+         Flatpak.dest = toMaybe (reviseToSubdir typ) cabalDest,
          Flatpak.sha256 = Plan.uCabalSha256 pkg
       } :
       []
@@ -210,17 +222,17 @@
 cabalHash arch =
    case arch of
       Flatpak.I386 -> Just $
-         "b2da736cc27609442b10f77fc1a687aba603a7a33045b722dbf1a0066fade198"
+         "c03043d5c9dfed9a1a4c795e4260221986dcdde28a68b909fcf4ccc07d7dd7b5"
       Flatpak.X86_64 -> Just $
-         "6136c189ffccaa39916f9cb5788f757166444a2d0c473b987856a79ecbf0c714"
+         "97e61bcd143f0b8a181ea2261a1de587b58fa9f84d123b9b9cec4463ae2f41c6"
       _ -> Nothing
 
 cabalInstallModule :: Flatpak.Arch -> Flatpak.Module
 cabalInstallModule arch =
-   let cabalVerName = "cabal-install-2.4.1.0"
+   let cabalVerName = "cabal-install-3.10.3.0"
        url =
          printf
-            "https://downloads.haskell.org/cabal/%s/%s-%s-unknown-linux.tar.xz"
+            "https://downloads.haskell.org/cabal/%s/%s-%s-linux-deb9.tar.xz"
                cabalVerName cabalVerName (archGHC arch)
    in Flatpak.Module {
          Flatpak.name = cabalVerName ++ "-" ++ Flatpak.archString arch,
@@ -237,28 +249,14 @@
                   Flatpak.Archive {Flatpak.stripComponents = 0},
                Flatpak.url = Just url,
                Flatpak.destFilename = Nothing,
+               Flatpak.dest = Nothing,
                Flatpak.sha256 = Plan.parseSha256 . Text.pack =<< cabalHash arch
              }]
       }
 
-reviseCabalScript :: [String]
-reviseCabalScript =
-   "tarball=\"$1\"" :
-   "pkgid=\"$(basename $tarball .tar.gz)\"" :
-   "name=\"$(echo $pkgid | sed -r 's:^(.*)-(.*)$:\\1:')\"" :
-   "ver=\"$(echo $pkgid | sed -r 's:^(.*)-(.*)$:\\2:')\"" :
-   "echo Revising .cabal file for \"$pkgid\"" :
-   "gunzip \"$tarball\"" :
-   "mkdir \"$pkgid\"" :
-   "mv \"$name.cabal\" \"$pkgid\"" :
-   "tar rf \"$pkgid.tar\" \"$pkgid/$name.cabal\"" :
-   "gzip \"$pkgid.tar\"" :
-   []
-
-allInOneModule ::
-   (String, [Flatpak.Source]) -> Options -> [String] ->
-   [RevisedUnit] -> Flatpak.Module
-allInOneModule main (cabalCfgOptions, ghcOptions) postInstall pkgs =
+allInOneModule :: Flatpak.Cabal -> [RevisedUnit] -> Flatpak.Module
+allInOneModule project pkgs =
+   let (cabalCfgOptions, ghcOptions) = projectOptions project in
       Flatpak.Module {
          Flatpak.name = "haskell-parts",
          Flatpak.onlyArches = [],
@@ -266,26 +264,21 @@
          Flatpak.builddir = False,
          Flatpak.configOpts = [],
          Flatpak.buildCommands =
-            "find . -name '*.tar.gz' | while read pkg; do bash revise.sh \"$pkg\"; done" :
             "mkdir .cabal" :
             "touch .cabal/config" :
-            unwords
-               ("cabal --config-file=.cabal/config install" :
-                  "-j$FLATPAK_BUILDER_N_JOBS" :
-                  "--offline --prefix=/app" :
-                  cabalCfgOptions ++ map ghcOption ghcOptions ++
-                  ["*.tar.gz"]) :
+            "echo 'packages: */' > cabal.project" :
+            unwords ("cabal --config-file=.cabal/config -j$FLATPAK_BUILDER_N_JOBS" :
+                     "--offline --store-dir /app/cabal" :
+                     "--installdir=/app/bin" :
+                     ("v2-install exe:" ++ projectMainExe project) :
+                     cabalCfgOptions ++ map ghcOption ghcOptions) :
             [],
-         Flatpak.postInstall = postInstall,
+         Flatpak.postInstall =
+            concatMap Flatpak.postInstallHook $ Flatpak.packageHooks project,
          Flatpak.cleanupModule = [],
          Flatpak.sources =
-            Flatpak.Source {
-               Flatpak.typ = Flatpak.Script reviseCabalScript,
-               Flatpak.url = Nothing,
-               Flatpak.destFilename = Just "revise.sh",
-               Flatpak.sha256 = Nothing
-            } :
-            concatMap (packageSources main Flatpak.File) pkgs
+            concatMap (packageSources (projectMain project) $
+                       Flatpak.Archive {Flatpak.stripComponents = 0}) pkgs
       }
 
 manifestCabalInstall ::
@@ -296,6 +289,12 @@
    base {
       Flatpak.cleanup =
          concatMap (ghcPkgCleanup plan . fst) archs ++ Flatpak.cleanup base,
+      Flatpak.cleanupCommands =
+         ( "find /app/cabal/ghc-* -mindepth 1 " ++
+           "\\( \\( -not -path '*/" ++
+           (fst $ projectMain project) ++
+           "*' -a -path '*/bin/*' \\) -o -path '*/lib/*' \\) -delete" ) :
+         Flatpak.cleanupCommands base,
       Flatpak.modules =
          (map ModuleEmbed $
           concatMap
@@ -303,9 +302,6 @@
                [ghcModule plan arch ghcHash, cabalInstallModule arch])
             archs) ++
          Flatpak.modules base ++
-         (ModuleEmbed $
-          allInOneModule (projectMain project) (projectOptions project)
-            (concatMap Flatpak.postInstallHook $ Flatpak.packageHooks project)
-            pkgs) :
+         (ModuleEmbed $ allInOneModule project pkgs) :
          []
    }
diff --git a/src/Main.hs b/src/Main.hs
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -21,6 +21,7 @@
 
 import Control.Monad (when)
 import Control.Applicative ((<$>))
+import Control.Arrow ((&&&))
 
 import qualified Data.Aeson as Json
 import qualified Data.Yaml as Yaml
@@ -73,7 +74,70 @@
                ++
                printf "%s, %s" xdgDir (Path.toString appDir)
 
+{- |
+Cabal operates on units.
+A package can have multiple units,
+for example a library unit and multiple executable units.
+Each of those units can have its own set of library and executable dependencies.
 
+However, when downloading packages in Flatpak
+we don't differentiate between the units
+and treat all units belonging to the same package as one.
+
+The below heuristic
+merges all units belonging to the same package into one package
+and topologically sorts the packages.
+
+This heuristic can be completely skipped when using the --cabal-install option,
+because in this mode all we need to do is to download all necessary packages
+in any order and cabal will determine the correct order of the units by itself.
+
+The heuristic goes as follows:
+
+1. Build a map between the unit IDs and the package ID that contains it
+2. Get the dependency graph using the cabal-plan API
+3. Group all units belonging to the same package
+   and merge their dependencies to obtain package dependencies
+4. Topologically sort the packages
+5. Take one representative unit for each package
+   and use them in the flatpak.json generation process.
+   This is safe to do as long as the rest of the generator
+   uses information that is common to all units in the same package.
+   Those are: uPId, uSha256, uCabalSha256 and uType.
+
+In certain situations
+this heuristic can still fail to produce a buildable sequence.
+For example, we can have two packages as such:
+Pkg1@(lib1, exe1) and Pkg2@(lib2)
+where the unit lib2 depends on lib1 and exe1 depends on lib2.
+Unit-wise, it is possible to sequence the builds of the units
+that avoids cyclical dependencies.
+But package-wise, it is not possible.
+In such cases and in general
+it is better to enable the --cabal-install option which avoids this problem.
+
+It is also not possible to use the qualified name of the component
+for the 'configure' stage
+and build a package in multiple parts in multiple Flatpak modules.
+This is because the Plan.uComps is not precise enough,
+as the documentation states that in certain situations
+that field may contain more than one value.
+In that case it is impossible to determine the precise component name.
+-}
+getSortedUnits :: Plan.PlanJson -> [Plan.Unit]
+getSortedUnits plan =
+   let
+      allUnits = Plan.pjUnits plan
+      -- Build a mapping from unit ID to package ID
+      unitIdToPkgId unitId = Plan.uPId $ allUnits Map.! unitId
+      -- Here we take one representative unit for a given package.
+      pkgIdToUnit = Map.fromList $ map (Plan.uPId &&& id) $ Map.elems allUnits
+   in filter ((Plan.UnitTypeBuiltin /=) . Plan.uType) $
+      map (pkgIdToUnit Map.!) $ topSort $
+      -- Merge unit groups into packages, merging their dependencies.
+      Map.mapKeysWith Set.union unitIdToPkgId $
+      Map.map (Set.map unitIdToPkgId) $ Plan.planJsonIdGraph plan
+
 main :: IO ()
 main = do
    opt <- OP.execParser Option.info
@@ -105,17 +169,19 @@
 
    let matchExe name comp =
          case comp of Plan.CompNameExe nameExe -> name == nameExe; _ -> False
+   let matchExeUnit name unit =
+         any (matchExe name) $ Map.keys $ Plan.uComps unit
    let mainExe = Text.pack $ Flatpak.command $ Flatpak.base projectJson
    let mainPackage = Flatpak.mainPackage projectJson
-   let units =
-         filter
-            (\unit ->
-               if Generate.matchName mainPackage unit
-                  then any (matchExe mainExe) $ Map.keys $ Plan.uComps unit
-                  else Map.member Plan.CompNameLib $ Plan.uComps unit) $
-         filter ((Plan.UnitTypeBuiltin /=) . Plan.uType) $
-         map (Plan.pjUnits plan Map.!) $ topSort $ Plan.planJsonIdGraph plan
 
+   mainUnit <-
+      case filter (matchExeUnit mainExe) $ Map.elems $ Plan.pjUnits plan of
+         [x] -> return x
+         [] -> fail "main package not found in build plan"
+         _ -> fail "main package found multiple times in build plan"
+
+   let units = getSortedUnits plan
+
    archs <-
       case Option.archs opt of
          [] ->
@@ -138,12 +204,10 @@
    let hackageDir =
          cabalDir </> Path.dir "packages" </> Path.dir "hackage.haskell.org"
 
-   mainVersion <-
-      case filter (Generate.matchName mainPackage) units of
-         [Plan.Unit{Plan.uPId = Plan.PkgId _pkg ver}] ->
-            return $ Retrieve.formatVersion ver
-         [] -> fail "main package not found in build plan"
-         _ -> fail "main package found multiple times in build plan"
+   let mainVersion = case mainUnit of
+         Plan.Unit{Plan.uPId = Plan.PkgId _pkg ver} ->
+            Retrieve.formatVersion ver
+
    (revisions, mainCabalHash) <- do
       tar <- Package.readTar $ hackageDir </> Path.file "01-index.tar.gz"
       either fail return $
diff --git a/src/Option.hs b/src/Option.hs
--- a/src/Option.hs
+++ b/src/Option.hs
@@ -7,7 +7,8 @@
 
 import qualified Shell.Utility.ParseArgument as ParseArg
 import qualified Options.Applicative as OP
-import Options.Applicative (help, metavar, argument, option, long, value, flag)
+import Options.Applicative
+         (help, metavar, argument, option, long, value, switch)
 
 import Control.Applicative (pure, (<*>))
 
@@ -36,7 +37,7 @@
 parseFlags :: OP.Parser T
 parseFlags =
    pure Cons
-    <*> flag False True
+    <*> switch
             (long "cabal-install"
           <> help "Build with one cabal-install (default: build module-wise using Cabal)")
     <*> OP.many
