[...snip...]lookupSymbol: looking up __imp__WSACleanup@0initLinker: startinitLinker: idempotent returnlookupSymbol: symbol not found<interactive>: C:\mnt\data1\ghc32b\network-2.3.0.14\ghc-7.4.2\HSnetwork-2.3.0.14.o: unknown symbol `__imp__WSACleanup'[...snip...]
The symbol to be resolved:
$ nm network-2.3.0.14/ghc-7.4.2/HSnetwork-2.3.0.14.o |grep WSACleanup U __imp__WSACleanup@0
WSACleanup is declared __declspec(dllimport) in the MinGW CRT headers.
That makes the object file to refer to __imp__WSACleanup@0, to be resolved through a stub library of MinGW named libws2_32.a. ws2_32 is mentioned in the extra-libraries field of the network package entry in the ghc package configuration database, so -lws2_32 is added to the linker command arguments. From the linker documentation:
For instance, when ld is called with the argument `-lxxx' it will attempt to find, in the first directory of its search path, libxxx.dll.a xxx.dll.a libxxx.a xxx.lib cygxxx.dll (*) libxxx.dll xxx.dll before moving on to the next directory in the search path.
So the linker finds libws2_32.a in one of the search paths passed on on the command line (through the built-in gcc specs, cf. link_gcc_c_sequence).
When linking the binary, how does the linker know it also needs ws2_32.dll?
It doesn't. Only the stub file is linked in. The stub file is a peculiar to Windows way to produce an indirection/relocation. When the produced binary is executed, the Windows dynamic loader takes care of the __imp__WSACleanup@0 symbol redirection/resolution.
I wonder why GHCi doesn't also find libws2_32.a? Maybe it isn't on the search path for some reason.
It doesn't search for libxxx.a, and the path searched does not include the location of the stub file. Also, I believe the PEI386 handling in rts/Linker.c currently would be unable to load such stub files.
Please, pardon my brevity, still looking into this.
libws2_32.a in MinGW-w64 is an archive combining objects created from a .def file and the C sources `src_libws2_32`.
The .deffile declares the indirection:
;; Definition file of WS2_32.dll; Automatic generated by gendef; written by Kai Tietz 2008;LIBRARY "WS2_32.dll"EXPORTS[...snip...]WSACleanup@0[...snip...]
To recap, the final linkage is done by the Windows dynamic loader using the DLL dependency information in the executable import tables. The partially linked object file HSnetwork-2.3.0.14.o which GHCi tries to load for the network package has no such information. In order for GCHi to be able to load such a package, it at least needs to:
be supplied with that information (perhaps via extra-libraries/extra-ghci-libraries fields in the package's .cabal file);
find the MinGW stub libraries the partially linked file depends upon (cf. compiler/ghci/Linker.lhs);
know how to load the stub libraries (currently no .idata sections processing in rts/Linker.c).
Ehm, wasn't thinking straight, there's no need to load the stub libraries, as they're already linked into the partially linked object file. So s/MinGW stub libraries/DLLs/ in (2) and s/stub libraries/DLLs/ in (3).
The confusion source is a similar bug #3242 (closed), where a reference to an undefined symbol _copysignf is found in the partially linked object file HSieee754-0.7.3.o of the ieee754 package. The undefined symbol reference doesn't come directly from a MinGW-w64 stub library, though.
Notice that in #3242 (closed) the undefined reference to _copysignf is still expected to be satisfied from a MinGW-w64 stub library named libmingwex.a which happens to implement the actual function, as MSVCRT doesn't. As a result GHCi fails to load the ieee754 package.
(for #3242 (closed)) arrange for GHCi to satisfy undefined references to symbols also via MinGW-w64 stub libraries (the list of which to be supplied by package authors via extra-libraries/extra-ghci-libraries);
implement the indirect __imp__* symbols resolution in GHCi.
Could you explain what is special about the WSACleanup symbol here? Why is it different from any other symbol that we import from a DLL? After all, we call a lot of functions that live in DLLs.
After all, we call a lot of functions that live in DLLs.
We only manage to do that for the fully linked by GNU ld executable images, which get loaded into the memory by the Windows dynamic loader, which, in turn, specially processes these 'import' symbols.
Could you explain what is special about the WSACleanup symbol here? Why is it different from any other symbol that we import from a DLL? After all, we call a lot of functions that live in DLLs.
Rephrasing that made the issue become more apparent, thanks. Why is it that only some packages that import from foreign libraries get references to the __imp_ prefixed symbols and most others don't? Most foreign functionality gets explictly declared and refered to using the Haskell FFI foreign import declarations. Some functionality, though, gets declared and refered to implicitly, via C headers, as in the case with the network package:
network-2.3.0.14/Network/Socket/Internal.hsc:
[...snip...]withSocketsDo :: IO a -> IO a#if !defined(WITH_WINSOCK)withSocketsDo x = x#elsewithSocketsDo act = do x <- initWinSock[...snip...]foreign import ccall unsafe "initWinSock" initWinSock :: IO Intforeign import ccall unsafe "shutdownWinSock" shutdownWinSock :: IO ()#endif[...snip...]
On Microsoft Windows and Symbian OS targets, the dllimport attribute causes the compiler to reference a function or variable via a global pointer to a pointer that is set up by the DLL exporting the symbol. The attribute implies extern. On Microsoft Windows targets, the pointer name is formed by combining _imp__ and the function or variable name.
The codegen has no control over the symbol name emitted, unlike the explicitly declared imports cases:
Suppose we have some compiled dll exporting some function foo. Suppose we write a client program in C calling this foo. Regardless of how this foo is prototyped: as bare foo or as __declspec(dllimport) foo a client program will happily call it, but depending on a prototype in different ways: in the first case this will be call foo and if this symbol is external a linker will generate a thunk for this foo as jmp __imp_foo, in the second case a C compiler always generates call __imp_foo.
Thus the single thing matters here: which prototype of a function was visible to C compiler when it compiled a code calling that function. If that prototype had __declspec(dllimport) attribute attached, a C compiler generated a call against __imp_foo, otherwise - a call against bare foo. GHC FFI of modern era (with no C backend) always generates the second variant AFAIK.
This also explains the difference between 32 and 64 GHCs for Windows. 64-bit GHC is distributed with mingw-w64 headers which use __declspec(dllimport) extensively, and many packages fail to compile. 32-bit GHC is distributed with mingw headers which has almost (or entirely?) no __declspec(dllimport) declared APIs.
To make 64-bit GHC usable on Windows I manually removed all __declspec(dllimport) from mingw-w64 headers and now it all works smoothly.