Solved Loading a dylib function using QLibrary
-
I am integrating support for a digital oscilloscope (PicoScope) into an existing application. The manufacturer of the scope kindly provides an API, libraries and documentation to do so. Using QLibrary, I am able to load the library properly as follows:
ps2000aLib = new QLibrary( QString(PICOSCOPE_LIBRARY_DIR_PATH) + QString(PICOSCOPE2000A_LIBRARY) ); if( ! ps2000aLib->isLoaded() ) { qDebug() << "ps2000a dll did not load"; return; }
The first function to call to acquire the scope is defined as follows in the manufacture documentation:
PICO_STATUS ps2000aOpenUnit ( int16_t * handle, int8_t * serial )
The guide can be found here:
https://www.picotech.com/download/manuals/picoscope-2000-series-a-api-programmers-guide.pdfWhen I try to get a function pointer, as follows:
typedef PICO_STATUS (*PS2000aOpenUnit)( int16_t*, int8_t*); PS2000aOpenUnit ps2000aOpenUnit = (PS2000aOpenUnit) ps2000aLib->resolve("ps2000aOpenUnit"); if( ! ps2000aOpenUnit ) { qDebug() << "ps2000aOpenUnit function not found in library"; return; }
the function pointer ps2000aOpenUnit is 0 and I fall inside the if statement, so the function is not found.
When I call:
nm -gUj .../libps2000a.dylib
on the command line, the symbol is listed in the result.
Am I doing something wrong or any reason the function might be found by nm and not by QLibrary?
-
I think you are just missing a QLibrary::load() call.
There may be more gotchas (like path issues) on your platform, but I can only comment for Windows and Linux.
-
Hi,
Where do you get that library from ?
-
@SGaist For Mac, the library and supporting header files are installed with the application. For Mac, that is:
https://www.picotech.com/downloads/_lightbox/picoscope6mac
or
https://www.picotech.com/download/software/beta/PicoScope-6.13.7-4r706.pkgFor Windows, there is a separate SDK package:
https://www.picotech.com/download/software/sr/PicoSDK_32_10.6.12.41.exeBut I have not downloaded that yet as I develop mostly on Mac first.
PicoTech (manufacturer) has been around for a long time and has offered the SDK for at least 10 years. They offer sample code for integration in C. They have a user forum but there are not many posts regarding integration in QT, unfortunately.
-
@aha_1980 The library is loaded during the instantiation, no ? My code also passes the first if-statement so the library seems to be loaded.
-
@aha_1980 So I think you are right. I added a call to ps2000a->load() and then it seemed to find the function. I don't know why I wasn't falling into the first if statement before...
-
I am now able to load the library through QLibrary. However it seems that the ps2000a library depends on another dynamic library, picoipp, which itself also depends on another dynamic library, iomp5. If I load the libraries with QLibrary, as below:
QString iomp5 = QString(PICOSCOPE_LIBRARY_DIR_PATH); iomp5 += QString(PICOSCOPE_IOMP5_LIBRARY); QLibrary* iomp5_lib = new QLibrary( iomp5 ); //QString(PICOSCOPE_LIBRARY_DIR_PATH) + QString(PICOSCOPE_IPP_LIBRARY) ); bool iomp5_loaded = iomp5_lib->load(); if( ! iomp5_loaded ) { qDebug() << "iomp5 library did not load: " + iomp5_lib->errorString(); return false; } QString pico = QString(PICOSCOPE_LIBRARY_DIR_PATH); pico += QString(PICOSCOPE_IPP_LIBRARY); QLibrary* picoipp_lib = new QLibrary( pico ); //QString(PICOSCOPE_LIBRARY_DIR_PATH) + QString(PICOSCOPE_IPP_LIBRARY) ); bool ipp_loaded = picoipp_lib->load(); if( ! ipp_loaded ) { qDebug() << "psipp library did not load: " + picoipp_lib->errorString(); return false; } bool ps2000a_loaded = ps2000aLib = new QLibrary( QString(PICOSCOPE_LIBRARY_DIR_PATH) + QString(PICOSCOPE2000A_LIBRARY) ); if( ! ps2000a_loaded ) { qDebug() << "ps2000a library did not load: " + ps2000aLib->errorString(); return false; }
I picoipp_lib is not loaded and I fall into the second if statement. The errorString is:
"picoipp library did not load: Cannot load library /Applications/PicoScope6.app/Contents/Resources/lib/libpicoipp.dylib: (dlopen(/Applications/PicoScope6.app/Contents/Resources/lib/libpicoipp.dylib, 5): Library not loaded: libiomp5.dylib\n Referenced from: /Applications/PicoScope6.app/Contents/Resources/lib/libpicoipp.dylib\n Reason: image not found)"
So it seems picoipp cannot see iomp5 even though it is apparently loaded.
If I load the picoipp & iomp5 libraries through my .pro file as follows:macx: LIBS += -L"/Applications/PicoScope6.app/Contents/Resources/lib/" -liomp5 macx: LIBS += -L"/Applications/PicoScope6.app/Contents/Resources/lib/" -lpicoipp macx: INCLUDEPATH += /Applications/PicoScope6.app/Contents/Resources/lib macx: DEPENDPATH += /Applications/PicoScope6.app/Contents/Resources/lib
there is no difference in the result, picoipp library does not find libiomp5.dylib. I don't know how to check if the libraries are actually loaded, however.
If I load all the libraries through my .pro file as follows:
macx: LIBS += -L"/Applications/PicoScope6.app/Contents/Resources/lib/" -liomp5 macx: LIBS += -L"/Applications/PicoScope6.app/Contents/Resources/lib/" -lpicoipp macx: LIBS += -L"/Applications/PicoScope6.app/Contents/Resources/lib/" -lps2000a macx: INCLUDEPATH += /Applications/PicoScope6.app/Contents/Resources/lib macx: DEPENDPATH += /Applications/PicoScope6.app/Contents/Resources/lib
then the plugin loader in my main application, as below:
QPluginLoader pluginLoader( pluginsDir.absoluteFilePath(fileName) ); // Load file into the plugin loader QObject *plugin = pluginLoader.instance(); // Get a pointer to the plugin if( plugin ) { // Filter files that aren't actually plugins ... }
does not recognize my plugin as a plugin.
Any insights on how to load the cascading libraries such that they are visible to each other would be great ! Or other suggestions on how to implement. -
Add the
DYLD_LIBRARY_PATH
environment variable to the Run part of the project panel. As value, put there the folder where these libraries can be found. -
@SGaist said in Loading a dylib function using QLibrary:
DYLD_LIBRARY_PATH
Great, thanks!! I'll try that. Once added, do I load the libraries with QLibrary or without ? -
That's up to you.
Personally, since you have a SDK at your disposal, I don't see why you wouldn't link to the libraries directly.