Cómo recuperar mediante programación la información del paquete GHC?
Pregunta
Más específicamente, dado un nombre de paquete arbritary que necesito para recuperar el mismo campo library-dirs
que se puede obtener con el comando ghc-pkg describe
desde dentro de un programa de Haskell en funcionamiento.
Solución
Esto es lo que podría llegar a por asomándose en el código fuente ghc-pkg
.
La función getPkgInfos
devuelve las definiciones de paquetes para todos los paquetes instalados (esperemos incluidos los paquetes instalados por el usuario). Con esto en sus manos, puede recuperar los directorios de la biblioteca y otra información del paquete. Ver la documentación para detalles.
La variable GHC_PKGCONF
necesita apuntar al archivo de configuración del paquete global para sistemas en los que no se encuentra en el lugar habitual. ghc-pkg
resuelve este problema mediante la recepción de una marca de línea de comandos a través de un script de envoltorio en Ubuntu, por ejemplo.
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
escribí este código a mí mismo, pero estaba inspirado en gran medida por GHC-paquete (con algunas piezas copiadas textualmente). El código original fue licenciado bajo una licencia de tipo BSD, creo que esto puede ser distribuido bajo la licencia CC-wiki de todos los contenidos Stackoverflow es bajo, pero no estoy muy seguro. De todos modos, como cualquier otra cosa, hice algunas pruebas iniciales y parece que funciona, sino que lo utiliza a su propio riesgo.
Otros consejos
El formato de la base de datos instalado paquetes es 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])
Esto no obedece configuración del paquete del usuario, pero debe ser un comienzo.
Haz Duncan Coutts en la listas de correo Cabal Haskell-café o @. (Lo digo en serio. Esa es una mejor foro de preguntas que Cabal desbordamiento de pila).
A veces sólo hay que señalar a la gente en un foro diferente.
Si está utilizando Cabal para configurar y construir su programa / biblioteca puede utilizado el Paths_ autogenerado * módulo.
Por ejemplo, si tiene un archivo foo.cabal
, cábala generará un módulo Paths_foo
(ver su fuente bajo dist/build/autogen
), que puede importar. Este módulo exporta una getLibDir :: IO FilePath
función que tiene el valor que está buscando.