Question

Plus précisément, étant donné un nom de package arbritary je dois récupérer le même champ de library-dirs qui peut être obtenu avec la commande ghc-pkg describe à l'intérieur d'un programme Haskell en cours d'exécution.

Était-ce utile?

La solution

Voici ce que je pouvais venir avec par jeter un oeil dans le code source de ghc-pkg.

La fonction getPkgInfos renvoie les définitions de paquet pour tous les paquets installés (nous l'espérons, y compris les paquets installés par l'utilisateur). Avec cela dans vos mains, vous pouvez récupérer les répertoires de bibliothèques et d'autres informations sur le package. Voir la documentation détails.

La variable GHC_PKGCONF doit pointer vers le fichier de configuration de package globale pour les systèmes où il n'est pas situé à l'endroit habituel. ghc-pkg résout ce problème en recevant un indicateur de ligne de commande via un script wrapper dans Ubuntu, par exemple.

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

J'ai écrit ce code moi-même, mais il a été largement inspiré par GHC-pkg (avec quelques morceaux copiés tels quels). Le code original a été distribué sous licence une licence de type BSD, je pense que cela peut être distribué sous la licence cc-wiki tout le contenu Stackoverflow est sous, mais je ne suis pas vraiment sûr. Quoi qu'il en soit, comme toute autre chose, je fait quelques tests initiaux et il semble fonctionner, mais l'utiliser à vos propres risques.

Autres conseils

Le format de la base de données de paquets installés est 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])

Cela ne respecte pas la configuration du package de l'utilisateur, mais devrait être un début.

Demandez Duncan Coutts sur le haskell-café @ ou listes de diffusion cabale. (Je suis sérieux. C'est un meilleur forum pour les questions Cabal que débordement de la pile).

Parfois, il vous suffit de pointer les gens à un autre forum.

Si vous utilisez cabale pour configurer et construire votre programme / bibliothèque, vous pouvez utiliser le module autogenerated Paths_ *.

Par exemple, si vous avez un fichier foo.cabal, cabale va générer un module Paths_foo (voir sa source sous dist/build/autogen) que vous pouvez importer. Ce module exporte une getLibDir :: IO FilePath fonction qui a la valeur que vous cherchez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top