diff options
author | Tamar Christina <tamar@zhox.com> | 2016-04-17 13:03:17 +0200 |
---|---|---|
committer | Tamar Christina <tamar@zhox.com> | 2016-04-17 13:06:40 +0200 |
commit | 97f2b16483aae28dc8fd60b6d2e1e283618f2390 (patch) | |
tree | 6b9444496a6cbe758a9fff0b05ac969fd87fa188 /compiler/ghci | |
parent | 4cbae1bd70097a2d365ce0644145a8203956d59a (diff) | |
download | haskell-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.hs | 50 |
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 |