summaryrefslogtreecommitdiff
path: root/compiler/ghci
diff options
context:
space:
mode:
authorTamar Christina <tamar@zhox.com>2016-04-17 13:03:17 +0200
committerTamar Christina <tamar@zhox.com>2016-04-17 13:06:40 +0200
commit97f2b16483aae28dc8fd60b6d2e1e283618f2390 (patch)
tree6b9444496a6cbe758a9fff0b05ac969fd87fa188 /compiler/ghci
parent4cbae1bd70097a2d365ce0644145a8203956d59a (diff)
downloadhaskell-97f2b16483aae28dc8fd60b6d2e1e283618f2390.tar.gz
Add Windows import library support to the Runtime Linker
Summary: Import libraries are files ending in `.dll.a` and `.lib` depending on which compiler creates them (GCC, vs MSVC). Import Libraries are standard `archive` files that contain object files. These object files can have two different formats: 1) The normal COFF Object format for object files (contains all ascii data and very little program code, so do not try to execute.) 2) "short import" format which just contains a symbol name and the dll in which the symbol can be found. Import Libraries are useful for two things: 1) Allowing applications that don't support dynamic linking to link against the import lib (non-short format) which then makes calls into the DLL by loading it at runtime. 2) Allow linking of mutually recursive dlls. if `A.DLL` requires `B.DLL` and vice versa, import libs can be used to break the cycle as they can be created from the expected exports of the DLLs. A side effect of having these two capabilities is that Import libs are often used to hide specific versions of DLLs behind a non-versioned import lib. e.g. GCC_S.a (non-conventional import lib) will point to the correct `libGCC` DLL. With this support Windows Haskell files can now just link to `-lGCC_S` and not have to worry about what the actual name of libGCC is. Also third party libraries such as `icuuc` use import libs to forward to versioned DLLs. e.g. `icuuc.lib` points to `icuuc51.dll` etc. Test Plan: ./validate Two new tests added T11072gcc T11072msvc Two binary files have been added to the test folder because the "short" import library format doesn't seem to be creatable via `dlltool` and requires Microsoft's `lib.exe`. Reviewers: bgamari, RyanGlScott, erikd, goldfire, austin, hvr Reviewed By: RyanGlScott, erikd Subscribers: thomie Differential Revision: https://phabricator.haskell.org/D1696 GHC Trac Issues: #11072
Diffstat (limited to 'compiler/ghci')
-rw-r--r--compiler/ghci/Linker.hs50
1 files changed, 34 insertions, 16 deletions
diff --git a/compiler/ghci/Linker.hs b/compiler/ghci/Linker.hs
index 4b8a322f58..5042136ce3 100644
--- a/compiler/ghci/Linker.hs
+++ b/compiler/ghci/Linker.hs
@@ -1227,9 +1227,6 @@ linkPackage hsc_env pkg
mapM_ (load_dyn hsc_env)
(known_dlls ++ map (mkSOName platform) dlls)
- -- DLLs are loaded, reset the search paths
- mapM_ (removeLibrarySearchPath hsc_env) $ reverse pathCache
-
-- After loading all the DLLs, we can load the static objects.
-- Ordering isn't important here, because we do one final link
-- step to resolve everything.
@@ -1238,6 +1235,13 @@ linkPackage hsc_env pkg
maybePutStr dflags "linking ... "
ok <- resolveObjs hsc_env
+
+ -- DLLs are loaded, reset the search paths
+ -- Import libraries will be loaded via loadArchive so only
+ -- reset the DLL search path after all archives are loaded
+ -- as well.
+ mapM_ (removeLibrarySearchPath hsc_env) $ reverse pathCache
+
if succeeded ok
then maybePutStrLn dflags "done."
else let errmsg = "unable to load package `"
@@ -1281,9 +1285,10 @@ locateLib hsc_env is_hs dirs lib
-- For non-Haskell libraries (e.g. gmp, iconv):
-- first look in library-dirs for a dynamic library (libfoo.so)
-- then look in library-dirs for a static library (libfoo.a)
- -- first look in library-dirs and inplace GCC for a dynamic library (libfoo.so)
+ -- then look in library-dirs and inplace GCC for a dynamic library (libfoo.so)
-- then check for system dynamic libraries (e.g. kernel32.dll on windows)
-- then try "gcc --print-file-name" to search gcc's search path
+ -- then try looking for import libraries on Windows (.dll.a, .lib)
-- then look in library-dirs and inplace GCC for a static library (libfoo.a)
-- for a dynamic library (#5289)
-- otherwise, assume loadDLL can find it
@@ -1291,6 +1296,7 @@ locateLib hsc_env is_hs dirs lib
= findDll `orElse`
findSysDll `orElse`
tryGcc `orElse`
+ tryImpLib `orElse`
findArchive `orElse`
assumeDll
@@ -1321,31 +1327,43 @@ locateLib hsc_env is_hs dirs lib
loading_profiled_hs_libs = interpreterProfiled dflags
loading_dynamic_hs_libs = interpreterDynamic dflags
+ import_libs = [lib <.> "lib", "lib" ++ lib <.> "lib", "lib" ++ lib <.> "dll.a"]
+
hs_dyn_lib_name = lib ++ '-':programName dflags ++ projectVersion dflags
hs_dyn_lib_file = mkHsSOName platform hs_dyn_lib_name
- so_name = mkSOName platform lib
+ so_name = mkSOName platform lib
lib_so_name = "lib" ++ so_name
dyn_lib_file = case (arch, os) of
(ArchX86_64, OSSolaris2) -> "64" </> so_name
_ -> so_name
- findObject = liftM (fmap Object) $ findFile dirs obj_file
- findDynObject = liftM (fmap Object) $ findFile dirs dyn_obj_file
- findArchive = let local = liftM (fmap Archive) $ findFile dirs arch_file
- linked = liftM (fmap Archive) $ searchForLibUsingGcc dflags arch_file dirs
- in liftM2 (<|>) local linked
- findHSDll = liftM (fmap DLLPath) $ findFile dirs hs_dyn_lib_file
- findDll = liftM (fmap DLLPath) $ findFile dirs dyn_lib_file
- findSysDll = fmap (fmap $ DLL . takeFileName) $ findSystemLibrary hsc_env so_name
- tryGcc = let short = liftM (fmap DLLPath) $ searchForLibUsingGcc dflags so_name dirs
- full = liftM (fmap DLLPath) $ searchForLibUsingGcc dflags lib_so_name dirs
- in liftM2 (<|>) short full
+ findObject = liftM (fmap Object) $ findFile dirs obj_file
+ findDynObject = liftM (fmap Object) $ findFile dirs dyn_obj_file
+ findArchive = let local = liftM (fmap Archive) $ findFile dirs arch_file
+ linked = liftM (fmap Archive) $ searchForLibUsingGcc dflags arch_file dirs
+ in liftM2 (<|>) local linked
+ findHSDll = liftM (fmap DLLPath) $ findFile dirs hs_dyn_lib_file
+ findDll = liftM (fmap DLLPath) $ findFile dirs dyn_lib_file
+ findSysDll = fmap (fmap $ DLL . takeFileName) $ findSystemLibrary hsc_env so_name
+ tryGcc = let short = liftM (fmap DLLPath) $ searchForLibUsingGcc dflags so_name dirs
+ full = liftM (fmap DLLPath) $ searchForLibUsingGcc dflags lib_so_name dirs
+ in liftM2 (<|>) short full
+ tryImpLib = case os of
+ OSMinGW32 -> let check name = liftM (fmap Archive) $ searchForLibUsingGcc dflags name dirs
+ in apply (map check import_libs)
+ _ -> return Nothing
assumeDll = return (DLL lib)
infixr `orElse`
f `orElse` g = f >>= maybe g return
+ apply [] = return Nothing
+ apply (x:xs) = do x' <- x
+ if isJust x'
+ then return x'
+ else apply xs
+
platform = targetPlatform dflags
arch = platformArch platform
os = platformOS platform