ghci linker and circular dependencies: bug or feature?

Andrea Rossato mailing_list at istitutocolli.org
Tue Dec 9 11:26:43 EST 2008


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?

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


More information about the Glasgow-haskell-users mailing list