[source]

compiler/ghci/Linker.hs

Note [Crash early load_dyn and locateLib]

[note link]

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.

Note [Fork/Exec Windows]

[note link]

fork/exec is expensive on Windows, for each time we ask GCC for a library we have to eat the cost of af least 3 of these: gcc -> real_gcc -> cc1. So instead get a list of location that GCC would search and use findDirs which hopefully is written in an optimized mannor to take advantage of caching. At the very least we remove the overhead of the fork/exec and waits which dominate a large percentage of startup time on Windows.