如何以编程方式检索GHC包信息?

时间:2009-10-05 20:05:18

标签: haskell ghc cabal hackage

更具体地说,给定一个任意的包名称,我需要检索可以从正在运行的Haskell程序中使用library-dirs命令获得的相同ghc-pkg describe字段。

4 个答案:

答案 0 :(得分:3)

通过窥视ghc-pkg源代码,我可以提出以下建议。

getPkgInfos函数返回所有已安装软件包的软件包定义(希望包括用户安装的软件包)。有了这个,您可以检索库目录和其他包信息。有关详细信息,请参阅the documentation

GHC_PKGCONF变量需要指向不在通常位置的系统的全局程序包配置文件。例如,ghc-pkg通过Ubuntu中的包装脚本接收命令行标志来解决此问题。

import qualified Config
import qualified System.Info
import Data.List
import Distribution.InstalledPackageInfo
import GHC.Paths
import System.Directory
import System.Environment
import System.FilePath
import System.IO.Error

getPkgInfos :: IO [InstalledPackageInfo]
getPkgInfos = do
    global_conf <-
        catch (getEnv "GHC_PKGCONF")
              (\err ->  if isDoesNotExistError err
                            then do let dir = takeDirectory $ takeDirectory ghc_pkg
                                        path1 = dir </> "package.conf"
                                        path2 = dir </> ".." </> ".." </> ".."
                                                    </> "inplace-datadir"
                                                    </> "package.conf"
                                    exists1 <- doesFileExist path1
                                    exists2 <- doesFileExist path2
                                    if exists1 then return path1
                                       else if exists2 then return path2
                                       else ioError $ userError "Can't find package.conf"
                            else ioError err)

    let global_conf_dir = global_conf ++ ".d"
    global_conf_dir_exists <- doesDirectoryExist global_conf_dir
    global_confs <-
        if global_conf_dir_exists
            then do files <- getDirectoryContents global_conf_dir
                    return  [ global_conf_dir ++ '/' : file
                            | file <- files
                            , isSuffixOf ".conf" file]
            else return []

    user_conf <-
        try (getAppUserDataDirectory "ghc") >>= either
            (\_ -> return [])
            (\appdir -> do
                let subdir = currentArch ++ '-':currentOS ++ '-':ghcVersion
                    user_conf = appdir </> subdir </> "package.conf"
                user_exists <- doesFileExist user_conf
                return (if user_exists then [user_conf] else []))

    let pkg_dbs = user_conf ++ global_confs ++ [global_conf]
    return.concat =<< mapM ((>>= return.read).readFile) pkg_dbs

currentArch = System.Info.arch
currentOS = System.Info.os
ghcVersion = Config.cProjectVersion

我自己编写了这段代码,但它很大程度上受到了ghc-pkg的启发(有些部分是逐字复制的)。原始代码是在BSD风格的许可下获得许可的,我认为这可以在cc-wiki许可下分发所有Stackoverflow内容,但我不确定。无论如何,作为其他任何东西,我做了一些初步测试,它似乎工作,但使用它需要你自己承担风险。

答案 1 :(得分:1)

已安装的软件包数据库的格式为Distribution.InstalledPackageInfo

import Distribution.InstalledPackageInfo
import Distribution.Package
import Distribution.Text
import GHC.Paths
import System
import System.FilePath
main = do
    name:_ <- getArgs
    packages <- fmap read $ readFile $ joinPath [libdir, "package.conf"]
    let matches = filter ((PackageName name ==) . pkgName . package) packages
    mapM_ (print . libraryDirs) (matches :: [InstalledPackageInfo_ String])

这不符合用户的软件包配置,但应该是一个开始。

答案 2 :(得分:1)

在haskell-cafe @或cabal邮件列表上询问Duncan Coutts。 (我很认真。对于Cabal问题而言,这是一个比堆栈溢出更好的论坛)。

有时你只需要将人们指向不同的论坛。

答案 3 :(得分:0)

如果您使用cabal配置和构建程序/库,则可以使用自动生成的Paths_ *模块。

例如,如果您有foo.cabal文件,则cabal会生成Paths_foo模块(请参阅dist/build/autogen下的来源),您可以导入该模块。该模块导出一个函数getLibDir :: IO FilePath,它具有您正在寻找的值。