
On Mon, 2 Sep 2002 11:31:27 +0100
"Simon Marlow"
So here's another idea. ghc's linker provides (via the ffi) a command addDLL to load dynamic libraries. It uses dlopen on unix and LoadLibrary on win32.
Now, with dlopen if you pass it NULL rather than the filename of a library it will give you back a handle to itself - the program that called it. If you've linked your program with the right incantations this gives you access to all the symbols in the main program.
Yes, we already use dlopen() with NULL to get symbols from other shared libraries, so you can refer to things like printf() from libc.
I noticed this just after posting, so you don't even need to do call addDLL, just doing initLinker is sufficient.
I didn't know about -export-dynamic: yes, it looks like that would do exactly the right thing. The linker might not even need any modification for this to work, because we already fall back to using dlsym() for a symbol that the linker can't find in its own symbol table.
[... I've just tried a simple example using -export-dynamic, and it does indeed work as advertised... ]
In fact it all works quite nicely, I've got a test program with a little plugin module that refers back to the main program. When the main program is linked with -optl-export-dynamic the plugin can be loaded up and all symbols resolve correctly. I still had to load copies of the base packages since the plugin .o still refers to symbols not in the main executalbe. (More on that in a moment) And yes indeed, it works with a vanilla ghc-5.04
To like the whole of the base package into the binary, you can either use --whole-archive with libHSbase.a as suggested by Alastair, or link in HSbase.o. Similarly for the haskell98 package.
I got lots of linking errors about duplicate symbols doing using --whole-archive for the standard packages. Perhaps someone who knows a bit more about linking could advise me. It works linking in HSbase.o however. Here's the output of the test program. It loads the .o file of a plugin module that imports things from the main program: [duncan@dunky dlink]$ ./TestDLink GHC dynamic loading test program c_loadObj pluginObj returned 1 c_resolveObjs returned 1 lookup symbol:
TestObj_foo_closure symbol is present
where "TestObj_foo_closure" is a symbol corresponding to my function "foo" defined to be a function imported from the main program. Note here that I am not loading a copy of the base package at runtime, it is resolving against the copy already in the main executable immage. Of course the main program's binary is now much larger ~5mb stripped vs 350k. Note that the program can be striped because the symbls are in a special dynamic export ELF section so do not get stripped. I'm having a problem using just -package flags. I get unresloved symbols. I'm currently doing this: ghc -optl-export-dynamic -ldl -L/usr/lib/ghc-5.04/ -lHSrts -lHSlang \ TestDLink.o -o TestDLink since doing ghc -optl-export-dynamic -ldl -package rst -package lang \ TestDLink.o -o TestDLink gives: /usr/lib/ghc-5.04/libHSrts.a(RtsAPIDeprec.o): In function `rts_mkAddr': RtsAPIDeprec.o(.text+0x14): undefined reference to `Addr_Azh_con_info' /usr/lib/ghc-5.04/libHSrts.a(RtsAPIDeprec.o): In function `rts_getAddr': RtsAPIDeprec.o(.text+0x2d): undefined reference to `Addr_Azh_con_info' RtsAPIDeprec.o(.text+0x35): undefined reference to `Addr_Azh_static_info' collect2: ld returned 1 exit status the flag -ldl is required to aviod link errors about dlopen() and friends. So generally quite sucessful. I should probably come up with some tutorial / documentation on doing plugins with ghc. Duncan