diff --git a/CHANGELOG b/CHANGELOG
new file mode 100644
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,2 @@
+- 0.1.0.0
+    * Initial release
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright (c) 2014, Jasper Van der Jeugt <m@jaspervdj.be>
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Jasper Van der Jeugt <m@jaspervdj.be> nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/cabal-dependency-licenses.cabal b/cabal-dependency-licenses.cabal
new file mode 100644
--- /dev/null
+++ b/cabal-dependency-licenses.cabal
@@ -0,0 +1,29 @@
+Name:     cabal-dependency-licenses
+Version:  0.1.0.0
+Synopsis: Compose a list of a project's dependencies with their licenses
+
+Description:
+  Compose a list of a project's dependencies with their licenses
+
+License:             BSD3
+License-file:        LICENSE
+Author:              Jasper Van der Jeugt <m@jaspervdj.be>
+Maintainer:          Jasper Van der Jeugt <m@jaspervdj.be>
+Copyright:           2014 Jasper Van der Jeugt
+Category:            Distribution
+Build-type:          Simple
+Extra-source-files:  CHANGELOG
+Cabal-version:       >= 1.10
+
+Executable cabal-dependency-licenses
+  Hs-source-dirs:      src
+  Main-is:             Main.hs
+  Default-language:    Haskell98
+  Ghc-options:         -Wall
+
+  Build-depends:
+    Cabal      >= 1.20 && < 1.21,
+    containers >= 0.5  && < 0.6,
+    base       >= 4    && < 5,
+    directory  >= 1.2  && < 1.3,
+    filepath   >= 1.3  && < 1.4
diff --git a/src/Main.hs b/src/Main.hs
new file mode 100644
--- /dev/null
+++ b/src/Main.hs
@@ -0,0 +1,130 @@
+--------------------------------------------------------------------------------
+module Main
+    ( main
+    ) where
+
+
+--------------------------------------------------------------------------------
+import           Control.Monad                      (forM_, unless)
+import           Data.List                          (foldl', sort)
+import           Data.Maybe                         (catMaybes)
+import           Data.Set                           (Set)
+import qualified Data.Set                           as Set
+import           Distribution.InstalledPackageInfo  (InstalledPackageInfo)
+import qualified Distribution.InstalledPackageInfo  as InstalledPackageInfo
+import qualified Distribution.License               as Cabal
+import qualified Distribution.Package               as Cabal
+import qualified Distribution.Simple.Configure      as Cabal
+import qualified Distribution.Simple.LocalBuildInfo as Cabal
+import qualified Distribution.Simple.PackageIndex   as Cabal
+import qualified Distribution.Text                  as Cabal
+import           System.Directory                   (getDirectoryContents)
+import           System.Exit                        (exitFailure)
+import           System.FilePath                    (takeExtension)
+import           System.IO                          (hPutStrLn, stderr)
+
+
+--------------------------------------------------------------------------------
+putErrLn :: String -> IO ()
+putErrLn = hPutStrLn stderr
+
+
+--------------------------------------------------------------------------------
+existsCabalFile :: IO Bool
+existsCabalFile = do
+    contents <- getDirectoryContents "."
+    return $ any ((== ".cabal") . takeExtension) contents
+
+
+--------------------------------------------------------------------------------
+findTransitiveDependencies
+    :: Cabal.PackageIndex
+    -> Set Cabal.InstalledPackageId
+    -> Set Cabal.InstalledPackageId
+findTransitiveDependencies pkgIdx set0 = go Set.empty (Set.toList set0)
+  where
+    go set []  = set
+    go set (q : queue)
+        | q `Set.member` set = go set queue
+        | otherwise          =
+            case Cabal.lookupInstalledPackageId pkgIdx q of
+                Nothing  ->
+                    -- Not found can mean that the package still needs to be
+                    -- installed (e.g. a component of the target cabal package).
+                    -- We can ignore those.
+                    go set queue
+                Just ipi ->
+                    go (Set.insert q set)
+                        (InstalledPackageInfo.depends ipi ++ queue)
+
+
+--------------------------------------------------------------------------------
+getDependencyInstalledPackageIds
+    :: Cabal.LocalBuildInfo -> Set Cabal.InstalledPackageId
+getDependencyInstalledPackageIds lbi =
+    findTransitiveDependencies (Cabal.installedPkgs lbi) $
+        Set.fromList
+            [ installedPackageId
+            | (_, componentLbi, _)    <- Cabal.componentsConfigs lbi
+            , (installedPackageId, _) <- Cabal.componentPackageDeps componentLbi
+            ]
+
+
+--------------------------------------------------------------------------------
+getDependencyInstalledPackageInfos
+    :: Cabal.LocalBuildInfo -> [InstalledPackageInfo]
+getDependencyInstalledPackageInfos lbi = catMaybes $
+    map (Cabal.lookupInstalledPackageId pkgIdx) $
+    Set.toList (getDependencyInstalledPackageIds lbi)
+  where
+    pkgIdx = Cabal.installedPkgs lbi
+
+
+--------------------------------------------------------------------------------
+groupByLicense
+    :: [InstalledPackageInfo]
+    -> [(Cabal.License, [InstalledPackageInfo])]
+groupByLicense = foldl'
+    (\assoc ipi -> insert (InstalledPackageInfo.license ipi) ipi assoc) []
+  where
+    -- 'Cabal.License' doesn't have an 'Ord' instance so we need to use an
+    -- association list instead of 'Map'. The number of licenses probably won't
+    -- exceed 100 so I think we're alright.
+    insert :: Eq k => k -> v -> [(k, [v])] -> [(k, [v])]
+    insert k v []   = [(k, [v])]
+    insert k v ((k', vs) : kvs)
+        | k == k'   = (k, v : vs) : kvs
+        | otherwise = (k', vs) : insert k v kvs
+
+
+--------------------------------------------------------------------------------
+printDependencyLicenseList
+    :: [(Cabal.License, [InstalledPackageInfo])]
+    -> IO ()
+printDependencyLicenseList byLicense =
+    forM_ byLicense $ \(license, ipis) -> do
+        putStrLn $ "# " ++ Cabal.display license
+        putStrLn ""
+
+        let sortedNames = sort $ map getName ipis
+        forM_ sortedNames $ \name -> putStrLn $ "- " ++ name
+        putStrLn ""
+  where
+    getName =
+        Cabal.display . Cabal.pkgName . InstalledPackageInfo.sourcePackageId
+
+
+--------------------------------------------------------------------------------
+main :: IO ()
+main = do
+    -- Check that we're in a directory with a cabal file
+    existsCabalFile' <- existsCabalFile
+    unless existsCabalFile' $ do
+        putErrLn "No cabal file found in the current directory"
+        exitFailure
+
+    -- Get info and print dependency license list
+    lbi <- Cabal.getPersistBuildConfig "dist"
+    printDependencyLicenseList $
+        groupByLicense $
+        getDependencyInstalledPackageInfos lbi
