yallop / ocaml-ctypes

Library for binding to C libraries using pure OCaml
MIT License
369 stars 95 forks source link

Binding static library on linux #580

Closed Alex-Shand closed 5 years ago

Alex-Shand commented 5 years ago

Hi,

I'm trying to write bindings for the dyncall static library (www.dyncall.org).

The build commands I've tried: ocamlfind ocamlopt <x> -linkpkg -package ctypes.foreign test.ml -o dyncall_test where is one of:

-cclib "--force-link /usr/local/lib/libdyncall_s.a"
-cclib /usr/local/lib/libdyncall_s.a
/usr/local/lib/libdyncall_s.a
-cclib "-Wl,--whole-archive" -cclib /usr/local/lib/libdyncall_s.a -cclib "-Wl,--no-whole-archive"
-cclib "-Wl,--no-as-needed" -cclib /usr/local/lib/libdyncall_s.a

And test.ml contains:

open Ctypes
open Foreign

type dcCallVM = unit ptr
let dcCallVM : dcCallVM typ = ptr void

let dcNewCallVM = foreign "dcNewCallVM" (int @-> returning dcCallVM)
let vm = dcNewCallVM 4096

In all cases the compilation completes without errors but running ./dyncall_test produces: 'Fatal error: exception Dl.DL_error("./dyncall_test: undefined symbol: dcNewCallVM")'

Other information: ocamlopt -v:

The OCaml native-code compiler, version 4.07.0
Standard library directory: /home/alex/.opam/4.07.0/lib/ocaml

gcc -v:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/7/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 7.3.0-27ubuntu1~18.04' --with-bugurl=file:///usr/share/doc/gcc-7/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++ --prefix=/usr --with-gcc-major-version-only --program-suffix=-7 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-libmpx --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04)

Any advice would be appreciated.

Thanks, Alex

yallop commented 5 years ago

I recommend using the static stub generation (Cstubs) rather than dynamic linking (Foreign), since it makes linking much easier, among other advantages. However, sticking with your current approach, the following works for me:

$ wget -q -O - http://www.dyncall.org/r1.0/dyncall-1.0-arch_linux-2011.08.19-x64.tar.gz | tar xz 
$ cat test.ml
open Ctypes
open Foreign

type dcCallVM = unit ptr
let dcCallVM : dcCallVM typ = ptr void

let dcNewCallVM = foreign "dcNewCallVM" (int @-> returning dcCallVM)
let vm = dcNewCallVM 4096
let () = Format.printf "dcNewCallVM 4096 => %a@." Ctypes.(format (ptr void)) vm
$ ocamlfind opt -cclib '-Wl,-E -Ldyncall-1.0-release/lib/ -Wl,-whole-archive -l:libdyncall_s.a -Wl,-no-whole-archive' -linkpkg -package ctypes.foreign test.ml -o dyncall_test
$ ./dyncall_test 
dcNewCallVM 4096 => 0x55787a6ab2b0
Alex-Shand commented 5 years ago

Thank you, that works perfectly.