1 -----------------------------------------------------------------------------
2 -- $Id: InteractiveUI.hs,v 1.82 2001/07/18 16:06:10 rrt Exp $
4 -- GHC Interactive User Interface
6 -- (c) The GHC Team 2000
8 -----------------------------------------------------------------------------
10 {-# OPTIONS -#include "Linker.h" #-}
11 module InteractiveUI ( interactiveUI, ghciWelcomeMsg ) where
13 #include "../includes/config.h"
14 #include "HsVersions.h"
18 import HscTypes ( GhciMode(..) )
19 import MkIface ( ifaceTyCls )
25 import Finder ( flushPackageCache )
29 import CmdLineOpts ( DynFlag(..), getDynFlags, saveDynFlags, restoreDynFlags, dopt_unset )
30 import Panic ( GhcException(..) )
33 #ifndef mingw32_TARGET_OS
39 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
53 import PrelGHC ( unsafeCoerce# )
54 import Foreign ( nullPtr )
55 import CString ( peekCString )
57 -----------------------------------------------------------------------------
61 \ / _ \\ /\\ /\\/ __(_)\n\
62 \ / /_\\// /_/ / / | | GHC Interactive, version " ++ cProjectVersion ++ ", for Haskell 98.\n\
63 \/ /_\\\\/ __ / /___| | http://www.haskell.org/ghc/\n\
64 \\\____/\\/ /_/\\____/|_| Type :? for help.\n"
66 GLOBAL_VAR(commands, builtin_commands, [(String, String -> GHCi Bool)])
68 builtin_commands :: [(String, String -> GHCi Bool)]
70 ("add", keepGoing addModule),
71 ("cd", keepGoing changeDirectory),
72 ("def", keepGoing defineMacro),
73 ("help", keepGoing help),
74 ("?", keepGoing help),
75 ("info", keepGoing info),
76 ("load", keepGoing loadModule),
77 ("module", keepGoing setContext),
78 ("reload", keepGoing reloadModule),
79 ("set", keepGoing setOptions),
80 ("type", keepGoing typeOfExpr),
81 ("unset", keepGoing unsetOptions),
82 ("undef", keepGoing undefineMacro),
86 keepGoing :: (String -> GHCi ()) -> (String -> GHCi Bool)
87 keepGoing a str = a str >> return False
89 shortHelpText = "use :? for help.\n"
92 \ Commands available from the prompt:\n\
94 \ <stmt> evaluate/run <stmt>\n\
95 \ :add <filename> ... add module(s) to the current target set\n\
96 \ :cd <dir> change directory to <dir>\n\
97 \ :def <cmd> <expr> define a command :<cmd>\n\
98 \ :help, :? display this list of commands\n\
99 \ :info [<name> ...] display information about the given names, or\n\
100 \ about currently loaded files if no names given\n\
101 \ :load <filename> ... load module(s) and their dependents\n\
102 \ :module <mod> set the context for expression evaluation to <mod>\n\
103 \ :reload reload the current module set\n\
104 \ :set <option> ... set options\n\
105 \ :undef <cmd> undefine user-defined command :<cmd>\n\
106 \ :type <expr> show the type of <expr>\n\
107 \ :unset <option> ... unset options\n\
109 \ :!<command> run the shell command <command>\n\
111 \ Options for `:set' and `:unset':\n\
113 \ +r revert top-level expressions after each evaluation\n\
114 \ +s print timing/memory stats after each evaluation\n\
115 \ +t print type after evaluation\n\
116 \ -<flags> most GHC command line flags can also be set here\n\
117 \ (eg. -v2, -fglasgow-exts, etc.)\n\
120 interactiveUI :: CmState -> [FilePath] -> [LibrarySpec] -> IO ()
121 interactiveUI cmstate paths cmdline_libs = do
123 hSetBuffering stdout NoBuffering
125 -- link in the available packages
126 pkgs <- getPackageInfo
128 linkPackages cmdline_libs pkgs
130 (cmstate, ok, mods) <-
132 [] -> return (cmstate, True, [])
133 _ -> cmLoadModule cmstate paths
135 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
139 dflags <- getDynFlags
141 (cmstate, maybe_hval)
142 <- cmCompileExpr cmstate dflags "IO.hFlush PrelHandle.stderr"
144 Just hval -> writeIORef flush_stderr (unsafeCoerce# hval :: IO ())
145 _ -> panic "interactiveUI:stderr"
147 (cmstate, maybe_hval)
148 <- cmCompileExpr cmstate dflags "IO.hFlush PrelHandle.stdout"
150 Just hval -> writeIORef flush_stdout (unsafeCoerce# hval :: IO ())
151 _ -> panic "interactiveUI:stdout"
153 startGHCi runGHCi GHCiState{ targets = paths,
157 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
158 Readline.resetTerminal Nothing
168 exists <- io (doesFileExist file)
170 dir_ok <- io (checkPerms ".")
171 file_ok <- io (checkPerms file)
172 when (dir_ok && file_ok) $ do
173 either_hdl <- io (IO.try (openFile "./.ghci" ReadMode))
176 Right hdl -> fileLoop hdl False
178 -- Read in $HOME/.ghci
179 either_dir <- io (IO.try (getEnv "HOME"))
183 cwd <- io (getCurrentDirectory)
184 when (dir /= cwd) $ do
185 let file = dir ++ "/.ghci"
186 ok <- io (checkPerms file)
187 either_hdl <- io (IO.try (openFile file ReadMode))
190 Right hdl -> fileLoop hdl False
192 -- read commands from stdin
193 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
200 io $ do putStrLn "Leaving GHCi."
203 -- NOTE: We only read .ghci files if they are owned by the current user,
204 -- and aren't world writable. Otherwise, we could be accidentally
205 -- running code planted by a malicious third party.
207 -- Furthermore, We only read ./.ghci if . is owned by the current user
208 -- and isn't writable by anyone else. I think this is sufficient: we
209 -- don't need to check .. and ../.. etc. because "." always refers to
210 -- the same directory while a process is running.
212 checkPerms :: String -> IO Bool
214 handle (\_ -> return False) $ do
215 #ifdef mingw32_TARGET_OS
218 st <- getFileStatus name
220 if fileOwner st /= me then do
221 putStrLn $ "WARNING: " ++ name ++ " is owned by someone else, IGNORING!"
224 let mode = fileMode st
225 if (groupWriteMode == (mode `intersectFileModes` groupWriteMode))
226 || (otherWriteMode == (mode `intersectFileModes` otherWriteMode))
228 putStrLn $ "*** WARNING: " ++ name ++
229 " is writable by someone else, IGNORING!"
234 fileLoop :: Handle -> Bool -> GHCi ()
235 fileLoop hdl prompt = do
237 mod <- io (cmGetContext (cmstate st))
238 when prompt (io (putStr (mod ++ "> ")))
239 l <- io (IO.try (hGetLine hdl))
241 Left e | isEOFError e -> return ()
242 | otherwise -> throw e
244 case remove_spaces l of
245 "" -> fileLoop hdl prompt
246 l -> do quit <- runCommand l
247 if quit then return () else fileLoop hdl prompt
249 stringLoop :: [String] -> GHCi ()
250 stringLoop [] = return ()
251 stringLoop (s:ss) = do
253 case remove_spaces s of
255 l -> do quit <- runCommand l
256 if quit then return () else stringLoop ss
258 #if HAVE_READLINE_HEADERS && HAVE_READLINE_LIBS
259 readlineLoop :: GHCi ()
262 mod <- io (cmGetContext (cmstate st))
263 l <- io (readline (mod ++ "> "))
267 case remove_spaces l of
272 if quit then return () else readlineLoop
275 -- Top level exception handler, just prints out the exception
277 runCommand :: String -> GHCi Bool
279 ghciHandle ( \exception -> do
281 showException exception
286 showException (DynException dyn) =
287 case fromDynamic dyn of
289 io (putStrLn ("*** Exception: (unknown)"))
290 Just (PhaseFailed phase code) ->
291 io (putStrLn ("Phase " ++ phase ++ " failed (code "
292 ++ show code ++ ")"))
294 io (putStrLn "Interrupted.")
295 Just (CmdLineError s) ->
296 io (putStrLn s) -- omit the location for CmdLineError
298 io (putStrLn (show other_ghc_ex))
299 showException other_exception
300 = io (putStrLn ("*** Exception: " ++ show other_exception))
302 doCommand (':' : command) = specialCommand command
304 = do timeIt (do stuff <- runStmt stmt; finishEvalExpr stuff)
307 -- Returns True if the expr was successfully parsed, renamed and
309 runStmt :: String -> GHCi (Maybe [Name])
311 | null (filter (not.isSpace) stmt)
314 = do st <- getGHCiState
315 dflags <- io getDynFlags
316 let dflags' = dopt_unset dflags Opt_WarnUnusedBinds
317 (new_cmstate, names) <- io (cmRunStmt (cmstate st) dflags' stmt)
318 setGHCiState st{cmstate = new_cmstate}
321 -- possibly print the type and revert CAFs after evaluating an expression
322 finishEvalExpr Nothing = return False
323 finishEvalExpr (Just names)
324 = do b <- isOptionSet ShowType
326 when b (mapM_ (showTypeOfName (cmstate st)) names)
328 b <- isOptionSet RevertCAFs
329 io (when b revertCAFs)
333 showTypeOfName :: CmState -> Name -> GHCi ()
334 showTypeOfName cmstate n
335 = do maybe_str <- io (cmTypeOfName cmstate n)
338 Just str -> io (putStrLn (showSDoc (ppr n) ++ " :: " ++ str))
340 flushEverything :: GHCi ()
342 = io $ do flush_so <- readIORef flush_stdout
344 flush_se <- readIORef flush_stdout
348 specialCommand :: String -> GHCi Bool
349 specialCommand ('!':str) = shellEscape (dropWhile isSpace str)
350 specialCommand str = do
351 let (cmd,rest) = break isSpace str
352 cmds <- io (readIORef commands)
353 case [ (s,f) | (s,f) <- cmds, prefixMatch cmd s ] of
354 [] -> io (hPutStr stdout ("unknown command `:" ++ cmd ++ "'\n"
355 ++ shortHelpText) >> return False)
356 [(_,f)] -> f (dropWhile isSpace rest)
357 cs -> io (hPutStrLn stdout ("prefix " ++ cmd ++
358 " matches multiple commands (" ++
359 foldr1 (\a b -> a ++ ',':b) (map fst cs)
360 ++ ")") >> return False)
362 noArgs c = throwDyn (CmdLineError ("command `" ++ c ++ "' takes no arguments"))
364 -----------------------------------------------------------------------------
367 help :: String -> GHCi ()
368 help _ = io (putStr helpText)
370 info :: String -> GHCi ()
371 info "" = do io (putStr "dunno, mate")
375 let cmst = cmstate st
376 dflags <- io getDynFlags
377 things <- io (mapM (cmInfoThing cmst dflags) names)
378 let real_things = [ x | Just x <- things ]
379 let descs = map (`ifaceTyCls` []) real_things
380 let strings = map (showSDoc . ppr) descs
381 io (mapM_ putStr strings)
383 addModule :: String -> GHCi ()
385 let files = words str
386 state <- getGHCiState
387 dflags <- io (getDynFlags)
388 io (revertCAFs) -- always revert CAFs on load/add.
389 let new_targets = files ++ targets state
390 (cmstate1, ok, mods) <- io (cmLoadModule (cmstate state) new_targets)
391 setGHCiState state{ cmstate = cmstate1, targets = new_targets }
392 modulesLoadedMsg ok mods
394 setContext :: String -> GHCi ()
396 = throwDyn (CmdLineError "syntax: `:m <module>'")
397 setContext m | not (isUpper (head m)) || not (all isAlphaNumEx (tail m))
398 = throwDyn (CmdLineError ("strange looking module name: `" ++ m ++ "'"))
400 isAlphaNumEx c = isAlphaNum c || c == '_'
402 = do st <- getGHCiState
403 new_cmstate <- io (cmSetContext (cmstate st) str)
404 setGHCiState st{cmstate=new_cmstate}
406 changeDirectory :: String -> GHCi ()
407 changeDirectory ('~':d) = do
408 tilde <- io (getEnv "HOME") -- will fail if HOME not defined
409 io (setCurrentDirectory (tilde ++ '/':d))
410 changeDirectory d = io (setCurrentDirectory d)
412 defineMacro :: String -> GHCi ()
414 let (macro_name, definition) = break isSpace s
415 cmds <- io (readIORef commands)
417 then throwDyn (CmdLineError "invalid macro name")
419 if (macro_name `elem` map fst cmds)
420 then throwDyn (CmdLineError
421 ("command `" ++ macro_name ++ "' is already defined"))
424 -- give the expression a type signature, so we can be sure we're getting
425 -- something of the right type.
426 let new_expr = '(' : definition ++ ") :: String -> IO String"
428 -- compile the expression
430 dflags <- io getDynFlags
431 (new_cmstate, maybe_hv) <- io (cmCompileExpr (cmstate st) dflags new_expr)
432 setGHCiState st{cmstate = new_cmstate}
435 Just hv -> io (writeIORef commands --
436 ((macro_name, keepGoing (runMacro hv)) : cmds))
438 runMacro :: HValue{-String -> IO String-} -> String -> GHCi ()
440 str <- io ((unsafeCoerce# fun :: String -> IO String) s)
441 stringLoop (lines str)
443 undefineMacro :: String -> GHCi ()
444 undefineMacro macro_name = do
445 cmds <- io (readIORef commands)
446 if (macro_name `elem` map fst builtin_commands)
447 then throwDyn (CmdLineError
448 ("command `" ++ macro_name ++ "' cannot be undefined"))
450 if (macro_name `notElem` map fst cmds)
451 then throwDyn (CmdLineError
452 ("command `" ++ macro_name ++ "' not defined"))
454 io (writeIORef commands (filter ((/= macro_name) . fst) cmds))
456 loadModule :: String -> GHCi ()
457 loadModule str = timeIt (loadModule' str)
460 let files = words str
461 state <- getGHCiState
462 dflags <- io getDynFlags
463 cmstate1 <- io (cmUnload (cmstate state) dflags)
464 setGHCiState state{ cmstate = cmstate1, targets = [] }
465 io (revertCAFs) -- always revert CAFs on load.
466 (cmstate2, ok, mods) <- io (cmLoadModule cmstate1 files)
467 setGHCiState state{ cmstate = cmstate2, targets = files }
468 modulesLoadedMsg ok mods
470 reloadModule :: String -> GHCi ()
472 state <- getGHCiState
473 case targets state of
474 [] -> io (putStr "no current target\n")
476 -> do io (revertCAFs) -- always revert CAFs on reload.
477 (new_cmstate, ok, mods) <- io (cmLoadModule (cmstate state) paths)
478 setGHCiState state{ cmstate=new_cmstate }
479 modulesLoadedMsg ok mods
481 reloadModule _ = noArgs ":reload"
484 modulesLoadedMsg ok mods = do
486 | null mods = text "none."
488 punctuate comma (map text mods)) <> text "."
491 io (putStrLn (showSDoc (text "Failed, modules loaded: " <> mod_commas)))
493 io (putStrLn (showSDoc (text "Ok, modules loaded: " <> mod_commas)))
496 typeOfExpr :: String -> GHCi ()
498 = do st <- getGHCiState
499 dflags <- io getDynFlags
500 (new_cmstate, maybe_tystr) <- io (cmTypeOfExpr (cmstate st) dflags str)
501 setGHCiState st{cmstate = new_cmstate}
504 Just tystr -> io (putStrLn tystr)
506 quit :: String -> GHCi Bool
509 shellEscape :: String -> GHCi Bool
510 shellEscape str = io (system str >> return False)
512 ----------------------------------------------------------------------------
515 -- set options in the interpreter. Syntax is exactly the same as the
516 -- ghc command line, except that certain options aren't available (-C,
519 -- This is pretty fragile: most options won't work as expected. ToDo:
520 -- figure out which ones & disallow them.
522 setOptions :: String -> GHCi ()
524 = do st <- getGHCiState
525 let opts = options st
526 io $ putStrLn (showSDoc (
527 text "options currently set: " <>
530 else hsep (map (\o -> char '+' <> text (optToStr o)) opts)
533 = do -- first, deal with the GHCi opts (+s, +t, etc.)
534 let (plus_opts, minus_opts) = partition isPlus (words str)
535 mapM setOpt plus_opts
537 -- now, the GHC flags
538 pkgs_before <- io (readIORef v_Packages)
539 leftovers <- io (processArgs static_flags minus_opts [])
540 pkgs_after <- io (readIORef v_Packages)
542 -- update things if the users wants more packages
543 when (pkgs_before /= pkgs_after) $
544 newPackages (pkgs_after \\ pkgs_before)
546 -- then, dynamic flags
549 leftovers <- processArgs dynamic_flags leftovers []
552 if (not (null leftovers))
553 then throwDyn (CmdLineError ("unrecognised flags: " ++
558 unsetOptions :: String -> GHCi ()
560 = do -- first, deal with the GHCi opts (+s, +t, etc.)
562 (minus_opts, rest1) = partition isMinus opts
563 (plus_opts, rest2) = partition isPlus rest1
565 if (not (null rest2))
566 then io (putStrLn ("unknown option: `" ++ head rest2 ++ "'"))
569 mapM unsetOpt plus_opts
571 -- can't do GHC flags for now
572 if (not (null minus_opts))
573 then throwDyn (CmdLineError "can't unset GHC command-line flags")
576 isMinus ('-':s) = True
579 isPlus ('+':s) = True
583 = case strToGHCiOpt str of
584 Nothing -> io (putStrLn ("unknown option: `" ++ str ++ "'"))
585 Just o -> setOption o
588 = case strToGHCiOpt str of
589 Nothing -> io (putStrLn ("unknown option: `" ++ str ++ "'"))
590 Just o -> unsetOption o
592 strToGHCiOpt :: String -> (Maybe GHCiOption)
593 strToGHCiOpt "s" = Just ShowTiming
594 strToGHCiOpt "t" = Just ShowType
595 strToGHCiOpt "r" = Just RevertCAFs
596 strToGHCiOpt _ = Nothing
598 optToStr :: GHCiOption -> String
599 optToStr ShowTiming = "s"
600 optToStr ShowType = "t"
601 optToStr RevertCAFs = "r"
603 newPackages new_pkgs = do
604 state <- getGHCiState
605 dflags <- io getDynFlags
606 cmstate1 <- io (cmUnload (cmstate state) dflags)
607 setGHCiState state{ cmstate = cmstate1, targets = [] }
610 pkgs <- getPackageInfo
611 flushPackageCache pkgs
613 new_pkg_info <- getPackageDetails new_pkgs
614 mapM_ (linkPackage False) (reverse new_pkg_info)
616 -----------------------------------------------------------------------------
619 data GHCiState = GHCiState
621 targets :: [FilePath],
623 options :: [GHCiOption]
627 = ShowTiming -- show time/allocs after evaluation
628 | ShowType -- show the type of expressions
629 | RevertCAFs -- revert CAFs after every evaluation
632 GLOBAL_VAR(flush_stdout, error "no flush_stdout", IO ())
633 GLOBAL_VAR(flush_stderr, error "no flush_stdout", IO ())
635 newtype GHCi a = GHCi { unGHCi :: IORef GHCiState -> IO a }
637 startGHCi :: GHCi a -> GHCiState -> IO a
638 startGHCi g state = do ref <- newIORef state; unGHCi g ref
640 instance Monad GHCi where
641 (GHCi m) >>= k = GHCi $ \s -> m s >>= \a -> unGHCi (k a) s
642 return a = GHCi $ \s -> return a
644 getGHCiState = GHCi $ \r -> readIORef r
645 setGHCiState s = GHCi $ \r -> writeIORef r s
647 isOptionSet :: GHCiOption -> GHCi Bool
649 = do st <- getGHCiState
650 return (opt `elem` options st)
652 setOption :: GHCiOption -> GHCi ()
654 = do st <- getGHCiState
655 setGHCiState (st{ options = opt : filter (/= opt) (options st) })
657 unsetOption :: GHCiOption -> GHCi ()
659 = do st <- getGHCiState
660 setGHCiState (st{ options = filter (/= opt) (options st) })
663 io m = GHCi { unGHCi = \s -> m >>= return }
665 -----------------------------------------------------------------------------
666 -- recursive exception handlers
668 -- Don't forget to unblock async exceptions in the handler, or if we're
669 -- in an exception loop (eg. let a = error a in a) the ^C exception
670 -- may never be delivered. Thanks to Marcin for pointing out the bug.
672 ghciHandle :: (Exception -> GHCi a) -> GHCi a -> GHCi a
673 ghciHandle h (GHCi m) = GHCi $ \s ->
674 Exception.catch (m s)
675 (\e -> unGHCi (ghciHandle h (ghciUnblock (h e))) s)
677 ghciUnblock :: GHCi a -> GHCi a
678 ghciUnblock (GHCi a) = GHCi $ \s -> Exception.unblock (a s)
680 -----------------------------------------------------------------------------
683 -- Left: full path name of a .o file, including trailing .o
684 -- Right: "unadorned" name of a .DLL/.so
685 -- e.g. On unix "qt" denotes "libqt.so"
686 -- On WinDoze "burble" denotes "burble.DLL"
687 -- addDLL is platform-specific and adds the lib/.so/.DLL
688 -- suffixes platform-dependently; we don't do that here.
690 -- For dynamic objects only, try to find the object file in all the
691 -- directories specified in v_Library_Paths before giving up.
694 = Either FilePath String
696 showLS (Left nm) = "(static) " ++ nm
697 showLS (Right nm) = "(dynamic) " ++ nm
699 linkPackages :: [LibrarySpec] -> [PackageConfig] -> IO ()
700 linkPackages cmdline_lib_specs pkgs
701 = do sequence_ [ linkPackage (name p `elem` loaded) p | p <- reverse pkgs ]
702 lib_paths <- readIORef v_Library_paths
703 mapM_ (preloadLib lib_paths) cmdline_lib_specs
705 -- Packages that are already linked into GHCi. For mingw32, we only
706 -- skip gmp and rts, since std and after need to load the msvcrt.dll
707 -- library which std depends on.
709 # ifndef mingw32_TARGET_OS
710 = [ "gmp", "rts", "std", "concurrent", "posix", "text", "util" ]
715 preloadLib :: [String] -> LibrarySpec -> IO ()
716 preloadLib lib_paths lib_spec
717 = do putStr ("Loading object " ++ showLS lib_spec ++ " ... ")
720 -> do b <- preload_static lib_paths static_ish
721 putStrLn (if b then "done" else "not found")
723 -> -- We add "" to the set of paths to try, so that
724 -- if none of the real paths match, we force addDLL
725 -- to look in the default dynamic-link search paths.
726 do b <- preload_dynamic (lib_paths++[""]) dll_unadorned
727 when (not b) (cantFind lib_paths lib_spec)
730 cantFind :: [String] -> LibrarySpec -> IO ()
732 = do putStr ("failed.\nCan't find " ++ showLS spec
733 ++ " in directories:\n"
734 ++ unlines (map (" "++) paths) )
737 -- not interested in the paths in the static case.
738 preload_static paths name
739 = do b <- doesFileExist name
740 if not b then return False
741 else loadObj name >> return True
743 preload_dynamic [] name
745 preload_dynamic (path:paths) rootname
746 = do maybe_errmsg <- addDLL path rootname
747 if maybe_errmsg /= nullPtr
748 then preload_dynamic paths rootname
752 = (throwDyn . CmdLineError)
753 "user specified .o/.so/.DLL could not be loaded."
756 linkPackage :: Bool -> PackageConfig -> IO ()
757 -- ignore rts and gmp for now (ToDo; better?)
758 linkPackage loaded_in_ghci pkg
759 | name pkg `elem` ["rts", "gmp"]
762 = do putStr ("Loading package " ++ name pkg ++ " ... ")
763 -- For each obj, try obj.o and if that fails, obj.so.
764 -- Complication: all the .so's must be loaded before any of the .o's.
765 let dirs = library_dirs pkg
766 let objs = hs_libraries pkg ++ extra_libraries pkg
767 classifieds <- mapM (locateOneObj dirs) objs
769 -- Don't load the .so libs if this is a package GHCi is already
770 -- linked against, because we'll already have the .so linked in.
771 let (so_libs, obj_libs) = partition isRight classifieds
772 let sos_first | loaded_in_ghci = obj_libs
773 | otherwise = so_libs ++ obj_libs
775 mapM loadClassified sos_first
776 putStr "linking ... "
780 isRight (Right _) = True
781 isRight (Left _) = False
783 loadClassified :: LibrarySpec -> IO ()
784 loadClassified (Left obj_absolute_filename)
785 = do loadObj obj_absolute_filename
786 loadClassified (Right dll_unadorned)
787 = do maybe_errmsg <- addDLL "" dll_unadorned -- doesn't seem right to me
788 if maybe_errmsg == nullPtr
790 else do str <- peekCString maybe_errmsg
791 throwDyn (CmdLineError ("can't load .so/.DLL for: "
792 ++ dll_unadorned ++ " (" ++ str ++ ")" ))
794 locateOneObj :: [FilePath] -> String -> IO LibrarySpec
796 = return (Right obj) -- we assume
797 locateOneObj (d:ds) obj
798 = do let path = d ++ '/':obj ++ ".o"
799 b <- doesFileExist path
800 if b then return (Left path) else locateOneObj ds obj
802 -----------------------------------------------------------------------------
803 -- timing & statistics
805 timeIt :: GHCi a -> GHCi a
807 = do b <- isOptionSet ShowTiming
810 else do allocs1 <- io $ getAllocations
811 time1 <- io $ getCPUTime
813 allocs2 <- io $ getAllocations
814 time2 <- io $ getCPUTime
815 io $ printTimes (allocs2 - allocs1) (time2 - time1)
818 foreign import "getAllocations" getAllocations :: IO Int
820 printTimes :: Int -> Integer -> IO ()
821 printTimes allocs psecs
822 = do let secs = (fromIntegral psecs / (10^12)) :: Float
823 secs_str = showFFloat (Just 2) secs
825 parens (text (secs_str "") <+> text "secs" <> comma <+>
826 int allocs <+> text "bytes")))
828 -----------------------------------------------------------------------------
831 foreign import revertCAFs :: IO () -- make it "safe", just in case