Andrea Rossato wrote:
Hello,
this is a followup of this:
http://article.gmane.org/gmane.comp.lang.haskell.cafe/48644
which didn't have replays. In order to make the review a bit easier I
prepared a minimal test case which, I believe, could prove there's a
bug in the ghci linker. I'm not submitting a bug report because I'm
not familiar with these problems and, in order not to waste other
people's time, I'd rather have some preliminary review.
All the code examples can be found here:
http://gorgias.mine.nu/ffi-test/
Here a tarball of everything:
http://gorgias.mine.nu/ffi-test.tar.gz
Take a simple C library like this:
#include <stdio.h>
extern char my_var[];
void my_fun()
{
fprintf (stderr, "%s\n", my_var);
}
Since my_var is defined as external, the dynamic library compiled
and linked with:
gcc -Wall -fPIC -c -o mylib.o mylib.c
gcc -shared -Wl,-soname,libmylib.so.1 -o libmylib.so.1.0 mylib.o
would have my_var as undefined.
If I write some Haskell bindings (Test.hsc) like this:
module Test where
import Foreign.C
import Foreign
#include <mylib.h>
foreign import ccall unsafe "my_fun" my_cfun :: IO ()
my_fun :: IO ()
my_fun = my_cfun
I'll need to include a stub.c file to initialize my_var:
char my_var[] = "Hello World!!";
And now come my problems:
1. First I have a Cabal problem. If I set:
extra-libraries: mylib
this will be used also when compiling dist/build/Test_hsc_make, and,
since libmylib.so.1.0 has an undefined reference to my_var, which will
be initialized only later, by stub.c, the compilation of the bindings
will fail with:
Configuring mylib-0.1...
Preprocessing library mylib-0.1...
/tmp/ffi-test/libmylib.so: undefined reference to `my_var'
collect2: ld returned 1 exit status
linking dist/build/Test_hsc_make.o failed
command was: /usr/bin/gcc -L/tmp/ffi-test -lmylib
-L/usr/lib/ghc-6.10.1/base-4.0.0.0 [...]
I can find a work-around by not setting cabal extra-libraries and
instead setting
ghc-options: -lmylib
But when compiling a test file:
import Test
main = my_fun
I'll need to pass -lmylib to ghc --make.
2. I also have ghci problem. If I try with:
ghci test_lib.hs
GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Ok, modules loaded: Main.
Prelude Main> main
Loading package mylib-0.1 ... linking ... <interactive>:
/home/andrea/.cabal/lib/mylib-0.1/ghc-6.10.1/HSmylib-0.1.o: unknown symbol `my_fun'
ghc: unable to load package `mylib-0.1'
Now, I have to remember to pass -lmylib:
ghci -lmylib test_lib.hs
GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help
Loading object (dynamic) mylib ... failed.
<command line>: user specified .o/.so/.DLL could not be loaded
(/tmp/ffi-test/libmylib.so: undefined symbol: my_var)
Whilst trying to load: (dynamic) mylib
Additional directories searched: (none)
Now, the my_var symbol is included in:
/home/andrea/.cabal/lib/mylib-0.1/ghc-6.10.1/HSmylib-0.1.o
and indeed:
nm --print-arma /home/andrea/.cabal/lib/mylib-0.1/ghc-6.10.1/HSmylib-0.1.o
| grep my_var
0000001c D my_var
So I desperately try:
ghci /home/andrea/.cabal/lib/mylib-0.1/ghc-6.10.1/HSmylib-0.1.o -lmylib /tmp/ffi-test/bindings/test_lib.hs
GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help
Loading object (static)
/home/andrea/.cabal/lib/mylib-0.1/ghc-6.10.1/HSmylib-0.1.o ... done
Loading object (dynamic) mylib ... failed.
<command line>: user specified .o/.so/.DLL could not be loaded
(/tmp/ffi-test/libmylib.so: undefined symbol: my_var)
Whilst trying to load: (dynamic) mylib
Additional directories searched: (none)
Is this a bug? An intended behaviour? Is there a way out? What am I
missing?
It's not a bug - or rather, it's a consequence of the fact that GHC does
its own runtime linking. The dynamic library libmylib.so is being linked
by the system linker, which has its own symbol table and knows nothing
about GHC's linker and its symbol table. The file HSmylib-0.1.o is loaded
by GHC's linker, so the my_var symbol is in GHC's symbol table, and hence
can't be found by the system linker when loading libmylib.so.
Some good news is that we should be able to make this work when we start
using shared libraries, because HSmylib will be a shared library and it
will be linked by the system linker (what I'm not sure about is how you
load mutually recursive shared objects at runtime, but presumably there's a
way to do that).
Perhaps you could work around the Cabal/hsc2hs problem by making a dummy
library containing my_var, and passing it to Cabal using
--hsc2hs-option=-ldummy.
Cheers,
Simon
Obviously the problem goes away if I link mylib.o with stub.o into
libmylib.so.1.0.
Thanks for your help.
Andrea
ps: here you can find a small shell script to automate the proposed
test (included in the tarball linked above):
http://gorgias.mine.nu/ffi-test/test_dynamic.sh
_______________________________________________
Glasgow-haskell-users mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
_______________________________________________
Glasgow-haskell-users mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users