What exactly are 'bindings'?

I want to do some fun stuff with my webcam.

So I figure I probably want OpenCV. Tbh I'm not sure i fully understand what OpenCV is either. I thought it was just a library of code, but you can download binaries, you can even 'install' it via a single command to your linux package manager (can't imagine what that gives you).

Anyway, I want to stay in Rust, and I know that bindings allow me to work in Rust and use C libraries, and I know Python is commonly used with OpenCV, perhaps someone wiser than me who understands the gaps in my knowledge can settle the confusion in this rather rambly post?

To sum up:

  • what are bindings
  • what is OpenCV really
  • what do i need to know before i start to use bindings?

Thanks guise!

1 Like

Bindings are just a kind of library that lets you use a library written in another language from Rust.

1 Like

Well, those binaries are the parts of the library, and the package manager command probably puts them in a place where the system C or C++ compiler can find them automatically.

Not all libraries are distributed purely as source code, especially not in C, where it's pretty standard to pre-compile a library and only hand out the binary and the corresponding header files.


Anyway, "bindings" are generally shims for one library that make it usable from within another language (i.e. not the one it was written in). OpenCV is written in a mixture of C and C++. It means that if you want to use it from Rust (or any other language other than C and C++), the C and C++ types, values, and functions must be wrapped somehow, in order for the two languages to communicate.

This is even more important in scripting languages; for instance, you can't "just" treat a C struct like a Python object; features such as dynamic name resolution and inheritance just don't exist in C. Similary, to stick with Rust, real enums (those with associated data) just don't exist in C either, but in order to get an idiomatic Rust API, you'll pretty much want them.

Pretty hard to tell without knowing what exactly you want to do. In order to use "the bindings" per se, you don't have to know about the C or C++ side of things, that's the whole point. But you'll still need to be able to read the documentation for OpenCV and map the concepts, types, and functions back and forth between C and Rust, in order to be able to do something useful with them.

4 Likes

OpenCV is a computer vision library written in C++.

Bindings are wrapper libraries that use programming language’s FFIforeign function interface feature to make an existing library written in another language usable in more, different programming languages. In the case of OpenCV, a C++-library, the OpenCV bindings for Rust use Rust’s FFI to make OpenCV (more) easily usable from Rust.

You only need to keep in mind that by using a library from a different language through bindings, you’re possibly getting a worse user experience than compared with using a library that’s written in the same language. Some possible shortcomings, as demonstrated in the case of the Rust OpenCV bindings, are:

  • You cannot rely on just on the normal dependency management of cargo. Instead, when using the OpenCV bindings, you also have to install OpenCV, as the README of the bindings explain.
  • The documentation is partially incomplete and mostly copied from the C++ API. This means that many code examples are in C++ and might refer to C++-specific ideas.
  • The library is not a fully ideomatic Rust API.
  • You rely on the maintainers of the bindings to keep them updated if you want to be able to use the most recent version of OpenCV in the future.

So in Rust libraries are usually distributed and also used through their source code, mostly because the only way to really use a library is when the compiler has access to its source code in order to be able to e.g generate code for generic functions. In C, this doesn’t need to be the case, compilation of different C libraries that depend on each other is a lot less coupled. Usually, one distinguishes between special “header files” and implementation in C or C++ code.

The implementation of a library is compiler to an “object file”, i.e. a binary, while an application using the library only needs to have the header files in order to be compiler itself. The header file usually contains just the signatures of public functions or data-types, at least for C, for C++ the situation is a bit more complicated. The depending program is compiled into an object file itself, and in order to actually turn the program into an executable, a linker combines the object files of the program with the object files of the library, pretty much by just appending the two binaries and replacing symbolic references to functions with the right pointers.

Another common occurrence is for the linking to be dynamic. In this case, your executable doesn’t include the library’s object files, but instead contains places that—at runtime—ask the operating system for a dependency, the first time that that dependency is needed. The OS will then look up the dependency, find the relevant object files in case they’re installed, load it into memory, and tell the application where it can find it.

Dynamic linking (or perhaps, even without linking being dynamic, the fact that C compilation has a separate linking step that can work with object files + header files only) is the reason why you are able to find “binaries” (== the object files) for OpenCV that you can install through your linux package manager. Dynamic linking has the advantage that you don’t need to save copies of a library inside of every application that uses it (saving disk space), and it even offers the possibility for multiple applications to share the same copy of a libraries object files in RAM at run-time. Furthermore the split between object files and header files often manigests in there being multiple packages, one “ordinary” version and one ending in -dev. The OpenCV binding for Rust mentions this, too. While you need the -dev version (containing in particular the header files, but which includes/depends on the non--dev version with the object files) for being able to compile a crate that depends on OpenCV, due to dynamic linking you will probably also need to have at least the ordinary (without -dev) version OpenCV package installed in order to be able to run your application. Actually, this last point probably depends on whether your application ends up linking OpenCV dynamically or statically; I’m not 100% sure about the defaults here, since I’ve never used OpenCV binding for Rust myself.

4 Likes

Very interesting everyone thank you!

Yes, I was able to eventually get my rust-opencv helloworld (just prints hello world, with opencv in cargo.toml, nothing else!) to compile after looking at the errors and guessing a little with my ubuntu package manager for similar sounding packages. If anyone from the future wants to know what it took here's the apt command sudo apt install libopencv-dev llvm libclang-dev clang
And note, as per the previous poster, you may actually have to install the 'real deal' OpenCV, which I'm assuming is `libopencv'.

Great, i thought, it's time to get cracking. And then I find myself in documentation hell. And I've never coded anything with OpenCV before.

So i think I'll just take in a few python-opencv tutorials and build a prototype there first and foremost (having also never coded in python either!).

I'm excited about Rust and Cargo's future. Makes everything so simple without sacrificing performance... Amazing.

1 Like

That’s really cool, feel free to a hare some performance comparison between C/C++, Python and Rust :crab::bullettrain_side: