Plan 9 from Bell Labs’s /usr/web/sources/contrib/fernan/nhc98/src/hmake/PackageConfig.hs

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


-----------------------------------------------------------------------------
-- |
-- Module      :  PackageConfig
-- Copyright   :  Malcolm Wallace
-- 
-- Maintainer  :  Malcolm Wallace <Malcolm.Wallace@cs.york.ac.uk>
-- Stability   :  Stable
-- Portability :  All
--
-- Work out the import directories for a bunch of packages.
--
--  * For ghc, we need to consult ghc-pkg for package import directories.
--
--  * nhc98 <= 1.16 stores package imports under its default incdir.
--          >= 1.17 stores package imports under $incdir/packages.
-----------------------------------------------------------------------------

module PackageConfig
  ( packageDirs
  ) where

import Config
import Compiler
import Platform (unsafePerformIO,escape)
import RunAndReadStdout (runAndReadStdout,basename,dirname)
import Directory (doesDirectoryExist)
import IO (hPutStrLn, stderr)
import List (partition,intersperse,isPrefixOf)
import Char (isDigit)
import Monad (when,foldM)

-- Missing from List library
elemBy        :: (a -> a -> Bool) -> a -> [a] -> Bool
elemBy eq _ []          =  False
elemBy eq x (y:ys)      =  x `eq` y || elemBy eq x ys


-- | Work out the import directories for a bunch of packages.
packageDirs :: CompilerConfig  -- ^ Which compiler, where it's located, etc.
            -> [String]        -- ^ The packages
            -> [FilePath]

-- For ghc, we need to consult ghc-pkg for package import directories.
packageDirs config@(CompilerConfig{ compilerStyle=Ghc
                                  , compilerPath=ghc }) packages =
    let ghcsym = (read . take 3 . filter isDigit . (++"00") . compilerVersion)
                 config
    in
    if ghcsym < (500::Int) then
      []
    else unsafePerformIO $ do
      pkgcfg <- runAndReadStdout (ghc++" --print-libdir")
      let libdir  = escape pkgcfg
          incdir1 = libdir++"/imports"
      ok <- doesDirectoryExist incdir1
      if ok
        then do
          let ghcpkg = matching ghc (ghcPkg ghc (compilerVersion config))
       -- ghcpkg <- runAndReadStdout
       --                  ("echo `" ++ ghc ++ " --print-libdir`/bin/ghc-pkg")
       -- pkgs <- runAndReadStdout (ghcpkg++" --list-packages")
          pkgs <- runAndReadStdout (ghcpkg++" -l")
          let (ok,bad) = partition (\p-> elemBy versionMatch p (deComma pkgs))
                                   packages
          when (not (null bad))
               (hPutStrLn stderr ("\nWarning: package(s) "
                                 ++concat (intersperse ", " bad)
                                 ++" not available (according to ghc-pkg)"))
          idirs <- mapM (\p-> runAndReadStdout
                                  (ghcpkg++" --show-package="++p
                                   ++" --field=import_dirs"))
                        ok
          return (pkgDirs libdir idirs)
        else do ioError (userError ("Can't find ghc packages at "++incdir1))
 where
    pkgDirs libdir dirs =
        map (\dir-> if "$libdir" `isPrefixOf` dir
                    then libdir++drop 7 dir
                    else if "[\"" `isPrefixOf` dir
                    then let d = drop 2 (init (init dir))
                         in if "$topdir" `isPrefixOf` d
                            then libdir++drop 7 d else d
                    else dir)
            (concatMap words dirs)
    deComma pkgs = map (\p-> if last p==',' then init p else p) (words pkgs)
    matching path cmd =
        if '/' `elem` path then dirname path++"/"++cmd else cmd
    ghcPkg ghc ver =
        if '-' `elem` basename ghc then "ghc-pkg-"++ver else "ghc-pkg"
    p `versionMatch` q = case extractPkgVersion p of
                           (p,"") -> p == fst (extractPkgVersion q)
                           _      -> p == q
    extractPkgVersion :: String -> (String,String)
    extractPkgVersion p =
        let p' = case p of ('(':ps)-> init ps; _-> p;
            (suf,pref) = span (/='-') (reverse p')
        in case pref of "" -> (p',""); _-> (reverse (tail pref), reverse suf)

-- nhc98 <= 1.16 stores package imports under its default incdir.
--       >= 1.17 stores package imports under $incdir/packages.
packageDirs config@(CompilerConfig{ compilerStyle=Nhc98
                                  , includePaths=[incdir] }) packages =
  let (pkgdir,base) | compilerVersion config <= "v1.16" = (incdir, [])
                    | otherwise     = (incdir++"/packages", [pkgdir++"/base"])
  in
  unsafePerformIO $ do
    ok <- doesDirectoryExist pkgdir
    if ok
      then do
        (good,bad) <- foldM (\(g,b) d->
                             do let dir = pkgdir++"/"++d
                                ok <- doesDirectoryExist dir
                                return (if ok then (dir:g, b) else (g, d:b)))
                            (base,[]) packages
        when (not (null bad))
             (hPutStrLn stderr ("\nWarning: package(s) "
                               ++concat (intersperse ", " bad)
                               ++" not available in "++pkgdir))
        return good
      else ioError (userError ("Can't find nhc98 packages at "++pkgdir))

-- No other compiler supports packages.
packageDirs config packages = []

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.