I have a project that is split up into two parts:
- Executable
- Library
The executable part has client specific code, but the library has generic functionality that doesn't change across the different client projects.
Right now I have 5 projects that when compiled creates a 25 MB executable each, since GHC compiles the executable and all dependencies statically into one file.
What I would like to do instead is to compile my library with all it's dependencies statically into one file, that the executables then can load dynamically. So that all the .a files for the external dependencies gets compiled into one .so file.
A quote that explains what I want to do (Generating single .so from multiple C++ and C object files):
The easiest way is to combine them into a single .so file by either combining all object files, or building two static .a libraries and then linking them into a single shared library.
Is this even possible with GHC?
I have been looking at different solutions, dynamically linking all libraries, using split-objs, but I can't seem to find a solution for what I would like to do.
EDIT: Add information about my setup and what I have tried so far.
My setup
I'm currently using cabal-install version 1.18.1.2 and 1.18.1.1 of the library.
I have my project setup in a sandbox:
$ cabal sandbox init
$ cabal install --dependencies-only
$ cabal configure
This installs all the dependencies in .cabal-sandbox in my project directory. Inside each dependency folder there is a compiled .a file, see acid-state-0.12.1 as an example:
▾.cabal-sandbox/
▾lib/
▾x86_64-linux-ghc-7.6.3/
▸acid-state-0.12.1/
▸ Data/
FileIO.hi
libHSacid-state-0.12.1.a
Paths_acid_state.hi
▸aeson-0.6.2.1/
▸base-unicode-symbols-0.2.2.4/
▸base64-bytestring-1.0.0.1/
▸blaze-builder-0.3.1.1/
▸blaze-html-0.6.1.1/
▸blaze-markup-0.5.1.5/
▸blaze-textual-0.2.0.8/
▸cereal-0.4.0.0/
▸clay-0.8/
▸clock-0.3/
▸dlist-0.5/
▸email-validate-1.0.0/
▸entropy-0.2.2.4/
▸extensible-exceptions-0.1.1.4/
▸gd-3000.7.3/
▸happstack-lite-7.3.1/
▸happstack-server-7.3.1/
▸hslogger-1.2.3/
▸MissingH-1.2.0.2/
▸monad-control-0.3.2.2/
▸postgresql-libpq-0.8.2.4/
▸postgresql-simple-0.3.8.0/
▸safecopy-0.8.2/
▸scrypt-0.3.6/
▸sendfile-0.7.9/
▸system-filepath-0.4.8/
▸threads-0.5.0.2/
▸time-compat-0.1.0.3/
▸transformers-base-0.4.1/
▸utf8-string-0.3.7/
Like I said in the inro, my project is divided into two parts as shown here in my cabal file (Note that some information is removed to keep the example s shorter):
name: myserver
version: 0.1.0.0
build-type: Simple
cabal-version: >=1.8
library
hs-source-dirs: lib
ghc-options: -Wall -fno-warn-orphans -fno-warn-unused-do-bind -threaded
exposed-modules:
Crypto.SimpleScrypt,
Util.Response,
Html.Components,
Storage.Memory,
Storage.Disk
build-depends:
base >=4.6 && <4.7,
bytestring >=0.10 && <0.11,
MissingH >=1.2 && <1.3,
happstack-lite >=7.3 && <7.4,
clay >=0.8 && <0.9,
text >=0.11 && <0.12,
blaze-markup >=0.5 && <0.6,
blaze-html >=0.6 && <0.7,
postgresql-simple >=0.3 && <0.4,
mtl >=2.1 && <2.2,
acid-state >=0.12 && <0.13,
safecopy >=0.8 && <0.9,
containers >=0.5 && <0.6,
scrypt >=0.3 && <0.4,
transformers >=0.3 && <0.4,
happstack-server >=7.3 && <7.4,
time >=1.4 && <1.5,
filepath >=1.3 && <1.4,
directory >=1.2 && <1.3,
gd >=3000.7 && <3000.8,
aeson >=0.6 && <0.7,
email-validate >=1.0 && <1.1,
clock >=0.3 && <0.4,
random >=1.0 && <1.1
executable myserver
hs-source-dirs: app
main-is: App.hs
ghc-options: -Wall -fno-warn-orphans -fno-warn-unused-do-bind -threaded
build-depends:
base >=4.6 && <4.7,
bytestring >=0.10 && <0.11,
MissingH >=1.2 && <1.3,
happstack-lite >=7.3 && <7.4,
clay >=0.8 && <0.9,
text >=0.11 && <0.12,
blaze-markup >=0.5 && <0.6,
blaze-html >=0.6 && <0.7,
postgresql-simple >=0.3 && <0.4,
mtl >=2.1 && <2.2,
acid-state >=0.12 && <0.13,
safecopy >=0.8 && <0.9,
containers >=0.5 && <0.6,
scrypt >=0.3 && <0.4,
transformers >=0.3 && <0.4,
happstack-server >=7.3 && <7.4,
time >=1.4 && <1.5,
filepath >=1.3 && <1.4,
directory >=1.2 && <1.3,
gd >=3000.7 && <3000.8,
aeson >=0.6 && <0.7,
email-validate >=1.0 && <1.1,
clock >=0.3 && <0.4,
random >=1.0 && <1.1,
myserver
What I have tried so far
I have tried adding -shared -fPIC
to the ghc-options
for the library
and -dynamic
for the executable. But that produced this error:
Linking a.out ...
/usr/bin/ld: /home/rzetterberg/development/haskell/myserver/.cabal-sandbox/lib/x86_64-linux-ghc-7.6.3/scrypt-0.3.6/libHSscrypt-0.3.6.a(Scrypt.o): relocation R_X86_64_32S against `stg_CAF_BLACKHOLE_info' can not be used when making a shared object; recompile with -fPIC
/home/rzetterberg/development/haskell/myserver/.cabal-sandbox/lib/x86_64-linux-ghc-7.6.3/scrypt-0.3.6/libHSscrypt-0.3.6.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
The problem is that really I don't know where to start, that's why I'm asking for help.