C-Binding HowTo?


#1

Hello,
I am trying to call a function from a library and I need a step-by-step instruction…
I am facing the following error:
in lib/libsnark/r1cs.cr:3: ‘ldflags’ link argument must be a String
@[Link(ldflags: “lib/libsnarc.a”)]

I created a library that I put in lib/libsnarc.a (lib is a sub folder of the main folder having the Crystal code), but I don’t know how to tell Crystal where is my library. I tried with this @[Link(ldflags: “lib/libsnarc.a”)] that I saw on the web (https://medium.com/@cfsamson/how-to-bind-your-own-c-library-to-crystal-fec9686598b7) but it does not work.
This is how I am trying to import my library:
@[Link(ldflags: “lib/libsnarc.a”)]
lib LibSnarc
# test…
fun test(name : UInt8*)
end


#2

You copy and pasted the code directly from the page. The page shows the double quotes more nicely, with unicode characters that are not the usual double quotes. That’s why you get the error.

Try copy and pasting this:

@[Link(ldflags: "lib/libsnarc.a')]

Also, to have that work all the time, regardless of where you program is compiled, better use "#{__DIR__}/lib/libsnarc.a" (or similar).


#3

Well spotted! Thank you this is working now, so I can get to the next error :slight_smile:

/usr/bin/ld: /home/gui/isekai/lib/libsnark/…/libsnarc.a(cwrapper.cpp.o): undefined reference to symbol ‘_ZNSt13basic_filebufIcSt11char_traitsIcEE5closeEv@@GLIBCXX_3.4
//usr/lib/x86_64-linux-gnu/libstdc++.so.6: error adding symbols: DSO missing from command line

In fact my library is C++ but I tried to expose C interface like this:
#ifndef CWRAPPER_H
#define CWRAPPER_H

#ifdef __cplusplus
extern "C" {
#endif

struct wrap;
typedef struct wrap wrap_t;


void test(char *fname);

void test2(wrap_t *m, int val);

#ifdef __cplusplus
}
#endif

#endif /* __CWRAPPER_H__ */

The cpp is simply including <stdlid.h> and fstream. Do you know if what I am trying to do can work?


#4

I made it work by adding -lstdc++:
@[Link(ldflags: "#{__DIR__}/../libsnarc.a -lstdc++")]
It’s great to be able to use C++ library with crystal, using a simple C wrapper!


#5

Hello,

Now my wrapper is now doing something useful and is not a hello world test. My C library is using other C++ libraries and when I compile the Crystal code I have ‘undefined reference’ to the other C++ libraries. Is there a way to link with them somehow?


#6

You might be missing to mention the compiled c++ library file in the @[Link(ldflags: ...)].


#7

Indeed, but I am new to linux so I did not know how to do it. In case of it can help somebody, I just needed to add the libraries names to the ldflags property. We can also use the -l shorcut (which add lib and .a to the name you indicate), and the -L to specify path:
@[Link(ldflags: “#{DIR}/…/libsnarc.a -lstdc++ -L#{DIR}/…/ -lzm -lprocps”)]
will link wih libzm.a in the same directory as my libsnarc.a, and libprocps.so, a shared library in the system.