qmake - QMAKE_RPATHDIR doesn't work - c++

I have mac os x. I have application and it needs to use shared library (framework on mac), that is developed as separate project, but concurrently and in Qt 5 too.
App.pro
.
.
else:mac: LIBS += -F$$OUT_PWD/Frameworks -framework library1
.
.
QMAKE_RPATHDIR += /usr/lib
firstly, i am telling to qmake, that library1 will reside in it's bundle in Frameworks directory (this is no problem, linking is done success)
secondly, QMAKE_RPATHDIR should tell to gcc compiler, that when app's libraries are located, it should look to those paths in QMAKE_RPATHDIR too. I specified /usr/lib, just to check if it will work, but:
otool -l app
doesn't show up any LC_RPATH (i am expecting there will be one record for /usr/lib) as in here Print rpath of executable on OSX
I really need to setup my development environment (Qt 5, Mac OS X, one base application, one core library (this will act's as SDK for plugins too) and additional plugins (shared libraries too).
ERROR is still:
dyld: Library not loaded: library1.framework/Versions/1/library1
Referenced from: /Users/Krab/projects/qtProjects/build-rootProject-Desktop_Qt_5_3_0_clang_64bit-Release/app/app.app/Contents/MacOS/app
Reason: image not found
this is obvious, because the settings in .pro files is just for linking and doesn't resolve the dynamic loading of those libraries (which should be resolved by that QMAKE_RPATHDIR directive).

You need to build your framework with the correct install name. For example:
QMAKE_LFLAGS_SONAME = -Wl,-install_name,#rpath/
Then in your application,
osx:LIBS += -F$$OUT_PWD/Frameworks -framework library1
QMAKE_RPATHDIR += /usr/lib
If your resulting "library1" framework is placed in /usr/lib, then your application should load fine. However, in almost all cases you'll want the framework placed inside your application bundle, like so:
myapp.app/Contents/Frameworks/library1.framework
In that case you'd set the rpath in your application a little differently, like so:
QMAKE_RPATHDIR += #executable_path/../Frameworks

Add
QMAKE_POST_LINK += install_name_tool -add_rpath <path to look in> $$TARGET
to your .pro file - where < path to look in> is the path you framework or dylib resides.
for example, if you place the framework right next to your executable, use
QMAKE_POST_LINK += install_name_tool -add_rpath #executable_path $$TARGET

In my case, I had a simple dylib instead of a framework linked to my executable. I had the following already:
LIBS += -L/path-to-mylibrary/ -lmylibrary
QMAKE_RPATHDIR += /path-to-mylibrary/
QMAKE_RPATHDIR was working as my executable listed the LC_RPATH command correctly (obtained by otool -l myexecutable):
Load command 25
cmd LC_RCPATH
cmdsize 56
name /path-to-mylibrary/ (offset 12)
However, my resulting executable listed the LC_LOAD_DYLIB command for my library as follows:
Load command 12
cmd LC_LOAD_DYLIB
cmdsize 48
name libmylibrary.dylib (offset 24)
As per this answer, I updated the LC_LOAD_DYLIB command to include the RPATH when looking for the dylib by adding the following to the .pro file of my executable application:
QMAKE_POST_LINK += install_name_tool -change libmylibrary.dylib #rpath/libmylibrary.dylib $$TARGET
Afterwards, my executable started listing the LC_LOAD_DYLIB command correctly:
Load command 12
cmd LC_LOAD_DYLIB
cmdsize 56
name #rpath/libmylibrary.dylib (offset 24)
As a side note, mylibrary is actually a qml plugin deployed into /qt-install-root/qt-version/platform/qml/Mylibrary/ and is loaded also from the QML engine in other projects.

Related

Linking a dynamic lib using Bazel on MacOS

I'm compiling my program using Bazel, and I have a dependency on Intel TBB.
Intel TBB only provide dynamic libraries (no static) for good reasons (if you are curious: ctrl+f static here).
In my bazel WORKSPACE I defined that rule :
new_local_repository(
name = "inteltbb",
path = "./third_party/intel_tbb",
build_file = "./third_party/inteltbb.BUILD",
)
and in my "inteltbb.BUILD" I have:
cc_library(
name = "dynamic_lib",
srcs = ["build/macos_intel64_clang_cc8.1.0_os10.12.5_debug/libtbb_debug.dylib"],
hdrs = glob(["include/**/*.h"]),
visibility = ["//visibility:public"],
strip_include_prefix = "include/"
)
Then in my final program (under the cc_binary rule) I have:
deps = [
"#inteltbb//:dynamic_lib", [...]
It compile properly, find the headers successfully but at runtime it crashes saying:
____Running command line: bazel-bin/build-game
dyld: Library not loaded: #rpath/libtbb_debug.dylib
Referenced from: /private/var/tmp/_bazel_dmabin/526b91f44cfc47d856222c6b20765cc8/execroot/__main__/bazel-out/darwin_x86_64-fastbuild/bin/build-game
Reason: image not found
I check under the "bazel-bin" folder (where the executable is symlink for runtime execution: bazel-bin/build-game.runfiles/main/) and I do have:
the symlink for the executable (build-game)
a folder called (brace yourself): _solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Sbuild_Smacos_Uintel64_U
clang_Ucc8.1.0_Uos10.12.5_Udebug that contain my libtbb_debug.dylib for intel tbb.
Also when I run: otool -l build-game | grep LC_RPATH -A2 the result is:
cmd LC_RPATH
cmdsize 152
path $ORIGIN/_solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Sbuild_Smacos_Uintel64_Uclang_Ucc8.1.0_Uos10.12.5_Udebug (offset 12)
I don't understand why my executable doesn't find my dylib. I can't find anything wrong about the otool output but I'm not a mac expert (at all).
Any idea is welcome.
[edit]
If I edit the executable using otool to replace the path to the dylib like that:
#executable_path/_solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Slib/libtbb_debug.dylib
Then it works fine. I doesn't feel right that bazel force me to do that at every compilation :/
[edit 2]
A few people asked me the line I used to modify the path of the lib in the executable.
First run:
otool -L build-game
To spot the path of the lib you want to change. In my case it was: #rpath/libtbb_debug.dylib.
After that run:
install_name_tool -change #rpath/libtbb_debug.dylib #executable_path/_solib_darwin_x86_64/_U#inteltbb_S_S_Cdynamic_Ulib___Uexternal_Sinteltbb_Slib/libtbb_debug.dylib build-game
to change the path. Note that you can use #executable_path to make it relative to the binary path or you can put an absolute path, up to you.
I think this is already a known issue, and it was just fixed. Sorry for the trouble.
[edit: updated after submitting the fix]

How to use hdfk library into qt?

How can I use HKDF library in my qt project? I found this library seems appropriate in qt (I checked with my source), but I couldn't include this header to project.
Adding a library to a Qt project is actually quite simple. In your qmake .pro file you need the following:
# This is the search location for the compiler to look for headers that accompany your library.
# For system libraries that typically resides under **/usr/include** or **/usr/local/include** if you used `make install`.
INCLUDEPATH+="/path/of/headers/for/library"
# This is the search location for the compiler/linker to look for the library itself.
# For system libraries this is usually somewhere under **/usr/lib** or **/usr/local/lib**
LIBS+= -L/path/of/library/itself
# This is the name of the library to include at link time
# without the **lib** prefix and the **.so** / **.a** / **.lib** / **.dll** extension.
LIBS+= -lMyLibraryName
# This is the full path of the library file itself
# *including* the aforementioned **lib** prefix and the **.so** / **.a** / **.lib** / **.dll** extension.
# This is used by qmake to look for changes to the library at build time,
# to make sure it is re-linked on change and other dependency related stuff
PRE_TARGETDEPS += /path/and/filename/of/library/itself/libMyLibraryName.lib
TIP: All the paths, unless they are specified as absolute paths (starting with '/') will be relative to the build directory. This might be the project directory, but in the case of shadow builds, it will be the shadow build directory. As a tip, simply prepend the following to your relative paths to make them relative to project directory: $$_PRO_FILE_PWD_/ so if for example your lib resides in /my/qt/project/libs/mylib you could make your project resilient to moving by using $$_PRO_FILE_PWD_/libs/mylib instead. Please note that the "project dir" is the location of the qmake .pro file.
I use CryptoPP HKDF implementation by https://www.cryptopp.com
Firstly, build static lib for valid architecture and for your platform (MacOS, Android, iOS, etc). CryptoPP Wiki has working manuals and scripts.
Then, just add 2 lines to your qmake *.pro file:
INCLUDEPATH += $$DEV_LIBS_PATH/cryptopp/$$ANDROID_ARCH/include
LIBS += -L$$DEV_LIBS_PATH/cryptopp/$$ANDROID_ARCH/lib -lcryptopp
as you can understand, I used qmake variables DEV_LIBS_PATH and ANDROID_ARCH which are just compose right path to relevant headers and static library libcryptopp.a.

QtCreator for iOS: How to deploy a dylib shared library with my application

I'm having a hard time deploying dynamic shared libraries on iOS.
To isolate and expose the problem, I have a very simple "HelloWorld" project: A library exporting class with a function returning "Hello World" and a program using the class and displaying the message.
I'm using QtCreator with Qt 5.5.
I'm able to generate the .dylib file and link my program. But, when I deploy it on the iPhone, I get the error:
Démarrage des processus distants.
dyld: Library not loaded: libMyLib.1.dylib
Referenced from: /private/var/mobile/Containers/Bundle/Application/D6942CCE-828D-4C10-86DA-F7DA7ADF7449/MyApp.app/MyApp
Reason: image not found
On Android, I had the same kind of issue and could fix it by manually adding the shared library to the final package (apk) file, using ANDROID_EXTRA_LIBS. But I can find no equivalent for iOS.
Here are my .pro files. Full project can be downloaded here. I reported this to Qt as a bug, but if one could propose a kind of workaround this would help!
MyLib.pro:
QT -= core gui
TARGET = MyLib
TEMPLATE = lib
DEFINES += MYLIB_LIBRARY
SOURCES += mylib.cpp
CONFIG += shared
HEADERS += mylib.h\
mylib_global.h
MyApp.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = MyApp
TEMPLATE = app
SOURCES += main.cpp\
dialog.cpp
HEADERS += dialog.h
INCLUDEPATH += ../MyLib
LIBS += ../MyLib/libMyLib.dylib
I'd like the solution to be all embedded in QtCreator. The only think that should be changed here is one of the two .pro files. Possibly with post-build calls to MACOS commands...? Or just a post-build instruction in MyApp.pro to copy the dylib in the right place (.app target folder) before application is deployed? I'm really surprised this is not covered silently by QtCreator....
Note: This question suggests to set DYLD_LIBRARY_PATH. But I have no clue hox to do this within the MyApp.pro file nor how it will help upon iOS deployment (as DYLD_LIBRARY_PATH can be set the MAC PATH to the lib, not the iPhone PATH to the lib...)
1) In your library project make sure your dylibs have installname #rpath/mylib.dylib or such. E.g. by adding QMAKE_SONAME_PREFIX = #rpath to your library .pro file.
(You can check by looking at the first line of otool -L /path/to/libmylib.dylib. If the library is a prebuilt 3rdparty one, change it with install_name_tool -id #rpath/libmylib.dylib)
2) add the following to the application .pro file
# link to the lib:
LIBS += -L../mylib -lmylib
# make the app find the libs:
QMAKE_RPATHDIR = #executable_path/Frameworks
# deploy the libs:
mylib.files = $$OUT_PWD/mylib/libmylib.1.dylib
mylib.path = Frameworks
QMAKE_BUNDLE_DATA += mylib
I came up with a workaround for that, in case it could help anyone.
Build your library statically instead of dynamically (replace CONFIG += shared by CONFIG += staticlib
Now, compiler will generate *.a files instead of *.dylib, You must use this extension when linking libraries (replace LIBS += myLib.dylib by LIBS += myLib.a)
If your library was only linked by a program, you are done
If your library, let's call it (A), was used by another library (B), then (B) should not link with it anymore (No LIB flag in B.pro). Only the top level program will link with all your static libraries.
With this approach, I could deploy a program using 15 libraries on an iPhone with QtCreator.

Building errors Qt creator with Tbb under Windows 8

I compiled TBB library as shown QtCreator and TBB under Windows
set the necessary paths to the library (. Dll)
INCLUDEPATH += "C:\Tbb\include"
LIBS += -L"C:\Tbb\build\windows_ia32_gcc_mingw_debug\" \
-tbb_debug.dll"
as shown, but build the project I have the following error image, any ideas?
Do not use extensions for libraries to link (they are added automagically)
Understand command line switches :) --library=namespec has a shorthand version -lnamespec. Following that you defined command line switch -t with an argument bb_debug.dll, which is nonsense :)
You should use -ltbb_debug

Qt Creator or qmake on MacOSX build library as ".so" not dylib

I need to build my plugin/library as a .so on Mac. That happens without extra trick on Linux and works like a charm.
What extra options I need to add to my .pro file?
CONFIG += debug
QT += xml
TEMPLATE = lib
TARGET = mylib
DEPENDPATH += .
macx:INCLUDEPATH += ../../../Test \
/usr/local/include/
macx:LIBS += -L../../../Test/lib
DEFINES += CORE_EXPORT=
DEFINES += GUI_EXPORT=
HEADERS += test.h testGui.h
FORMS += testGui.ui
SOURCES += test.cpp testGui.cpp
RESOURCES += test.qrc
The ".so" suffix doesn't mean anything on OS X. On an ELF platform like Linux, an "*.so" file is a shared library. On OS X, shared libraries have the ".dylib" extension. On Linux, plugins are implemented as shared libraries (*.so) because you can unload them again when you're done with them. On OS X, shared libraries cannot be unloaded. That makes them unsuitable for plugins.
On OS X, you use bundles instead of shared libraries in order to implement plugins. Last time I looked, qmake doesn't support this directly. But you can modify the linker flags in order to build a bundle. By default, qmake uses the "-dynamiclib" linker flag, which builds a *.dylib. Instead, you should use the "-bundle" flag, which builds bundles. You can try this:
CONFIG += plugin
QMAKE_LFLAGS_PLUGIN -= -dynamiclib
QMAKE_LFLAGS_PLUGIN += -bundle
The file extension of a bundle is not standardized. You can use whatever you want (.so, .dylib, .plugin, .donald_duck, ...) Apple recommends ".bundle", but doesn't enforce it. To control the filename of the created bundle, you can set QMAKE_EXTENSION_SHLIB and QMAKE_PREFIX_SHLIB. For example, to get mylib.bundle, set:
QMAKE_EXTENSION_SHLIB = bundle
QMAKE_PREFIX_SHLIB =
If instead you want to get libmylib.so, only set:
QMAKE_PREFIX_SHLIB = so
As the names suggest, QMAKE_EXTENSION_SHLIB contains the file extension (without the .), and QMAKE_PREFIX_SHLIB contains the file prefix (by default it's lib).
you may need to put the -dynamiclibs line after bundle... works for me.
found here:
http://jonmacey.blogspot.com/2012/03/using-maya-api-with-qt-creator.html