How to link C lib statically with OCaml app
Here is a simple example with libmagic.
Let's write a simple application. Here is a file test.ml
:
let magic_cookie = Magic.make []
let () = print_endline (Magic.file magic_cookie Sys.argv.(1))
And if we build this app in usual way, we got a working binary on this system:
systemA:~$ ocamlfind ocamlopt test.ml -o test -package magic -linkpkg
systemA:~$ ./test test
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
But on other system we can got an error:
systemB:~$ ./test test
./test: error while loading shared libraries: libmagic.so.1: cannot open shared object file: No such file or directory
To link libmagic statically, we have to disable autolinking with -noautolink
and provide necessary flags to gcc manually with -cclib '-Wl,-Bstatic -lmagic_stubs -lmagic -Wl,-Bdynamic -lz'
. Read OCaml manual about these options.
systemA:~$ ocamlfind ocamlopt test.ml -o test -package magic -linkpkg -noautolink -cclib '-Wl,-Bstatic -lmagic_stubs -lmagic -Wl,-Bdynamic -lz'
systemB:~$ ./test test
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped
You can see what compiler is really doing by adding -verbose
option:
systemA:~$ ocamlfind ocamlopt test.ml -o test -package magic -linkpkg -noautolink -cclib '-Wl,-Bstatic -lmagic_stubs -lmagic -Wl,-Bdynamic -lz' -verbose
Effective set of compiler predicates: pkg_magic,native
+ ocamlopt -o test -verbose -noautolink -I /usr/lib/ocaml/magic /usr/lib/ocaml/magic/magic.cmxa test.ml -cclib -Wl,-Bstatic -lmagic_stubs -lmagic -Wl,-Bdynamic -lz
+ as -o 'test.o' '/tmp/camlasm5b7b13.s'
+ as -o '/tmp/camlstartupe71be7.o' '/tmp/camlstartupaa15d5.s'
+ gcc -o 'test' '-L/usr/lib/ocaml/magic' '-L/usr/lib/ocaml' '/tmp/camlstartupe71be7.o' '/usr/lib/ocaml/std_exit.o' 'test.o' '/usr/lib/ocaml/magic/magic.a' '/usr/lib/ocaml/stdlib.a' '-Wl,-Bstatic' '-lmagic_stubs' '-lmagic' '-Wl,-Bdynamic' '-lz' '/usr/lib/ocaml/libasmrun.a' -lm -ldl
Yet another way — no -noautolink
but -static
and -dynamic
instead of -Wl,-Bstatic
and -Wl,-Bdynamic
. But this way it links libc and other stuff. For example I got 959K binary instead of 284K. I don't know yet why.
systemA:~$ $ ocamlfind ocamlopt test.ml -o test -package magic -linkpkg -cclib '-static -lmagic_stubs -lmagic -dynamic -lz' -verbose
Effective set of compiler predicates: pkg_magic,autolink,native
+ ocamlopt -o test -verbose -I /usr/lib/ocaml/magic /usr/lib/ocaml/magic/magic.cmxa test.ml -cclib -static -lmagic_stubs -lmagic -dynamic -lz
+ as -o 'test.o' '/tmp/camlasm29ca7e.s'
+ as -o '/tmp/camlstartupf55661.o' '/tmp/camlstartupd90aac.s'
+ gcc -o 'test' '-L/usr/lib/ocaml/magic' '-L/usr/lib/ocaml' '/tmp/camlstartupf55661.o' '/usr/lib/ocaml/std_exit.o' 'test.o' '/usr/lib/ocaml/magic/magic.a' '/usr/lib/ocaml/stdlib.a' '-lmagic_stubs' '-lmagic' '-static' '-lmagic_stubs' '-lmagic' '-dynamic' '-lz' '/usr/lib/ocaml/libasmrun.a' -lm -ldl
/usr/lib/ocaml/libasmrun.a(unix.o): In function `caml_dlopen':
(.text+0x232): warning: Using 'dlopen' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
Does anybody know a better way to link C lib statically with OCaml? Let me know.