http://www.vex.net/~trebla/haskell/so.xhtml describes how to compile shared library.
About compiling command:
ghc -O2 -dynamic -shared -fPIC -o libEval.so Eval.hs hsbracket.c -lHSrts-ghc7.6.3
it says:
(Could you omit -dynamic to request static libraries of other packages? Not really, they were not generated with -fPIC. In particular it is illegal on x86_64.)
Why is it so? What should one do to compile shared library without libHS* dependencies?
Since Kaiko contacted me privately for an answer, might as well post it here...
Short version
By omitting -dynamic you would be trying to take all the static .a libs and link them into one massive .so file. Those .a libs were themselves built without -fPIC. All code that ends up on a .so file must be built with -fPIC (at least on ELF x86-64). Thus the linking would fail in this case because -fPIC is required but the libs were not built with -fPIC.
Long version
There are a few things that vary between different ways of building
static and dynamic libraries:
Is it built as a .a archive or as a .so (or .dll/.dynlib) object?
Is it built with -fPIC, position independent code or not?
Are external symbols expected to be in the same DSO or an external DSO?
In principle, lots of different combinations of these things make sense
but in practice only a few are used.
On Linux (ELF), there are two standard approaches to building libraries,
fully static and fully dynamic. In the fully static approach the answer
to question 1,2,3 above are: .a archive, no -fPIC, same DSO. In the
fully dynamic approach the answers are: .so lib, -fPIC, external DSO.
Now what you want to do is different. You want all libraries to be built
as .a files, but with -fPIC and external symbols expected to be in the
same DSO. This would then let you link all those libraries together into
one huge shared library. So the crucial difference is the use of -fPIC,
since on ELF (specifically x86_64) code that ends up in a shared lib
must be built with -fPIC.
By contrast, on Windows, GHC can do exactly what you want, to link all
the Haskell libs (including the RTS etc) into one massive shared lib
(.dll). This is because on Windows (unlike ELF), position independent
code does not matter. So on Windows, one is able to take the static
libraries and link them into a big shared library.
In principle this should also be possible on Linux, if all of the
Haskell libraries were built statically but with -fPIC. This is not the
default, and that is the immediate reason why you cannot omit -dynamic
in this case on Linux.
So in principle, one could try rebuilding ghc and the core libraries
from source using the -fPIC flag and then see if it then works to omit
-dynamic and link everything into one huge shared lib.
Yes, compiling with -fPIC helps. Here is how to do that.
ghc-7.8.4/mk/build.mk:
SRC_HC_OPTS = -H64m -O
EXTRA_HC_OPTS = -fPIC
SRC_CC_OPTS = -fPIC -O
GhcStage1HcOpts = -fasm -O0
GhcStage2HcOpts = -fasm -O0
GhcLibHcOpts = -fasm -O2
GhcLibWays = v dyn
DYNAMIC_GHC_PROGRAMS = YES
DYNAMIC_BY_DEFAULT = NO
SplitObjs = NO
HADDOCK_DOCS = NO
BUILD_DOCBOOK_HTML = NO
BUILD_DOCBOOK_PS = NO
BUILD_DOCBOOK_PDF = NO
While you compile ghc:
export EXTRA_CONFIGURE_OPTS="--disable-library-profiling --enable-shared"
To build cabal packages with -fPIC use:
cabal install --enable-shared --ghc-option=-fPIC text
Test file foo.hs (Data.Text is used to see if cabal packages also work):
import Foreign.C as C
import Data.Text as T
import Data.Text.Foreign as T
foreign export ccall len :: CString -> IO CInt
len t = C.peekCString t >>= return . CInt . fromIntegral . T.length . T.pack
main = return ()
Dynamic build:
ghc -dynamic --make foo.hs
Dynamic mixed with static build (not sure if pthread is needed but it illustrates how to add dynamic linking):
ghc -fPIC -shared --make -o libfoo.so \
-optl-Wl,-Bstatic -lHSrts -lCffi \
-lHSbase-4.7.0.2 -lHSinteger-gmp-0.5.1.0 -lHSghc-prim-0.3.1.0 \
-optl-Wl,-Bdynamic -lpthread foo.hs
Related
I'm working on a project that produces a shared object (.so) file. The source code is in both C and Haskell. It needs to be linked with libraries for the GHC Runtime System and for the Hint Haskell module.
Currently, the command to compile the file is:
ghc -Weverything -Werror -fforce-recomp $^ -o $# -dynamic -shared -lHSrts-ghc8.10.5 -lHShint-0.9.0.4-7GR8UnOuwIbHNCqCSHKCK0-ghc8.10.5
There must be a way to automate the finding of the libraries instead of hard-coding the names. I want the Makefile to continue to work with future releases of GHC and Hint. It seems to be that ghc-pkg
should be able to provide this, but I can't find how.
I am trying to build an executable from different libraries using the below statement
g++ -fPIC -O -DUSING_PCH -D_REENTRANT -I"/app1/home1/quickfast/boost_1_61_0/include/boost-1_61" -I"/app1/home1/quickfast/boost_1_61_0/." -I"../../src" -I"../src/Examples" -I"/app1/home1/quickfast/boost_1_61_0/include" -L"." -L"/app1/home1/quickfast/boost_1_61_0/stage/lib" -L/app1/home1/quickfast/quickfast-master/lib -l"QuickFAST" -l"boost_thread-gcc44-mt-1_61" -l"boost_system-gcc44-mt-1_61" -l"boost_filesystem-gcc44-mt-1_61" -l"boost_unit_test_framework-gcc44-mt-1_61" -static -ldl -lpthread -o "../../bin/testSequences"
The above compilation statement includes lot of libraries, which are availabe as dynamic libaries(.so file) as well as static libraries (.a file). For example library boost_system-gcc44-mt-1_61 is present in the system as libboost_system-gcc44-mt-1_61.so as well as libboost_system-gcc44-mt-1_61.a . What I want is that while compilation only dynamic libraries (.so files) are picked up and static libraries are ignored. Can someone please guide.
You are telling it to pick up static libraries by using the -static link option. If you remove it, it'll probably work as you expect.
I've created a Haskell package that makes FFI calls to functions defined in CUDA code. I'd like to compile .cu file to an object (.o) file during package build and force linker to link it in.
So far, I tried to use a technique found this question. I've customized buildHook to:
run nvcc
run default buildHook
create ar library file with nvcc compiled code.
Setup.hs is available here.
This solution has a major disadvantage in restricting this package to static linking. Although cabal produces a shared library, it won't work because it has no way of resolving symbols located in the object file.
Is there a simpler way to link custom code during building?
I do a similar thing. I have a Haskell file which calls CUDA code.
Here's how I compile CUDA libraries and link with Haskell:
$(NVCC) -c -E $(NVCC_OPTS) -o build/file.i file.cu
$(NVCC) -c $(NVCC_OPTS) -o build/file.o file.cu
I then link everything into a C++ Shared Library called LibSO with Haskell options
$(CXX) -shared -Wl,-rpath=\$$$$ORIGIN $(CXX_LINK_LIBS) $(PACKAGE_RPATH) -Lbuild -rdynamic -L/usr/local/lib/ghc-7.6.3 -lHSrts-ghc7.6.3 -o build/LibSO.so build/file.o
where
CXX_LINK_LIBS = -Lbuild -lcudart -lcuda -lpthread -lcupti -lcurand -lnvidia-ml
NVCC_OPTS = --compiler-options -fPIC -maxrregcount=0 --machine 64 --DCUDA
I then take my Haskell files and compile them into o and hi files. (I compile twice because of TemplateHaskell)
ghc -v0 -Wall -rtsopts -threaded -stubdir build -ibuild/ -no-hs-main -o build/iop.o -ohi build/iop.hi -c haskell/iop.lhs
ghc -v0 -Wall -rtsopts -threaded -stubdir build -ibuild/ -no-hs-main -fPIC -dynamic -osuf dyn_o -hisuf dyn_hi -o build/iop.dyn_o -ohi build/iop.dyn_hi -c haskell/iop.lhs
So now we have haskell dynamic objects and a C++ shared library.
In the end, I link a main haskell file with everything:
ghc -optl "-Wl,-rpath=\$$ORIGIN" $(CXX_LINK_LIBS) -Lbuild -rtsopts -threaded -lstdc++ -lLibSO -o build/Main build/iop.dyn_o
Does this sort of help?
I have a project where I have one static library libhelper.a and another with my actual shared object library, libtestlib.so. My goal is to link libhelper.a into libtestlib.so. Is that possible on Linux/BSD? When I tried and created a test program I got the following errors:
./prog1:/usr/local/lib/libtestlib.so.1.0: undefined symbol ''
My guess is that this is occurring because libhelper.a was not compiled with -fPIC while libtestlib.so was. What is the proper way to build programs that use shared libraries that also have dependancies on static libraries?
Thanks!
My goal is to link libhelper.a into libtestlib.so. Is that possible on Linux?
Sure. This should do:
gcc -shared -fPIC -o libtestlib.so $(OBJS) \
-Wl,--whole-archive -lhelper -Wl,--no-whole-archive
libhelper.a was not compiled with -fPIC
It's best to rebuild libhelper.a with -fPIC. If that's not possible, above command will still work on Linux/ix86, but not on e.g. Linux/x86_64.
What is the proper way to build programs that use shared libraries that also have dependancies on static libraries?
If you include libhelper.a into libtestlib.so as above, then simple:
gcc main.c -ltestlib
is all you need. If you insist on linking with libhelper.a, then you must tell the end-user that he must link with e.g.
gcc main.c -ltestlib -lhelper
There is no way to specify that libtestlib.so depends on libhelper.a.
I am working in Linux, Eclipse CDT, g++, with Boost library. Having existing program which uses Boost thread, I try to link it statically instead of dynamically. /usr/local/lib directory contains the following files:
libbost_thread.a
libbost_thread.so
libbost_thread.1.41.0
Dynamic linking works:
g++ -o"MyProgram" ./main.o -lboost_thread
Static linking:
g++ -static -o"MyProgram" ./main.o -lboost_thread
produces huge number of messages like:
undefined reference to `pthread_mutex_init'
How can I link statically to the Boost library?
For pthread_mutex_init, you want to compile/link with -pthread option:
g++ -static -pthread -o"MyProgram" ./main.o -lboost_thread
The problem is that functions like pthread_mutex_init are in a separate library. Dynamic libraries can include the metadata for the fact that it needs the separate library (so libboost_thread.so includes the fact that it needs libpthread).
But static libraries don't have that information. So you need to provide the reference to any necessary libraries when you link statically.
As for using -pthread instead of -lpthread, it's slightly preferable because it not only links the necessary library, but provides any other options that should be used (such a -D_REENTRANT to the compiler).
Try adding -lpthread to your invocation.
On Linux a dynamic library may automatically depend on other dynamic libraries so that when you link it, you get the other libraries for free. When linking statically, there is no such system and you have to specify the other libraries manually.