Come recuperare a livello di codice GHC informazioni del pacchetto?
Domanda
In particolare, dato un nome di pacchetto arbritary ho bisogno di recuperare lo stesso campo library-dirs
che si può ottenere con il comando ghc-pkg describe
dall'interno di un programma di Haskell in esecuzione.
Soluzione
Ecco quello che ho potuto venire con sbirciando nel codice sorgente ghc-pkg
.
La funzione restituisce i getPkgInfos
definizioni di pacchetto per tutti i pacchetti installati (si spera inclusi i pacchetti installati dall'utente). Con questo nelle vostre mani, è possibile recuperare le directory di libreria e altre informazioni di pacchetto. Vedere la documentazione per i dettagli.
La variabile GHC_PKGCONF
deve puntare al file di configurazione del pacchetto globale per i sistemi in cui non si trova al solito posto. ghc-pkg
risolve questo problema ricevendo un flag della riga di comando tramite uno script involucro in Ubuntu, per esempio.
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
Ho scritto questo codice me stesso, ma è stato in gran parte ispirato da GHC-pkg (con alcuni pezzi copiati pari pari). Il codice originale è stato rilasciato sotto una licenza BSD-style, credo che questo possa essere distribuito sotto la licenza CC-wiki tutti i contenuti StackOverflow è sotto, ma io non sono davvero sicuro. In ogni caso, come qualsiasi altra cosa, ho fatto alcuni test iniziale e sembra funzionare, ma usarlo a vostro rischio e pericolo.
Altri suggerimenti
Il formato del database dei pacchetti installati è 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])
Questa non obbedisce configurazione del pacchetto per l'utente, ma dovrebbe essere un inizio.
Chiedi Duncan Coutts sulla mailing list cabala Haskell-Cafe @ o. (Dico sul serio. Questo è un forum per le domande più Cabal di overflow dello stack).
A volte basta puntare la gente in un forum diverso.
Se stai usando cabala per configurare e costruire il vostro programma / libreria si può utilizzare il Paths_ generato automaticamente * modulo.
Ad esempio, se si dispone di un file foo.cabal
, cabala genererà un modulo Paths_foo
(vedi la sua fonte in dist/build/autogen
), che è possibile importare. Questo modulo esporta una funzione getLibDir :: IO FilePath
, che ha il valore che stai cercando.