Understanding dynamic loaded libraries and the DynamicLibrary class better


#1

Hi, It’s the electrical engineer again, asking complicated questions :grin:

Today: Understanding how to handle C++ libraries loaded at runtime.

First: What’s my motivation behind this question: I’d like to check if a certain dynamic C++ library (to be specific: uhd - a library to access some software defined radio hardware) is installed on a system and use it in that case. However, I don’t want to redistribute the whole library with my project, as this functionality should be optional. As far as I know, this library is not intended to be used this way. It offers an alternative pure C interface (which seem to make things a lot easier) for most functionality, but sadly not for all features I need.

Now I did some research on that topic and found this document, explaining how dynamic loading through dlopen works and why there is the need of factory functions that are declared as extern "C". I think I understood most parts of it and I believe most of it applies to other platforms too.

Now to gain some better understanding of the possibilities and restrictions I tried creating a little test-case with an Xcode project that builds a small dylib and another JUCE-based command-line project that tries loading und using my libraries functions.

So far I was only successful at using plain C functions in this setup. Problems arise when trying to invoke any of the member-functions on class instances generated by those factory functions, ranging from linker errors in case of simply including the headers for my library in my loading project (I understand them) to runtime errors when declaring a base class with virtual functions, using this header in both projects and creating a derived class in my library. So there are a bunch of questions for me at the moment:

  • Can anyone provide a good working example of how to create a simple class that can be used with dynamic loading or point me in the right direction of how this class has to be designed?
  • Is a usual C++ library like the one mentioned above even usable in this case?

#2

A sane library wouldn’t expect itself to be used just via a C++ interface through a dynamic library. C++ is very tricky to get right with dynamic libraries, which is why most libraries that are intended for generic use will have a full C interface. (They might provide a C++ convenience layer on top of that. Sometimes this is done even if the library itself is written with C++…)


#3

Okay, so to sum it up:
As the library I plan to use has a C interface (although the library is written in pure C++) for the most important features I should use the C Interface. Using this interface would make no trouble, trying to use the C++ interface would be tricky or even impossible to get right as the library probably was never designed with this kind of usage in mind. Did I get you right?

Now even if my original plan doesn’t work I would still like to understand better what exactly a C++ library has to look like to be used this way. Because if I didn’t understand everything wrong, every audio plugin should be such a library in the end, am I right? I didn’t spot the relevant parts of the code that answer my question when stepping through the JUCE sourcecode. So I’d still be happy to see a (simplified) working example on how such library interfaces have to be written so that it works :slightly_smiling_face:


#4

The popular audio plugin formats are indeed dynamic libraries with a C interface. VST2 is probably the easiest to understand in terms of interfacing with C++.


#5

That’s quite interesting, I always thought they all had some kind of C++ interface - JUCE never made it necessary for me to take a closer look :wink: But after struggling with the topic myself it makes sense.

However I tried to find the spot in the JUCE codebase where I see how a VST or some other plugin is loaded by JUCE, however, I’ve trouble finding it. Could you anyone me a pointer?
Information on VST2 as you mentioned are somewhat hard to find as it’s a deprecated format.


#6

JUCE\modules\juce_audio_processors\format_types\juce_VSTPluginFormat.cpp

The file is…Long. :wink: So it isn’t so easy to see how it all exactly works.

Here’s a much more minimal (and incomplete) implementation I did without JUCE :

https://bitbucket.org/xenakios/nanohost/src/1c03f29c62facb248d217577ff4184a7a47d4190/audiomodule.cpp?at=master&fileviewer=file-view-default

Due to Steinberg’s licensing, the Nanohost repo is missing the VST2 header files, though…(JUCE no longer requires the VST2 headers, it has its own versions of the needed data structures etc.)


#7

Great, I’ll study the code and learn :nerd_face: