كيفية استرداد حزمة حزمة GHC برمجيا؟
سؤال
وبشكل أكثر تحديدا، بالنظر إلى اسم الحزمة الشبرية أحتاج إلى استرداد نفسه library-dirs
الحقل الذي يمكن الحصول عليه مع ghc-pkg describe
أمر من داخل برنامج تشغيل Haskell.
المحلول
إليك ما يمكنني التوصل إليه من خلال تطل 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، لكنني لست متأكدا حقا. على أي حال، كشيء آخر، فعلت بعض الاختبارات الأولية ويبدو أن العمل، ولكن استخدامها على مسؤوليتك الخاصة.
نصائح أخرى
تنسيق قاعدة بيانات الحزم المثبتة 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])
هذا لا يطيع تكوين حزمة المستخدم، ولكن يجب أن يكون بداية.
اسأل Duncan Coutts على القوائم البريدية في Haskell-Cafe أو Cabal. (أنا جاد. هذا هو منتدى أفضل لأسئلة CABAL من تجاوز مكدس).
في بعض الأحيان عليك فقط توجيه الناس في منتدى مختلف.
إذا كنت تستخدم Cabal لتكوين وإنشاء برنامجك / المكتبة، فيمكنك استخدام الوحدة النمطية للمسارات الحسية.
على سبيل المثال، إذا كان لديك foo.cabal
ملف، cabal سوف تولد Paths_foo
الوحدة النمطية (انظر مصدرها تحت dist/build/autogen
) ما يمكنك استيراده. هذه الوحدة تصدر وظيفة getLibDir :: IO FilePath
التي لديها القيمة التي تبحث عنها.