Как программно получить информацию о пакете GHC? - PullRequest
1 голос
/ 06 октября 2009

Более конкретно, учитывая имя произвольного пакета, мне нужно извлечь то же поле library-dirs, которое можно получить с помощью команды ghc-pkg describe из работающей программы на Haskell.

Ответы [ 4 ]

3 голосов
/ 08 октября 2009

Вот что я могу придумать, заглянув в исходный код ghc-pkg.

Функция getPkgInfos возвращает определения пакетов для всех установленных пакетов (возможно, включая пакеты, установленные пользователем). Имея это в ваших руках, вы можете получить каталоги библиотеки и другую информацию о пакете. Подробнее см. в документации .

Переменная 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 голос
/ 06 октября 2009

Формат базы данных установленных пакетов: 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])

Это не подчиняется конфигурации пакета пользователя, но должно быть началом.

1 голос
/ 06 октября 2009

Спросите Дункана Кутта в списках рассылки haskell-cafe @ или cabal. (Я серьезно. Это лучший форум для вопросов Cabal, чем переполнение стека).

Иногда вам просто нужно указать людей на другом форуме.

0 голосов
/ 06 октября 2009

Если вы используете cabal для настройки и сборки своей программы / библиотеки, вы можете использовать автоматически сгенерированный модуль Paths_ *.

Например, если у вас есть файл foo.cabal, cabal сгенерирует модуль Paths_foo (см. Его источник в dist/build/autogen), который вы можете импортировать. Этот модуль экспортирует функцию getLibDir :: IO FilePath, которая имеет значение, которое вы ищете.

...