# C stubs for a binary library (on windows)

**URL:** <https://discuss.ocaml.org/t/c-stubs-for-a-binary-library-on-windows/5917>\
**Category:** Ecosystem\
**Tags:** build\
**Created:** [June 5, 2020, 8:15am UTC](https://discuss.ocaml.org/t/c-stubs-for-a-binary-library-on-windows/5917 "2020-06-05T08:15:50Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![aubanel](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/aubanel/32/2237_2.png) [@aubanel](https://discuss.ocaml.org/u/aubanel)\
**Post date:** [June 5, 2020, 8:15am UTC](https://discuss.ocaml.org/t/c-stubs-for-a-binary-library-on-windows/5917/1 "2020-06-05T08:15:50Z")

</div>

Hi there!  
I am writing an ocaml wrapper for an existing windows library. I have a .h and a .lib. I don’t know which compiler has been used to produce the .lib, most likely cl.  
I’m using the [Ocaml for windows](https://fdopen.github.io/opam-repository-mingw/installation/) environment, which comes with recent versions of ocaml and opam, as well as a pre-configured C.compiler:

> ```
> $ $CC --version
> x86_64-w64-mingw32-gcc (GCC) 9.2.0
> Copyright (C) 2019 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions. There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
> 
> ```

I can build and link my stubs and library correctly. However, at execution time, I get a segfault. I did a minimum example with just a single C file and my library, compiled with the provided $CC: still a segfault.

I then downloaded another C compiler ([TDM GCC](https://jmeubank.github.io/tdm-gcc/)). I’ve compiled my minimal C example: it works !  
So I’ve tried to use this C compiler for ocamlopt, by putting the following dune file at the root of my project:

> ```
> (env
> (_ 
> (ocamlopt_flags (-cc gcc))
> )
> )
> 
> ```

Hélas, when I build, it does not find flexdll symbols:

> ```
> $ dune build tests/api/main.exe
> ocamlopt tests/api/main.exe (exit 2)
> (cd _build/default && C:\OCaml64\home\XXXXX\.opam\4.10.0+mingw64c\bin\ocamlopt.opt.exe -w @1..3@5..28@30..39@43@46..47@49..57@61..62-40 -strict-sequence -strict-formats -short-paths -keep-locs -cc gcc -o tests/api/main.exe src/api/api.cmxa -I src/api -I src/api/lib tests/api/.main.eobjs/native/dune __exe__ Main.cmx)
> C:/TDM-GCC-64/bin/../lib/gcc/x86_64-w64-mingw32/9.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: C:/OCaml64/home/amonnier/.opam/4.10.0+mingw64c/lib/ocaml\libasmrun.a(win32_n.o): in function `caml_dlopen':
> /home/appveyor/.opam/ocaml-variants.4.10.0+mingw64c/.opam-switch/build/ocaml-variants.4.10.0+mingw64/runtime/win32.c:232: undefined reference to `flexdll_wdlopen'
> 
> ```

[… similarly missing symbols: flexdll\_wdlopen, flexdll\_dump\_exports, flexdll\_dlopen, flexdll\_dlclose, flexdll\_dlsym, flexdll\_dlerror]

> ```
> /lib/libmingw32.a(lib64_libmingw32_a-crt0_c.o): in function `main':
> C:/crossdev/src/mingw-w64-v7-git20191109/mingw-w64-crt/crt/crt0_c.c:18: undefined reference to `WinMain'
> collect2.exe: error: ld returned 1 exit status
> File "caml_startup", line 1:
> Error: Error during linking
> 
> ```

I’m running short of ideas: does it make sense to try to use this other compiler ? are there extra flags needed to tell it where to find these flexdll and WinMain symbols ? And why the hell do I get a segfault with $CC and not with gcc ?

Any clue will be deeply appreciated,

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [June 5, 2020, 8:31am UTC](https://discuss.ocaml.org/t/c-stubs-for-a-binary-library-on-windows/5917/2 "2020-06-05T08:31:44Z")

</div>

It is hard to say without more information, but I don’t think that using `-cc` will work: especially on Windows, the linking step is delicate and it uses `flexlink`, it won’t work with a plain C compiler. If it were me, I would try to understand why/where it segfaults first.

Best wishes,  
Nicolás

---

<div class="post-metadata">

**Author:** ![nojb](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/nojb/32/519_2.png) [@nojb](https://discuss.ocaml.org/u/nojb)\
**Post date:** [June 5, 2020, 8:35am UTC](https://discuss.ocaml.org/t/c-stubs-for-a-binary-library-on-windows/5917/3 "2020-06-05T08:35:39Z")

</div>

By the way, are you sure you can use a static library compiled by `msvc` with `mingw`?

Best wishes,  
Nicolás

---

<div class="post-metadata">

**Author:** ![aubanel](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/aubanel/32/2237_2.png) [@aubanel](https://discuss.ocaml.org/u/aubanel)\
**Post date:** [June 8, 2020, 2:11am UTC](https://discuss.ocaml.org/t/c-stubs-for-a-binary-library-on-windows/5917/4 "2020-06-08T02:11:18Z")

</div>

Well, it works with [TDM GCC](https://jmeubank.github.io/tdm-gcc/about/), which as far as I understand is a [flavor of mingw](https://github.com/jmeubank/tdm-distrib/blob/master/tdm64/core/README-gcc-tdm64.md). I could not spot anything related to static library linking. I could try other compilers though, maybe msys2 ?

Trying to understand the detail of the segfault is a good idea. There is no gdb provided with the mingw coming with the ocaml install. I tried with the one coming with TDM GCC, it works but does not give very valuable information:

> ```
> (gdb) break main
> Breakpoint 1 at 0x40155d: file api_test.c, line 6.
> (gdb) run
> Starting program: C:\Users\XXXX\repos\XXXX\src\api\bin\a1.exe
> [New Thread 55804.0xd08c]
> 
> Thread 1 hit Breakpoint 1, main () at api_test.c:6
> 6 int ret = 0;
> (gdb) step
> 7 ret = Process_InitParams("A", "B", 15.5);
> (gdb) step
> 0x00000000000086d8 in ?? ()
> (gdb)
> 
> ```

Without surprise, the segfault is on the call to the function implemented in the static lib.  
If I look in the executable, it seems to be properly defined:

> ```
> $ nm a.exe | grep Process_InitParams
> 00000000004083a8 D __imp_Process_InitParams
> 00000000004015a0 T Process_InitParams
> 
> ```

If I run gdb on the same exe but compiled with TDM GCC, I have the expected behavior (in that case an error as the parameters passed to the `Process_InitParams` function are dummy ones) :

> ```
> (gdb) break main
> Breakpoint 1 at 0x40156d: file api_test.c, line 6.
> (gdb) run
> Starting program: C:\Users\XXXX\repos\XXXX\src\api\bin\a2.exe
> [New Thread 59032.0xb368]
> [New Thread 59032.0xb718]
> [New Thread 59032.0x3198]
> [New Thread 59032.0xfbfc]
> 
> Thread 1 hit Breakpoint 1, main () at api_test.c:6
> 6 int ret = 0;
> (gdb) step
> 7 ret = Process_InitParams("A", "B", 15.5);
> (gdb) step
> [New Thread 59032.0xc6ac]
> [New Thread 59032.0xee30]
> [New Thread 59032.0xe9dc]
> C:\ANSYS/configurations.cfg
> Cnet notification level 4 : Process::init --> Configuration B doesn't exist ! Invalid configuration: B
> 8 printf("%d\n", ret);
> (gdb) step
> 9 return ret;
> (gdb) step
> 10 }
> 
> ```

My main C file is really the most stupid thing one could write:

> ```
> #include <XXXX.h>
> #include <stdio.h>
> int main(void)
> {
> int ret = 0;
> ret = Process_InitParams("A", "B", 15.5);
> printf("%d\n", ret);
> return ret;
> }
> 
> ```

I build my executables with the following commands:  
` $CC api_test.c -Iinclude -Llib -lXXXX -g`  
to use the mingw provided with ocaml and  
`gcc api_test.c -Iinclude -Llib -lXXXX -g`  
for the one provided by TDM GCC.  
They are using exactly the same gcc version.

> ```
> $ $CC --version
> x86_64-w64-mingw32-gcc (GCC) 9.2.0
> 
> ```

and

> ```
> $ gcc --version
> gcc.exe (tdm64-1) 9.2.0
> 
> ```

---

<div class="post-metadata">

**Author:** ![aubanel](https://sea2.discourse-cdn.com/flex020/user_avatar/discuss.ocaml.org/aubanel/32/2237_2.png) [@aubanel](https://discuss.ocaml.org/u/aubanel)\
**Post date:** [June 10, 2020, 2:51am UTC](https://discuss.ocaml.org/t/c-stubs-for-a-binary-library-on-windows/5917/5 "2020-06-10T02:51:43Z")

</div>

OK, after some research by a colleague, it appears it’s a known issue of mingw not being able to link with msvc-produced libraries in [some cases](https://sourceforge.net/p/mingw-w64/wiki2/Answer%2064%20bit%20MSVC-generated%20x64%20.lib/).

For future reference, the solution has been to use opam to create a 4.10.0+msvc64c switch (opam create switch 4.10.0+msvc64c) in order to install the ocaml compiler compiled with MSVC. Then use [ocaml-env](https://fdopen.github.io/opam-repository-mingw/ocaml-env/):

```auto
eval $(ocaml-env cygwin --ms=vs2017)

```

in the cygwin environment to setup everything before the build.  
Works like a charm. Thanks @oandrieu !
