3
3
{-# LANGUAGE UnboxedTuples #-}
4
4
{-# LANGUAGE ForeignFunctionInterface #-}
5
5
--
6
- -- Copyright (C) 2004-5 Don Stewart - http://www.cse.unsw.edu.au/~dons
7
- --
6
+ -- Copyright (C) 2004-5 Don Stewart
7
+ --
8
8
-- This library is free software; you can redistribute it and/or
9
9
-- modify it under the terms of the GNU Lesser General Public
10
10
-- License as published by the Free Software Foundation; either
11
11
-- version 2.1 of the License, or (at your option) any later version.
12
- --
12
+ --
13
13
-- This library is distributed in the hope that it will be useful,
14
14
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
15
15
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
16
-- Lesser General Public License for more details.
17
- --
17
+ --
18
18
-- You should have received a copy of the GNU Lesser General Public
19
19
-- License along with this library; if not, write to the Free Software
20
20
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21
21
-- USA
22
- --
22
+ --
23
23
24
24
-- | An interface to the GHC runtime's dynamic linker, providing runtime
25
25
-- loading and linking of Haskell object files, commonly known as
@@ -34,7 +34,7 @@ module System.Plugins.Load (
34
34
, load
35
35
, load_
36
36
, dynload
37
- , pdynload
37
+ , pdynload
38
38
, pdynload_
39
39
, unload
40
40
, unloadAll
@@ -149,7 +149,7 @@ data LoadStatus a
149
149
-- provided with appropriate type constraints such that Haskell compiler
150
150
-- can determine the expected type returned by 'load', as the return
151
151
-- type is notionally polymorphic.
152
- --
152
+ --
153
153
-- Example:
154
154
--
155
155
-- > do mv <- load "Plugin.o" ["api"] [] "resource"
@@ -184,18 +184,21 @@ load obj incpaths pkgconfs sym = do
184
184
#endif
185
185
addModuleDeps m' moduleDeps
186
186
v <- loadFunction m sym
187
- return $ case v of
187
+ return $ case v of
188
188
Nothing -> LoadFailure [" load: couldn't find symbol <<" ++ sym++ " >>" ]
189
189
Just a -> LoadSuccess m a
190
190
191
191
--
192
192
-- | Like load, but doesn't want a package.conf arg (they are rarely used)
193
193
--
194
- load_ :: FilePath -> [FilePath ] -> Symbol -> IO (LoadStatus a )
194
+ load_ :: FilePath -- ^ object file
195
+ -> [FilePath ] -- ^ any include paths
196
+ -> Symbol -- ^ symbol to find
197
+ -> IO (LoadStatus a )
195
198
load_ o i s = load o i [] s
196
199
197
- --
198
- -- A work-around for Dynamics. The keys used to compare two TypeReps are
200
+
201
+ -- | A work-around for Dynamics. The keys used to compare two TypeReps are
199
202
-- somehow not equal for the same type in hs-plugin's loaded objects.
200
203
-- Solution: implement our own dynamics...
201
204
--
@@ -204,8 +207,8 @@ load_ o i s = load o i [] s
204
207
-- is not the case, we core dump. Use pdynload if you don't trust the
205
208
-- user to supply you with a Dynamic
206
209
--
207
- dynload :: Typeable a
208
- => FilePath
210
+ dynload :: Typeable a
211
+ => FilePath
209
212
-> [FilePath ]
210
213
-> [PackageConf ]
211
214
-> Symbol
@@ -220,7 +223,8 @@ dynload obj incpaths pkgconfs sym = do
220
223
Nothing -> LoadFailure [" Mismatched types in interface" ]
221
224
222
225
------------------------------------------------------------------------
223
- --
226
+
227
+ -- |
224
228
-- The super-replacement for dynload
225
229
--
226
230
-- Use GHC at runtime so we get staged type inference, providing full
@@ -229,23 +233,22 @@ dynload obj incpaths pkgconfs sym = do
229
233
--
230
234
-- TODO where does the .hc file go in the call to build() ?
231
235
--
232
-
233
236
pdynload :: FilePath -- ^ object to load
234
237
-> [FilePath ] -- ^ include paths
235
238
-> [PackageConf ] -- ^ package confs
236
239
-> Type -- ^ API type
237
240
-> Symbol -- ^ symbol
238
241
-> IO (LoadStatus a )
239
242
240
- pdynload object incpaths pkgconfs ty sym = do
243
+ pdynload object incpaths pkgconfs ty sym = do
241
244
#if DEBUG
242
245
putStr " Checking types ... " >> hFlush stdout
243
246
#endif
244
247
errors <- unify object incpaths [] ty sym
245
248
#if DEBUG
246
249
putStrLn " done"
247
250
#endif
248
- if null errors
251
+ if null errors
249
252
then load object incpaths pkgconfs sym
250
253
else return $ LoadFailure errors
251
254
@@ -269,12 +272,12 @@ pdynload_ object incpaths pkgconfs args ty sym = do
269
272
#if DEBUG
270
273
putStrLn " done"
271
274
#endif
272
- if null errors
275
+ if null errors
273
276
then load object incpaths pkgconfs sym
274
277
else return $ LoadFailure errors
275
278
276
279
------------------------------------------------------------------------
277
- -- run the typechecker over the constraint file
280
+ -- | run the typechecker over the constraint file
278
281
--
279
282
-- Problem: if the user depends on a non-auto package to build the
280
283
-- module, then that package will not be in scope when we try to build
@@ -290,7 +293,7 @@ unify obj incs args ty sym = do
290
293
(tmpf1,hdl1) <- mkTemp -- and send .hi file here.
291
294
hClose hdl1
292
295
293
- let nm = mkModid (basename tmpf)
296
+ let nm = mkModid (basename tmpf)
294
297
src = mkTest nm (hierize' . mkModid . hierize $ obj)
295
298
(fst $ break (== ' .' ) ty) ty sym
296
299
is = map (" -i" ++ ) incs -- api
@@ -312,7 +315,7 @@ unify obj incs args ty sym = do
312
315
hierize' (' \\ ' : cs) = ' .' : hierize' cs
313
316
hierize' (c: cs) = c : hierize' cs
314
317
315
- mkTest modnm plugin api ty sym =
318
+ mkTest modnm plugin api ty sym =
316
319
" module " ++ modnm ++ " where" ++
317
320
" \n import qualified " ++ plugin ++
318
321
" \n import qualified " ++ api ++
@@ -327,11 +330,11 @@ mkTest modnm plugin api ty sym =
327
330
pdynload obj incpaths pkgconfs sym ty = do
328
331
(m, v) <- load obj incpaths pkgconfs sym
329
332
ty' <- mungeIface sym obj
330
- if ty == ty'
333
+ if ty == ty'
331
334
then return $ Just (m, v)
332
335
else return Nothing -- mismatched types
333
336
334
- where
337
+ where
335
338
-- grab the iface output from GHC. find the line relevant to our
336
339
-- symbol. grab the string rep of the type.
337
340
mungeIface sym o = do
@@ -348,11 +351,11 @@ pdynload obj incpaths pkgconfs sym ty = do
348
351
--
349
352
-- a version of load the also unwraps and types a Dynamic object
350
353
--
351
- dynload2 :: Typeable a =>
352
- FilePath ->
353
- FilePath ->
354
+ dynload2 :: Typeable a =>
355
+ FilePath ->
356
+ FilePath ->
354
357
Maybe [PackageConf] ->
355
- Symbol ->
358
+ Symbol ->
356
359
IO (Module, a)
357
360
358
361
dynload2 obj incpath pkgconfs sym = do
@@ -402,13 +405,13 @@ reload m@(Module{path = p, iface = hi}) sym = do
402
405
#endif
403
406
m_ <- loadObject p . Object . ifaceModuleName $ hi -- load object at path p
404
407
let m' = m_ { iface = hi }
405
-
408
+
406
409
resolveObjs (unloadAll m)
407
410
#if DEBUG
408
411
putStrLn " done" >> hFlush stdout
409
412
#endif
410
413
v <- loadFunction m' sym
411
- return $ case v of
414
+ return $ case v of
412
415
Nothing -> LoadFailure [" load: couldn't find symbol <<" ++ sym++ " >>" ]
413
416
Just a -> LoadSuccess m' a
414
417
@@ -493,31 +496,29 @@ loadPackageFunction pkgName modName functionName =
493
496
-- NB the environment stores the *full path* to an object. So if you
494
497
-- want to know if a module is already loaded, you need to supply the
495
498
-- *path* to that object, not the name.
496
- --
499
+ --
497
500
-- NB -- let's try just the module name.
498
501
--
499
502
-- loadObject loads normal .o objs, and packages too. .o objs come with
500
503
-- a nice canonical Z-encoded modid. packages just have a simple name.
501
504
-- Do we want to ensure they won't clash? Probably.
502
505
--
503
-
506
+ --
504
507
--
505
508
-- the second argument to loadObject is a string to use as the unique
506
509
-- identifier for this object. For normal .o objects, it should be the
507
510
-- Z-encoded modid from the .hi file. For archives\/packages, we can
508
511
-- probably get away with the package name
509
512
--
510
-
511
-
512
513
loadObject :: FilePath -> Key -> IO Module
513
- loadObject p ky@ (Object k) = loadObject' p ky k
514
- loadObject p ky@ (Package k) = loadObject' p ky k
514
+ loadObject p ky@ (Object k) = loadObject' p ky k
515
+ loadObject p ky@ (Package k) = loadObject' p ky k
515
516
516
517
loadObject' :: FilePath -> Key -> String -> IO Module
517
518
loadObject' p ky k
518
519
| (" HSrts" ++ sysPkgSuffix) `isSuffixOf` p = return (emptyMod p)
519
520
520
- | otherwise
521
+ | otherwise
521
522
= do alreadyLoaded <- isLoaded k
522
523
when (not alreadyLoaded) $ do
523
524
r <- withCString p c_loadObj
@@ -527,7 +528,7 @@ loadObject' p ky k
527
528
528
529
where emptyMod q = Module q (mkModid q) Vanilla undefined ky
529
530
530
- --
531
+ -- |
531
532
-- load a single object. no dependencies. You should know what you're
532
533
-- doing.
533
534
--
@@ -560,11 +561,11 @@ resolveObjs unloadLoaded
560
561
561
562
562
563
-- | Unload a module
563
- unloadObj :: Module -> IO ()
564
+ unloadObj :: Module -> IO ()
564
565
unloadObj (Module { path = p, kind = k, key = ky }) = case k of
565
566
Vanilla -> withCString p $ \ c_p -> do
566
567
removed <- rmModule name
567
- when (removed) $ do r <- c_unloadObj c_p
568
+ when (removed) $ do r <- c_unloadObj c_p
568
569
when (not r) (panic " unloadObj: failed" )
569
570
Shared -> return () -- can't unload .so?
570
571
where name = case ky of Object s -> s ; Package pk -> pk
@@ -579,14 +580,14 @@ loadShared str = do
579
580
putStrLn $ " shared: " ++ str
580
581
#endif
581
582
maybe_errmsg <- withCString str $ \ dll -> c_addDLL dll
582
- if maybe_errmsg == nullPtr
583
+ if maybe_errmsg == nullPtr
583
584
then return (Module str (mkModid str) Shared undefined (Package (mkModid str)))
584
585
else do e <- peekCString maybe_errmsg
585
586
panic $ " loadShared: couldn't load `" ++ str++ " \' because " ++ e
586
587
587
588
588
589
--
589
- -- Load a -package that we might need, implicitly loading the cbits too
590
+ -- | Load a -package that we might need, implicitly loading the cbits too
590
591
-- The argument is the name of package (e.g. \"concurrent\")
591
592
--
592
593
-- How to find a package is determined by the package.conf info we store
@@ -610,7 +611,7 @@ loadPackage p = do
610
611
611
612
612
613
--
613
- -- Unload a -package, that has already been loaded. Unload the cbits
614
+ -- | Unload a -package, that has already been loaded. Unload the cbits
614
615
-- too. The argument is the name of the package.
615
616
--
616
617
-- May need to check if it exists.
@@ -625,12 +626,12 @@ unloadPackage pkg = do
625
626
let pkg' = takeWhile (/= ' -' ) pkg -- in case of *-0.1
626
627
libs <- liftM (\ (a,_) -> (filter (isSublistOf pkg') ) a) (lookupPkg pkg)
627
628
flip mapM_ libs $ \ p -> withCString p $ \ c_p -> do
628
- r <- c_unloadObj c_p
629
+ r <- c_unloadObj c_p
629
630
when (not r) (panic " unloadObj: failed" )
630
- rmModule (mkModid p) -- unrecord this module
631
+ rmModule (mkModid p) -- unrecord this module
631
632
632
633
--
633
- -- load a package using the given package.conf to help
634
+ -- | load a package using the given package.conf to help
634
635
-- TODO should report if it doesn't actually load the package, instead
635
636
-- of mapM_ doing nothing like above.
636
637
--
@@ -644,10 +645,10 @@ loadPackageWith p pkgconfs = do
644
645
#if DEBUG
645
646
putStrLn " done"
646
647
#endif
647
-
648
+
648
649
649
650
-- ---------------------------------------------------------------------
650
- -- module dependency loading
651
+ -- | module dependency loading
651
652
--
652
653
-- given an Foo.o vanilla object file, supposed to be a plugin compiled
653
654
-- by our library, find the associated .hi file. If this is found, load
@@ -684,11 +685,11 @@ loadDepends obj incpaths = do
684
685
685
686
-- now, try to generate a path to the actual .o file
686
687
-- fix up hierachical names
687
- let mods_ = map (\ s -> (s, map (\ c ->
688
+ let mods_ = map (\ s -> (s, map (\ c ->
688
689
if c == ' .' then ' /' else c) $ s)) ds'
689
690
690
691
-- construct a list of possible dependent modules to load
691
- let mods = concatMap (\ p ->
692
+ let mods = concatMap (\ p ->
692
693
map (\ (hi,m) -> (hi,p </> m++ " .o" )) mods_) incpaths
693
694
694
695
-- remove modules that don't exist
@@ -717,15 +718,15 @@ loadDepends obj incpaths = do
717
718
#endif
718
719
resolveObjs (mapM_ unloadPackage ps')
719
720
#if DEBUG
720
- when (not (null ps')) $ putStrLn " done"
721
- putStr " Loading object"
721
+ when (not (null ps')) $ putStrLn " done"
722
+ putStr " Loading object"
722
723
mapM_ (\ (m,_) -> putStr (" " ++ m) >> hFlush stdout) mods''
723
724
#endif
724
725
moduleDeps <- mapM (\ (hi,m) -> loadObject m (Object hi)) mods''
725
726
return (hiface,moduleDeps)
726
727
727
728
-- ---------------------------------------------------------------------
728
- -- Nice interface to .hi parser
729
+ -- | Nice interface to .hi parser
729
730
--
730
731
getImports :: String -> IO [String ]
731
732
getImports m = do
0 commit comments