plugins 1.5.7 → 1.6.2.1
raw patch · 9 files changed
Files
- plugins.cabal +14/−9
- src/System/Eval/Haskell.hs +2/−2
- src/System/Plugins/Consts.hs +1/−1
- src/System/Plugins/Env.hs +64/−15
- src/System/Plugins/Load.hs +43/−14
- src/System/Plugins/Make.hs +8/−8
- src/System/Plugins/Parser.hs +1/−1
- src/System/Plugins/Process.hs +8/−35
- src/System/Plugins/Utils.hs +4/−7
plugins.cabal view
@@ -1,5 +1,5 @@ name: plugins-version: 1.5.7+version: 1.6.2.1 homepage: https://github.com/stepcut/plugins synopsis: Dynamic linking for Haskell and C objects description: Dynamic linking and runtime evaluation of Haskell,@@ -18,20 +18,24 @@ License-file: LICENSE author: Don Stewart 2004..2010 maintainer: Jeremy Shaw <jeremy@seereason.com>-cabal-version: >= 1.6+cabal-version: >= 1.10 build-type: Configure-Tested-with: GHC == 7.4.*- , GHC == 7.6.*- , GHC == 7.8.*- , GHC == 7.10.*- , GHC == 8.0.*- , GHC == 8.2.*+Tested-with: GHC == 7.4.2+ , GHC == 7.6.3+ , GHC == 7.8.4+ , GHC == 7.10.3+ , GHC == 8.0.2+ , GHC == 8.2.2+ , GHC == 8.6.5+ , GHC == 8.8.3+ , GHC == 8.10.1 extra-source-files: config.guess, config.h.in, config.mk.in, config.sub, configure, configure.ac, install.sh, Makefile, testsuite/makewith/io/TestIO.conf.in, testsuite/makewith/unsafeio/Unsafe.conf.in library+ default-language: Haskell2010 exposed-modules: System.Eval, System.Eval.Haskell,@@ -46,7 +50,7 @@ System.Plugins.Process, System.Plugins.Utils - extensions: CPP,+ default-extensions: CPP, ForeignFunctionInterface ghc-options: -Wall -funbox-strict-fields -fno-warn-missing-signatures hs-source-dirs: src@@ -59,6 +63,7 @@ filepath, random, process,+ split, ghc >= 6.10, ghc-prim
src/System/Eval/Haskell.hs view
@@ -254,7 +254,7 @@ x = ident () -- what is this big variable name?--- its a random value, so that it won't clash if the accidently mistype+-- its a random value, so that it won't clash if the accidentally mistype -- an unbound 'x' or 'v' in their code.. it won't reveal the internal -- structure of the wrapper, which is annoying in irc use by lambdabot @@ -267,7 +267,7 @@ -- ----- return NULL pointer if an error occured.+-- return NULL pointer if an error occurred. -- foreign export ccall hs_eval_b :: CString -> IO (Ptr CInt)
src/System/Plugins/Consts.hs view
@@ -20,7 +20,7 @@ module System.Plugins.Consts where -#include "../../../config.h"+#include "config.h" #if __GLASGOW_HASKELL__ >= 604
src/System/Plugins/Env.hs view
@@ -40,17 +40,19 @@ lookupMerged, addMerge, addPkgConf,+ defaultPkgConf, union, addStaticPkg, isStaticPkg, rmStaticPkg, grabDefaultPkgConf, readPackageConf,- lookupPkg+ lookupPkg,+ pkgManglingPrefix ) where -#include "../../../config.h"+#include "config.h" import System.Plugins.LoadTypes (Module) import System.Plugins.Consts ( sysPkgSuffix )@@ -59,7 +61,7 @@ import Data.IORef ( writeIORef, readIORef, newIORef, IORef() ) import Data.Maybe ( isJust, isNothing, fromMaybe )-import Data.List ( (\\), nub, )+import Data.List ( (\\), nub ) import System.IO.Unsafe ( unsafePerformIO ) import System.Directory ( doesFileExist )@@ -76,13 +78,20 @@ Way(WayDyn), dynamicGhc, ways, #endif defaultDynFlags, initDynFlags)-import SysTools (initSysTools)+import SysTools ( initSysTools+#if MIN_VERSION_ghc(8,10,1)+ , lazyInitLlvmConfig+#else+ , initLlvmConfig+#endif+ ) import Distribution.Package hiding ( #if MIN_VERSION_ghc(7,6,0) Module, #endif depends, packageName, PackageName(..)+ , installedUnitId #if MIN_VERSION_ghc(7,10,0) , installedPackageId #endif@@ -96,8 +105,16 @@ import Distribution.Simple.Program import Distribution.Verbosity +import System.Environment+import Data.List.Split+ import qualified Data.Map as M import qualified Data.Set as S++#if !MIN_VERSION_ghc(8,10,1)+lazyInitLlvmConfig = initLlvmConfig+#endif+ -- -- and map Data.Map terms to FiniteMap terms --@@ -173,7 +190,7 @@ -- -- our environment, contains a set of loaded objects, and a map of known--- packages and their informations. Initially all we know is the default+-- packages and their information. Initially all we know is the default -- package.conf information. -- env = unsafePerformIO $ do@@ -305,6 +322,15 @@ ps <- readPackageConf f modifyPkgEnv env $ \ls -> return $ union ls ps +-- | This function is required when running with stack.+defaultPkgConf :: IO ()+defaultPkgConf = do+ paths <- lookupEnv "GHC_PACKAGE_PATH"+ unsetEnv "GHC_PACKAGE_PATH"+ case paths of+ Nothing -> return ()+ Just s -> mapM_ addPkgConf $ splitOn ":" s+ -- -- | add a new FM for the package.conf to the list of existing ones; if a package occurs multiple -- times, pick the one with the higher version number as the default (e.g., important for base in@@ -316,14 +342,14 @@ in foldr addOnePkg fm ps' : ls where -- we add each package with and without it's version number and with the full installedPackageId- addOnePkg p fm' = addToPkgEnvs (addToPkgEnvs (addToPkgEnvs fm' (display $ sourcePackageId p) p) (display $ installedPackageId p) p)+ addOnePkg p fm' = addToPkgEnvs (addToPkgEnvs (addToPkgEnvs fm' (display $ sourcePackageId p) p) (display $ packageId p) p) (packageName p) p -- if no version number specified, pick the higher version addToPkgEnvs = addWithFM higherVersion higherVersion pkgconf1 pkgconf2- | installedPackageId pkgconf1 >= installedPackageId pkgconf2 = pkgconf1+ | packageId pkgconf1 >= packageId pkgconf2 = pkgconf1 | otherwise = pkgconf2 --@@ -335,7 +361,7 @@ grabDefaultPkgConf :: IO PkgEnvs grabDefaultPkgConf = do- pc <- configureAllKnownPrograms silent defaultProgramConfiguration+ pc <- configureAllKnownPrograms silent defaultProgramDb #if MIN_VERSION_Cabal(1,24,0) (compiler, _platform, _programConfiguration) <- configure silent Nothing Nothing pc@@ -351,7 +377,7 @@ -- readPackageConf :: FilePath -> IO [PackageConfig] readPackageConf f = do- pc <- configureAllKnownPrograms silent defaultProgramConfiguration+ pc <- configureAllKnownPrograms silent defaultProgramDb #if MIN_VERSION_Cabal(1,24,0) (compiler, _platform, _programConfiguration) <- configure silent Nothing Nothing pc@@ -407,6 +433,17 @@ (f', g') <- liftM unzip $ mapM (go (nub $ seen ++ ps)) (ps \\ seen) return $ (nub $ (concat f') ++ f, if static then [] else nub $ (concat g') ++ g) +-- This is the prefix of mangled symbols that come from this package.+pkgManglingPrefix :: PackageName -> IO (Maybe String)+-- base seems to be mangled differently!+pkgManglingPrefix "base" = return $ Just "base"+pkgManglingPrefix p = withPkgEnvs env $ \fms -> return (go fms p)+ where+ go [] _ = Nothing+ go (fm:fms) q = case lookupFM fm q of+ Nothing -> go fms q -- look in other pkgs+ Just pkg -> Just $ drop 2 $ getHSLibraryName $ installedUnitId pkg+ data LibrarySpec = DLL String -- -lLib | DLLPath FilePath -- -Lpath@@ -459,14 +496,20 @@ ldOptsPaths = [ path | Just (DLLPath path) <- ldInput ] dlls = map mkSOName (extras ++ ldOptsLibs) #if defined(CYGWIN) || defined(__MINGW32__)- libdirs = fix_topdir (libraryDirs pkg) ++ ldOptsPaths+ libdirs = fix_topdir (libraryDirs pkg) ++ ldOptsPaths ++ fix_topdir (libraryDynDirs pkg) #else- libdirs = libraryDirs pkg ++ ldOptsPaths+ libdirs = libraryDirs pkg ++ ldOptsPaths ++ libraryDynDirs pkg #endif -- If we're loading dynamic libs we need the cbits to appear before the -- real packages.+#if MIN_VERSION_ghc(8,8,1)+ settings <- initSysTools (libdir)+ llvmConfig <- lazyInitLlvmConfig (libdir)+#else settings <- initSysTools (Just libdir)- dflags <- initDynFlags $ defaultDynFlags settings+ llvmConfig <- lazyInitLlvmConfig (Just libdir)+#endif+ dflags <- initDynFlags $ defaultDynFlags settings llvmConfig libs <- mapM (findHSlib #if MIN_VERSION_ghc(7,8,0) (WayDyn `elem` ways dflags || dynamicGhc)@@ -530,9 +573,15 @@ -- Solution: look for dynamic libraries only if using -dynamic; otherwise, use static -- and add any other dynamic libraries found. dl <- findHSdlib dirs lib- let rdl = case dl of- Just file -> Right $ Dynamic file- Nothing -> Left lib+ rdl <- case dl of+ Just file -> return $ Right $ Dynamic file+ Nothing -> do+ -- TODO Generate this suffix automatically. It's absurd we have to use the preprocessor.+ dynamicSuffix <- findHSdlib dirs (lib ++ "-ghc" ++ (reverse $ takeWhile (/= '-') $ reverse GHC_LIB_PATH))+ case dynamicSuffix of+ Just file -> return $ Right $ Dynamic file+ Nothing -> return $ Left lib+ if dynonly then return rdl else do rsl <- findHSslib dirs lib return $ case rsl of
src/System/Plugins/Load.hs view
@@ -61,7 +61,7 @@ ) where -#include "../../../config.h"+#include "config.h" import System.Plugins.Make ( build ) import System.Plugins.Env@@ -104,8 +104,14 @@ #else import DynFlags (defaultDynFlags, initDynFlags) import GHC.Paths (libdir)-import SysTools (initSysTools)+import SysTools ( initSysTools+#if MIN_VERSION_ghc(8,10,1)+ , lazyInitLlvmConfig+#else+ , initLlvmConfig #endif+ )+#endif import GHC.Ptr ( Ptr(..), nullPtr ) #if !MIN_VERSION_ghc(7,4,1) import GHC.Exts ( addrToHValue# )@@ -120,14 +126,24 @@ #endif import System.IO ( hClose ) +#if !MIN_VERSION_ghc(8,10,1)+lazyInitLlvmConfig = initLlvmConfig+#endif+ ifaceModuleName = moduleNameString . moduleName . mi_module readBinIface' :: FilePath -> IO ModIface readBinIface' hi_path = do -- kludgy as hell #if MIN_VERSION_ghc(7,2,0)+#if MIN_VERSION_ghc(8,8,1)+ mySettings <- initSysTools (libdir) -- how should we really set the top dir?+ llvmConfig <- lazyInitLlvmConfig (libdir)+#else mySettings <- initSysTools (Just libdir) -- how should we really set the top dir?- dflags <- initDynFlags (defaultDynFlags mySettings)+ llvmConfig <- lazyInitLlvmConfig (Just libdir)+#endif+ dflags <- initDynFlags (defaultDynFlags mySettings llvmConfig) e <- newHscEnv dflags #else e <- newHscEnv defaultCallbacks undefined@@ -244,7 +260,7 @@ -- -- Use GHC at runtime so we get staged type inference, providing full -- power dynamics, *on module interfaces only*. This is quite suitable--- for plugins, of coures :)+-- for plugins, of course :) -- -- TODO where does the .hc file go in the call to build() ? --@@ -259,11 +275,11 @@ #if DEBUG putStr "Checking types ... " >> hFlush stdout #endif- errors <- unify object incpaths [] ty sym+ (errors, success) <- unify object incpaths [] ty sym #if DEBUG putStrLn "done" #endif- if null errors+ if success then load object incpaths pkgconfs sym else return $ LoadFailure errors @@ -283,11 +299,11 @@ #if DEBUG putStr "Checking types ... " >> hFlush stdout #endif- errors <- unify object incpaths args ty sym+ (errors, success) <- unify object incpaths args ty sym #if DEBUG putStrLn "done" #endif- if null errors+ if success then load object incpaths pkgconfs sym else return $ LoadFailure errors @@ -316,9 +332,9 @@ hWrite hdl src - e <- build tmpf tmpf1 (i:is++args++["-fno-code","-c","-ohi "++tmpf1])+ (e,success) <- build tmpf tmpf1 (i:is++args++["-fno-code","-c","-ohi "++tmpf1]) mapM_ removeFile [tmpf,tmpf1]- return e+ return (e, success) where -- fix up hierarchical names@@ -473,10 +489,17 @@ -> String -> IO (Maybe a) loadFunction__ pkg m valsym- = do let symbol = prefixUnderscore++(maybe "" (\p -> zEncodeString p++"_") pkg)- ++zEncodeString m++"_"++(zEncodeString valsym)++"_closure"+ = do let encode = zEncodeString+ p <- case pkg of+ Just p -> do+ prefix <- pkgManglingPrefix p+ return $ encode (maybe p id prefix)++"_"+ Nothing -> return ""+ let symbol = prefixUnderscore++p++encode m++"_"++(encode valsym)++"_closure"+ #if DEBUG putStrLn $ "Looking for <<"++symbol++">>"+ initLinker #endif ptr@(Ptr addr) <- withCString symbol c_lookupSymbol if (ptr == nullPtr)@@ -595,10 +618,15 @@ -- Load a .so type object file. -- loadShared :: FilePath -> IO Module-loadShared str = do+loadShared str' = do #if DEBUG- putStrLn $ " shared: " ++ str+ putStrLn $ " shared: " ++ str' #endif+ let str = case str' of+ -- TODO My GHC segfaults because libm.so is a linker script+ "libm.so" -> "/lib/x86_64-linux-gnu/libm.so.6"+ "libpthread.so" -> "/lib/x86_64-linux-gnu/libpthread.so.0"+ x -> x maybe_errmsg <- withCString str $ \dll -> c_addDLL dll if maybe_errmsg == nullPtr then return (Module str (mkModid str) Shared undefined (Package (mkModid str)))@@ -617,6 +645,7 @@ -- loadPackage :: String -> IO () loadPackage p = do+ initLinker #if DEBUG putStr (' ':p) >> hFlush stdout #endif
src/System/Plugins/Make.hs view
@@ -113,7 +113,7 @@ -- -- | Merging may be avoided if the source files are older than an -- existing merged result. The @MergeCode@ type indicates whether--- merging was performed, or whether it was unneccessary.+-- merging was performed, or whether it was unnecessary. -- type MergeCode = MakeCode @@ -269,11 +269,11 @@ #if DEBUG putStr "Compiling object ... " >> hFlush stdout #endif- err <- build src obj args+ (err, success) <- build src obj args #if DEBUG putStrLn "done" #endif- return $ if null err+ return $ if success then MakeSuccess ReComp obj else MakeFailure err }@@ -287,7 +287,7 @@ build :: FilePath -- ^ path to .hs source -> FilePath -- ^ path to object file -> [String] -- ^ any extra cmd line flags- -> IO [String]+ -> IO ([String], Bool) build src obj extra_opts = do @@ -306,12 +306,12 @@ putStr $ show $ ghc : flags #endif - (_out,err) <- exec ghc flags -- this is a fork()+ (_out,err,success) <- exec ghc flags -- this is a fork() obj_exists <- doesFileExist obj -- sanity- return $ if not obj_exists && null err -- no errors, but no object?- then ["Compiled, but didn't create object file `"++obj++"'!"]- else err+ return $ if not obj_exists && success+ then (["Compiled, but didn't create object file `"++obj++"'!"], success)+ else (err, success) -- --------------------------------------------------------------------- -- | Merge to source files into a temporary file. If we've tried to
src/System/Plugins/Parser.hs view
@@ -25,7 +25,7 @@ replaceModName ) where -#include "../../../config.h"+#include "config.h" import Data.List import Data.Char
src/System/Plugins/Process.hs view
@@ -7,25 +7,19 @@ module System.Plugins.Process (exec, popen) where import System.Exit-#if __GLASGOW_HASKELL__ >= 604 import System.IO import System.Process import Control.Concurrent (forkIO)-#else-import qualified Posix as P-#endif import qualified Control.Exception as E -- -- slight wrapper over popen for calls that don't care about stdin to the program ---exec :: String -> [String] -> IO ([String],[String])+exec :: String -> [String] -> IO ([String],[String],Bool) exec f as = do- (a,b,_) <- popen f as (Just [])- return (lines a, lines b)--#if __GLASGOW_HASKELL__ >= 604+ (a,b,c,_) <- popen f as (Just [])+ return (lines a, lines b,c) type ProcessID = ProcessHandle @@ -37,9 +31,9 @@ -- Posix.popen doesn't have this problem, so maybe we can reproduce its -- pipe handling somehow. ---popen :: FilePath -> [String] -> Maybe String -> IO (String,String,ProcessID)+popen :: FilePath -> [String] -> Maybe String -> IO (String,String,Bool,ProcessID) popen file args minput =- E.handle (\e -> return ([],show (e::E.IOException), error (show e))) $ do+ E.handle (\e -> return ([],show (e::E.IOException), False, error (show e))) $ do (inp,out,err,pid) <- runInteractiveProcess file args Nothing Nothing @@ -64,27 +58,6 @@ case exitCode of ExitFailure code | null errput -> let errMsg = file ++ ": failed with error code " ++ show code- in return ([],errMsg,error errMsg)- _ -> return (output,errput,pid)--#else------- catch so that we can deal with forkProcess failing gracefully. and--- getProcessStatus is needed so as not to get a bunch of zombies,--- leading to forkProcess failing.------ Large amounts of input will cause problems with blocking as we wait--- on the process to finish. Make sure no lambdabot processes will--- generate 1000s of lines of output.----popen :: FilePath -> [String] -> Maybe String -> IO (String,String,P.ProcessID)-popen f s m =- E.handle (\e -> return ([], show (e::IOException), error $ show e )) $ do- x@(_,_,pid) <- P.popen f s m- b <- P.getProcessStatus True False pid -- wait- return $ case b of- Nothing -> ([], "process has disappeared", pid)- _ -> x--#endif+ in return ([],errMsg,False,error errMsg)+ | otherwise -> return ([],errput,False,error errput)+ _ -> return (output,errput,True,pid)
src/System/Plugins/Utils.hs view
@@ -58,7 +58,7 @@ ) where -#include "../../../config.h"+#include "config.h" import System.Plugins.Env ( isLoaded ) import System.Plugins.Consts ( objSuf, hiSuf, tmpDir )@@ -289,7 +289,7 @@ infixr 6 </> infixr 6 <.> -(</>), (<.>), (<+>), (<>) :: FilePath -> FilePath -> FilePath+(</>), (<.>), (<+>) :: FilePath -> FilePath -> FilePath [] </> b = b a </> b = a ++ "/" ++ b @@ -299,9 +299,6 @@ [] <+> b = b a <+> b = a ++ " " ++ b -[] <> b = b-a <> b = a ++ b- -- -- | dirname : return the directory portion of a file path -- if null, return "."@@ -429,7 +426,7 @@ -- -- This code checks if "-o foo" or "-odir foodir" are supplied as args -- to make(), and if so returns a modified file path, otherwise it--- uses the source file to determing the path to where the object and+-- uses the source file to determine the path to where the object and -- .hi file will be put. -- outFilePath :: FilePath -> [Arg] -> (FilePath,FilePath)@@ -473,7 +470,7 @@ -- fileExist still seems to throw exceptions on some platforms: ia64 in -- particular. ----- invarient : we already assume the first file, 'a', exists+-- invariant : we already assume the first file, 'a', exists -- newer :: FilePath -> FilePath -> IO Bool newer a b = do