Wie programm GHC Paketinformationen abrufen?
Frage
Insbesondere ein arbritary Paketnamen gegeben Ich brauche die gleiche library-dirs
Feld abzurufen, die mit dem ghc-pkg describe
Befehl aus dem Inneren eines laufenden Haskell-Programm erhalten werden kann.
Lösung
Hier ist, was ich tun konnte, indem sie in den ghc-pkg
Quellcode späht.
Die getPkgInfos
Funktion gibt die Paketdefinitionen für alle installierten Pakete (hoffentlich einschließlich vom Benutzer installierten Pakete). Mit diesem in der Hand, können Sie die Bibliotheksverzeichnisse und andere Paketinformationen abzurufen. Siehe der Dokumentation Details.
Die GHC_PKGCONF
Variable muss Punkt für die globale Paket-Konfigurationsdatei für Systeme, bei denen es nicht an der üblichen Stelle befindet. ghc-pkg
löst dieses Problem, indem Sie einen Befehlszeile-Flag über einen Wrapper-Skript in Ubuntu zum Beispiel zu empfangen.
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
Ich schrieb diesen Code selbst, aber es wurde von GHC-pkg weitgehend inspiriert (mit einigen Stücken kopiert wörtlich). Der ursprüngliche Code wurde unter einer BSD-Lizenz veröffentlicht, ich denke, das unter dem verteilt werden kann cc-wiki Lizenz alle Stackoverflow Inhalt unter, aber ich bin nicht wirklich sicher. Wie auch immer, wie alles andere, ich habe einige erste Tests und es scheint zu funktionieren, aber auf eigene Gefahr.
Andere Tipps
Das Format der installierten Pakete Datenbank 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])
Dies ist nicht die Paketkonfiguration des Benutzers gehorcht, soll aber ein Anfang sein.
Stellen Sie Duncan Coutts auf der Haskell-Cafe @ oder Kabale Mailinglisten. (Ich meine es ernst. Das ist ein besseres Forum für Cabal Fragen als Stack-Überlauf).
Manchmal muss man nur zu Punkt Menschen an einem anderen Forum.
Wenn Sie Kabalen zu konfigurieren verwenden und bauen Sie Ihre Programm / Bibliothek Sie die automatisch generierte Paths_ verwendet wird, kann * Modul.
Zum Beispiel, wenn Sie eine Datei foo.cabal
haben, Kabale einen Paths_foo
Modul (siehe seine Quelle unter dist/build/autogen
) erzeugen, die Sie importieren können. Dieses Modul exportiert eine Funktion getLibDir :: IO FilePath
, die den Wert Sie suchen.