더 구체적으로 말하자면, 임의의 패키지 이름을 사용하면 실행중인 Haskell 프로그램 내부에서 ghc-pkg describe
명령으로 얻을 수있는 동일한 library-dirs
필드를 가져와야합니다.프로그래밍 방식으로 GHC 패키지 정보를 검색하는 방법은 무엇입니까?
답변
다음은 소스 코드 ghc-pkg
을 엿 들으면서 생각해 낼 수있는 부분입니다.
getPkgInfos
함수는 설치된 모든 패키지 (사용자가 설치 한 패키지 포함)의 패키지 정의를 반환합니다. 이것을 사용하여 라이브러리 디렉토리 및 기타 패키지 정보를 검색 할 수 있습니다. 자세한 내용은 the documentation을 참조하십시오.
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 스타일의 라이센스하에 라이센스를 받았으며,이 모든 것은 Stackoverflow 컨텐츠가 아래에있는 cc-wiki 라이센스하에 배포 될 수 있다고 생각하지만 실제로는 잘 모르겠습니다. 어쨌든, 다른 어떤 것으로서, 나는 초기 테스트를했는데 제대로 작동하는 것으로 보인다.
cabal을 사용하여 프로그램/라이브러리를 구성하고 빌드하는 경우 자동 생성 된 Paths_ * 모듈을 사용할 수 있습니다.
예를 들어 파일이 foo.cabal
인 경우 cabal은 모듈 (해당 소스는 dist/build/autogen
참조)을 가져올 수 있습니다. 이 모듈은 찾고있는 값을 가진 getLibDir :: IO FilePath
함수를 내 보냅니다.
답변 주셔서 감사합니다.하지만 그건 내가 찾고있는 것이 아닙니다. 내 설치 패키지가 아닌 다른 lib 디렉토리를 가져와야합니다. –
설치된 패키지 데이터베이스의 형식은 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])
이것은 사용자의 패키지 구성을 따르지는 않지만 시작이어야합니다.
haskell-cafe @ 또는 cabal 메일 링리스트에서 Duncan Coutts에게 질문하십시오. (나는 진지해. 스택 오버플로보다 카발 질문에 더 좋은 포럼이다.)
간혹 다른 포럼에 사람들을 안내해야 할 때가 있습니다.
그래, 그게 기본적으로 내가 쓴 것보다 포괄적 인 버전이야. 단 하나의 하드 코딩 된'% GHC_ROOT %/package.conf'를 사용하는 대신에, 당신은 정규적으로 사용되는 것들 모두를 찾은 것 같아요. – ephemient
ghc-pkg가 그 동작을 모방하기 위해 찾은 모든 것을 찾으려고했습니다. –