diff options
| -rw-r--r-- | compiler/ghci/Linker.hs | 77 | ||||
| -rw-r--r-- | compiler/main/DynFlags.hs | 3 | ||||
| -rw-r--r-- | docs/users_guide/using-warnings.rst | 11 | 
3 files changed, 82 insertions, 9 deletions
diff --git a/compiler/ghci/Linker.hs b/compiler/ghci/Linker.hs index 9f1307d798..32bf270abd 100644 --- a/compiler/ghci/Linker.hs +++ b/compiler/ghci/Linker.hs @@ -1262,8 +1262,9 @@ linkPackage hsc_env pkg     = do          let dflags    = hsc_dflags hsc_env              platform  = targetPlatform dflags -            dirs | interpreterDynamic dflags = Packages.libraryDynDirs pkg -                 | otherwise                 = Packages.libraryDirs pkg +            is_dyn = interpreterDynamic dflags +            dirs | is_dyn    = Packages.libraryDynDirs pkg +                 | otherwise = Packages.libraryDirs pkg          let hs_libs   =  Packages.hsLibraries pkg              -- The FFI GHCi import lib isn't needed as @@ -1313,8 +1314,12 @@ linkPackage hsc_env pkg          -- See comments with partOfGHCi          when (packageName pkg `notElem` partOfGHCi) $ do              loadFrameworks hsc_env platform pkg -            mapM_ (load_dyn hsc_env) -              (known_dlls ++ map (mkSOName platform) dlls) +            -- See Note [Crash early load_dyn and locateLib] +            -- Crash early if can't load any of `known_dlls` +            mapM_ (load_dyn hsc_env True) known_dlls +            -- For remaining `dlls` crash early only when there is surely +            -- no package's DLL around ... (not is_dyn) +            mapM_ (load_dyn hsc_env (not is_dyn) . mkSOName platform) dlls          -- After loading all the DLLs, we can load the static objects.          -- Ordering isn't important here, because we do one final link @@ -1337,18 +1342,72 @@ linkPackage hsc_env pkg                               ++ sourcePackageIdString pkg ++ "'"                   in throwGhcExceptionIO (InstallationError errmsg) +{- +Note [Crash early load_dyn and locateLib] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If a package is "normal" (exposes it's code from more than zero Haskell +modules, unlike e.g. that in ghcilink004) and is built "dyn" way, then +it has it's code compiled and linked into the DLL, which GHCi linker picks +when loading the package's code (see the big comment in the beginning of +`locateLib`). + +When loading DLLs, GHCi linker simply calls the system's `dlopen` or +`LoadLibrary` APIs. This is quite different from the case when GHCi linker +loads an object file or static library. When loading an object file or static +library GHCi linker parses them and resolves all symbols "manually". +These object file or static library may reference some external symbols +defined in some external DLLs. And GHCi should know which these +external DLLs are. + +But when GHCi loads a DLL, it's the *system* linker who manages all +the necessary dependencies, and it is able to load this DLL not having +any extra info. Thus we don't *have to* crash in this case even if we +are unable to load any supposed dependencies explicitly. + +Suppose during GHCi session a client of the package wants to +`foreign import` a symbol which isn't exposed by the package DLL, but +is exposed by such an external (dependency) DLL. +If the DLL isn't *explicitly* loaded because `load_dyn` failed to do +this, then the client code eventually crashes because the GHCi linker +isn't able to locate this symbol (GHCi linker maintains a list of +explicitly loaded DLLs it looks into when trying to find a symbol). + +This is why we still should try to load all the dependency DLLs +even though we know that the system linker loads them implicitly when +loading the package DLL. + +Why we still keep the `crash_early` opportunity then not allowing such +a permissive behaviour for any DLLs? Well, we, perhaps, improve a user +experience in some cases slightly. + +But if it happens there exist other corner cases where our current +usage of `crash_early` flag is overly restrictive, we may lift the +restriction very easily. +-} +  -- we have already searched the filesystem; the strings passed to load_dyn  -- can be passed directly to loadDLL.  They are either fully-qualified  -- ("/usr/lib/libfoo.so"), or unqualified ("libfoo.so").  In the latter case,  -- loadDLL is going to search the system paths to find the library. --- -load_dyn :: HscEnv -> FilePath -> IO () -load_dyn hsc_env dll = do +load_dyn :: HscEnv -> Bool -> FilePath -> IO () +load_dyn hsc_env crash_early dll = do    r <- loadDLL hsc_env dll    case r of      Nothing  -> return () -    Just err -> cmdLineErrorIO ("can't load .so/.DLL for: " -                                ++ dll ++ " (" ++ err ++ ")") +    Just err -> +      if crash_early +        then cmdLineErrorIO err +        else let dflags = hsc_dflags hsc_env in +          when (wopt Opt_WarnMissedExtraSharedLib dflags) +            $ putLogMsg dflags +                (Reason Opt_WarnMissedExtraSharedLib) SevWarning +                  noSrcSpan (defaultUserStyle dflags)(note err) +  where +    note err = vcat $ map text +      [ err +      , "It's OK if you don't want to use symbols from it directly." +      , "(the package DLL is loaded by the system linker" +      , " which manages dependencies by itself)." ]  loadFrameworks :: HscEnv -> Platform -> PackageConfig -> IO ()  loadFrameworks hsc_env platform pkg diff --git a/compiler/main/DynFlags.hs b/compiler/main/DynFlags.hs index 48c7103dd9..9e93e47eeb 100644 --- a/compiler/main/DynFlags.hs +++ b/compiler/main/DynFlags.hs @@ -807,6 +807,7 @@ data WarningFlag =     | Opt_WarnAllMissedSpecs     | Opt_WarnUnsupportedCallingConventions     | Opt_WarnUnsupportedLlvmVersion +   | Opt_WarnMissedExtraSharedLib     | Opt_WarnInlineRuleShadowing     | Opt_WarnTypedHoles     | Opt_WarnPartialTypeSignatures @@ -3985,6 +3986,7 @@ wWarningFlagsDeps = [    flagSpec "unsupported-calling-conventions"                                           Opt_WarnUnsupportedCallingConventions,    flagSpec "unsupported-llvm-version"    Opt_WarnUnsupportedLlvmVersion, +  flagSpec "missed-extra-shared-lib"     Opt_WarnMissedExtraSharedLib,    flagSpec "unticked-promoted-constructors"                                           Opt_WarnUntickedPromotedConstructors,    flagSpec "unused-do-bind"              Opt_WarnUnusedDoBind, @@ -4707,6 +4709,7 @@ standardWarnings -- see Note [Documenting warning flags]          Opt_WarnInlineRuleShadowing,          Opt_WarnAlternativeLayoutRuleTransitional,          Opt_WarnUnsupportedLlvmVersion, +        Opt_WarnMissedExtraSharedLib,          Opt_WarnTabs,          Opt_WarnUnrecognisedWarningFlags,          Opt_WarnSimplifiableClassConstraints, diff --git a/docs/users_guide/using-warnings.rst b/docs/users_guide/using-warnings.rst index fe3c8cb58c..6a6166bf0d 100644 --- a/docs/users_guide/using-warnings.rst +++ b/docs/users_guide/using-warnings.rst @@ -39,6 +39,7 @@ generally likely to indicate bugs in your program. These are:      * :ghc-flag:`-Wdodgy-foreign-imports`      * :ghc-flag:`-Winline-rule-shadowing`      * :ghc-flag:`-Wunsupported-llvm-version` +    * :ghc-flag:`-Wmissed-extra-shared-lib`      * :ghc-flag:`-Wtabs`      * :ghc-flag:`-Wunrecognised-warning-flags`      * :ghc-flag:`-Winaccessible-code` @@ -1326,6 +1327,16 @@ of ``-W(no-)*``.      Warn when using :ghc-flag:`-fllvm` with an unsupported version of LLVM. +.. ghc-flag:: -Wmissed-extra-shared-lib +    :shortdesc: Warn when GHCi can't load a shared lib. +    :type: dynamic +    :reverse: -Wno-missed-extra-shared-lib +    :category: + +    Warn when GHCi can't load a shared lib it deduced it should load +    when loading a package and analyzing the extra-libraries stanza +    of the target package description. +  .. ghc-flag:: -Wunticked-promoted-constructors      :shortdesc: warn if promoted constructors are not ticked      :type: dynamic  | 
