macdeployqt on homebrew installed frameworks - qt

I'm trying to deploy an application using macdeployqt. All Qt frameworks get copied correctly into the application bundle. The problem I encounter is that macdeployqt does not have write permissions on the copied frameworks which originally reside in /usr/local/lib. This is because I have installed qt using homebrew which seems to make install everything read only. My question is whether there is a better way to fix this issue then manually changing all permissions of the qt libraries inside /usr/local/lib so that I can use macdeployqt from within a qt .pro project. (I don't want to use macdeployqt manually with sudo or such)
The reason why I'm asking is because I am using many third party libraries in the project (they get copied ok etc.) which I need to update often through homebrew and thus have to redo the permission changing on them.
Thanks in advance!

Just in case someone finds this old post looking for info about macdeployqt:
Use a script to do macdeployqt in preference to scripting the macdeployqt commands in your .pro file. That will allow you to change the permissions on the files on the fly.
Here is [a snippet of] the script I use for one of my apps:
https://bugreports.qt-project.org/browse/QTBUG-23268
If you're on Windows and don't have bash, you can use perl or python. The script referenced above modifies the files on the fly to work around a bug - you can put anything you want here, including changing the permissions on the files.
Using a script also means that you have the flexibility to add commands later to do code-signing, packaging or whatever else you need.
The Qt .pro "scripting language" actually generates Makefile commands under the hood and can be quite obscure if you want to accomplish deployment tasks that relate to paths and sets of files.
Also you'll need to create an extra target or include it into your build target - either way the build process becomes more complex and more error prone.
Disclaimer: I worked on Qt for 8 years as a Senior Engineer for Nokia/Trolltech, and also have published a commercial cross-platform app using Qt.

Related

Getting path to compiler executable in Qt

I write applications in C++/Qt, and sometimes I have to compile them in Windows. For that I use MinGW. Unfortunately, that makes the executable dependant on mingwm10.dll and libgcc_s_dw2-1.dll. I prefer to solve such problems by just copying needed DLLs into application folder and distributing it like this. I use QMAKE_POST_LINK in the *.pro file to automate the process.
Unfortunately, for various reasons MinGW ends up in different directories on different systems I use. Is there a way to get the path to the compiler executable in Qt project? MinGW libs lie near its exe, so it would solve the problem.
Thanks.
UPDATE
I'm afraid I didn't put myself clear enough.
I know that 90% of users don't have Qt, and 99% don't have MinGW installed on their Windows desktop. This is why I distribute all needed DLLs along with the executable, so that it can run everywhere without installing anything. I just copy them in the same folder with the *.exe. To automate this copying process, I add a copy command to the QMAKE_POST_LINK, which executes it after the linker finishes linking my program.
The problem is that this copy command still needs to know from where to copy MinGW libraries. Hence my question: how can one know the compiler path in compile time?
$$OUT_PWDin Qt *.pro file expands to the path to the directory where built application is put to. $$PWD expands to the project directory. Is there a similar macro (or maybe a hack) which gives the path to the compiler executable?
You are trying to approach the problem from the wrong angle. In particular, the solution you want will not be robust. It will still break on different systems, for example, the ones that have different version of MinGW toolchain installed and therefore different runtime DLLs, which if loaded by your application (built with another version of MinGW) will most probably cause crashes and undefined behavior during runtime. Furthermore, there might be systems which do not even have MinGW installed. These are the main reasons why applications built with certain version of toolchain should be distributed with the corresponding runtime DLLs included (this is what is called redistributable runtime) which is common practice on Windows, and there is nothing wrong with it.
However, there is much better way to solve your problem. Simply link all the MinGW runtime libraries statically into your application. This is a very good practice for Windows applications (and a very bad one for Unix ones). To do that, add the following to the corresponding *.pro:
QMAKE_LFLAGS_WINDOWS += -static-libgcc -static-libstdc++ -static
NOTE: Qt libraries themselves have to be built with these flags too, i.e. they should be independent of the MinGW runtime too. If not, then you'd still have a transitive dependency to the MinGW runtime because of the Qt libraries your application is linked against.
NOTE: _WINDOWS suffix will ensure that your application gets linked with these flags only for the Windows platform, while on Unix it will still link dynamically with runtimes (such as glibc.so on Linux) for the reasons discussed above.
After that your application will no longer explicitly depend on any MinGW runtime DLLs what will solve both distribution and maintenance headaches.
NOTE: If you ever decide to migrate from QMake to CMake (recommended), then here's how you do the same for CMake.
Update
You could check the QMAKE_CXX variable, but most likely it does not contain an absolute path to g++.exe. Usually it is simply g++, and the directory containing it is searched in PATH then. So in this case you'd have to parse PATH and check each directory in it for existence of g++ in it. This is very nasty logic to write in such a limited build system as QMake. So, as I stated above, you better off with 2 options:
Link runtimes statically into the application, so that you don't have to distribute anything. If you don't want to do it, then I want to know why - please write a comment;
Migrate to more feature-rich and flexible build system - CMake.

OpenGL Widget works in creator but black when launched from .exe

I have been working on a Qt OpenGL project for a bit now for some school work. I had to re-build Qt 5.0.1 for my windows machine so I could use OpenGL proper. At the end of this project I need to turn over the files and any executables, so I figured I could take the release .exe and stick it in a .zip for use.
I followed instructions online of making sure I place any needed .dll's into the .exe's dir. For my project there are 10:
icudt49, icuin49, icuuc49, libEGL, libGLESv2, Qt5Core, Qt5Gui, Qt5OpenGL and Qt5Widgets
I took these files all from:
C:\Qt\Qt5.0.1\5.0.1\msvc2010\bin
on my system.
Issue is the .exe will run and I get the UI and all. But the OpenGL scene is just black. I can still click objects in the scene, evidently zoom in and out and all that. I assume thats just the Qt translating the commands still. But nothing is visible. I'm unsure what the problem can be because it all works fine when launched from the creator.
EDIT: So, with all the dlls in the release folder, running the project from within creator will also have a black screen, when I remove them, it runs well. So perhaps one of the dll's is just wrong?
Also:
I looked online about publishing with Qt Creator and found not too much aid, said I should start from completely rebuilding Qt Creator staticly, but I'm sure the guide I had followed did this, however I still can't publish from the build menu, so I stuck with the above method.
I suggest, that you open every of the DDLs in your Zip file with Dependency Walker (http://www.dependencywalker.com/). It should display information about dependencies from one of your QtXXX.dll files to other files. If one of the dependencies is missing, you know where to look next. You can also try to open your executable with Dependency Walker. I haven't used the program for a long time so I don't remember if opening an executable is the only way it works. Anyway, here are the reasons why you might want to use the tool: http://www.dependencywalker.com/help/html/overview_1.htm
This question might also be helpful:
At least one module has an unresolved import due to a missing export function in an implicitly dependent module
Good luck!
So the ultimate issue was the use of the correct DLLs. Using something like DependenyWalker can help you to note which DLLs may be missing, however it did nothing in my case.
I had installed Qt once, and also rebuilt, uninstalled and re-installed it. However all the libraries it was calling from as no longer in C:\Qt\Qt5.0.1\5.0.1\msvc2010\bin as expected, it was calling from the github repository where I built it C:\Users\User\Documents\GitHub\qt5. Once this is sorted out, it still required a framework folder and then it works as expected.
1) Copy the correct DLL files to the release folder of the build.
2) Create a folder in the same dir as the .exe named "platforms". (Note: elsewhere has said create plugins>platforms, but this will not work with newer Qt versions)
3) From the same source you got the other DLLs, copy qwindows.dll to the platforms folder you created.
4) Run the executable and enjoy.
As long as the system you're running on is capable of your OpenGL structure, it should be fine.

How to specify build, deployment, and run configuration in a Qt Creator `.pro.shared` file?

I can see from the documentation on https://qt-project.org/doc/qtcreator-2.6/creator-sharing-project-settings.html how to create a .pro.shared file that standardizes Editor settings.
But there's no mention of build configurations, build steps, deployment methods, or run configurations.
I tried just renaming my .pro.user file (which includes custom build, deployment, and run configuration) to .pro.shared, but when I reopened the project, I got the defaults.
What's the right way to specify these settings in a .pro.shared file?
So short answer: You can't. Those settings are the reason why it is a .user file: They reference settings that are specific to one Qt Creator instance.
Long answer: We are moving to support this use case better, 2.6 was a huge step in that direction. With 2.6 you might be able to share build/deploy/run settings, but you need to make sure everybody using that .user file has compatible kits with exactly the same ids. You also need to make sure that everybody is using the same paths to sources, builds, operating system, etc. which limits its use quite a bit.
This might work e.g. with the Qt 5 kit installed by the official Qt 5 packages or with kits created specially for your setup. This will fail in any setup where you do not have tight control over all the development setups! On the other hand: If somebody is using a non-default setup of creator (kits, paths, etc.) then creator will just throw away some or all kit defined in the .user file of the project and will then continue, asking for kits to use. That is exactly what you will get without a .shared/.user file available at all.
Please be aware that as far as I know nobody ever tested such a setup. So you will most likely run into bugs and misbehavior... if you do: Please file bug reports at https://bugreports.qt.io/ ;-)
If you have only one environment you are targeting with your development, then you can get pretty far by having that environment set up (e.g. you only have one compiler/Qt version/kit defined that is exactly what you want everybody to use). Creator will then just default to that one, even if you have no .user file at all.

How to make Qt aware of the QMYSQL driver

I'm trying to access a MySql database from a Qt application but I get the following error:
QSqlDatabase: QMYSQL driver not loaded
QSqlDatabase: available drivers: QSQLITE QSQLITE2
I find this very strange cause I have libqsqlmysql.so on my Qt folder. I have even tried to compile the MySql driver as a static plugin and add it to my .pro file as:
QTPLUGIN += qsqlmysql
But this also generates the same runtime error (it must've found the plugin cause there's no error compiling the application)
What am I missing? I would like to avoid having to compile Qt from source cause this will have to work seamlessly on the deploy machines as well.
BTW: Even though I'm developing and testing on Linux I will need to support Windows. Will I experience this same issue on Windows? How can I compile and link the MySql driver in both Linux and Windows?
The solution:
After following #Sergey's recommendations I did an strace of the application redirecting the output to grep so I could search for 'mysql' and for my surprise the application wasn't looking for the plugin at QTDIR/plugins/sqldrivers where I had libqsqlmysql.so, it was looking at QTDIR/lib. After copying the plugin to the lib folder the MySql connection worked.
Try opening the shared library with dlopen() and see if it loads and if not, what dlerror() tells you. I always run into similar problems on Windows. LoadLibrary()/GetLastError() saved me numerous times (last time it was because of a wrong version of some libiconv/libintl DLL). Running ldd on the plugin may also help.
If dlopen() works fine, try to load the plugin with QPluginLoader. If it doesn't load, then check the buildkey of the plugin. I usually do it the dirty way by running strings on the plugin and then looking for strings like "buildkey" or "QT_PLUGIN_VERIFICATION_DATA". Just looking at the build key and around it may give you an idea. For example, you may realize that you have compiled your plugin in the release mode while your application is compiled in the debug mode. In such case the build key won't match and the plugin won't load. Everything in the build key must match your configuration. Note that the version and the build key are checked differently: the build key must match exactly (or match some black magic called QT_BUILD_KEY_COMPAT), but in the version only the major version must match exactly, the minor version must be the version of Qt the plugin was compiled with or later and the patch level is ignored. So if your plugin was compiled with Qt 4.x.y then it will work with Qt versions 4.z.* where z>=x. This actually makes sense.
If the build key looks okay (which is unlikely if you got to this point), you may wish to look at QLibraryPrivate::isPlugin() source code to figure out what's wrong, but that doesn't look like an easy task to me (although running this in a debugger may help).
If QPluginLoader does load the plugin, check if it is in the right directory and has correct permissions. If you still didn't solve the problem by this point, it's time to look at the SQL module source code that actually loads these plugins. But it is extremely unlikely. I ran into this problem many, many times and it was always either the library not loading or the build key not matching.
Another way to go after QPluginLoader loads the plugin successfully is to use strace to figure out whether the program at least tries to open the plugin file. Searching for something like "sqldrivers" or "plugins" in the strace output should also give away the directory where Qt is searching for its plugins and specifically SQL drivers.
Update
Is it possible to compile the driver as a static plugin and don't worry about anything? Let's try:
d:\Qt4\src\plugins\sqldrivers\psql>qmake CONFIG+=static LIBS+=-Ld:/programs/Post
greSQL/lib INCLUDEPATH+=d:/programs/PostgreSQL/include
d:\Qt4\src\plugins\sqldrivers\psql>make
It compiles fine and now I got libqsqlpsql.a (release) and libqsqlpsqld.a (debug) in QTDIR/plugins/sqldrivers (it is the right place on Windows). I am using PostgreSQL driver here, but I don't think it will be any different for MySQL which I just don't have installed. Ok, let's compile some real program with it:
d:\alqualos\pr\archserv>qmake QTPLUGIN+=qsqlpsql PREFIX=d:/alqualos LIBS+=-Ld:/g
nu/lib INCLUDEPATH+=d:/gnu/include LIBS+=-Ld:/programs/PostgreSQL/lib LIBS+=-lpq
Note that I had to manually link to libpq, otherwise the linker would complain about undefined references. The funny thing is, qmake knows that qsqlpsql is located in QTDIR/plugins/sqldrivers and sets compiler and linker options accordingly. So it still needs to be in the right place to work, only you don't have to worry about your users running into the same problem as it is only used during compilation. An alternative would be to just use LIBS+=-Lpath/to/plugin LIBS+=-lqsqlpsql instead of QTPLUGIN+=qsqlpsql, at least the docs say that it should work, but I haven't tested it.
In order for the application to actually use the plugin I had to put the following in my main unit (CPP file):
#include <QtPlugin>
Q_IMPORT_PLUGIN(qsqlpsql)
It works! Also, from what I've been able to figure out from the sources, the build key and the version are checked only when a plugin is dynamically loaded (all the relevant stuff is in the QLibrary's private class, not even QPluginLoader's). So the resulting executable may (or may not, depending on the binary compatibility) work even with different versions and builds of Qt, although using it with older versions may trigger some bugs that were fixed later.
It is also worth noting that the order for loading SQL drivers is this: use the driver statically linked into Qt if available, then look for a driver registered manually with QSqlDatabase::registerSqlDriver(), then look for a driver statically imported into the application (the way described above), and finally try to load a shared plugin. So when you link statically, your users won't be able to use dynamically linked drivers they may already have, but will be able to use drivers linked statically into Qt (like in Ubuntu).
I compiled QT first and then realised that I need mysql as well. So I compiled mysql plugin by
executing following command in QT-DIR\src\plugins\sqldrivers\mysql folder.
Mysql plugin compile command
qmake "INCLUDEPATH+=$$quote(C:\Program Files\MySQL\MySQL Server 5.5\include)" "LIBS+=$$quote(C:\Program Files\MySQL\MySQL Server 5.5\lib\libmysql.lib)" mysql.pro
Plugings are then created in created in folder QT-DIR\plugins\sqldrivers.
However, when I tried to use it in my code. It failed with following error.
Error msg
QSqlDatabase: QMYSQLDriver driver not loaded
Solution
After some googling and checking Path variable I realised that the Mysql server lib
( C:\Program Files\MySQL\MySQL Server 5.5\lib) directory was not in my Path variable. I expect that the dll in this folder are used by the plugin at runtime. After including Mysql server lib in Path variable everything worked smoothly. Hope this information saves some hair on other programmers scalp, as I uprooted quite a few. :D
Last time I looked at this you needed to rebuild Qt from source and include the appropriate MySQL source.
Building Qt from the sources is not hard, it just takes a while. You are likely to have the required tools already.
A possible workaround may be to access the back-end over ODBC instead.
In order for your app to pick up the plugin at runtime, the shared library implementing the MySQL plugin needs to be placed in the correct directory. The best way of determining that directory is to check the output of QCoreApplication::libraryPaths. You can also force specific paths by using a qt.conf file.
Please note that plugins must be placed in subdirectories within the plugin path, and the final part of the path name (i.e., the parent directory of the shared libraries) cannot be changed. SQL drivers need to go in a directory named sqldrivers, i.e. <pluginpath>/sqldrivers. For more details on plugin directories, see How to Create Qt Plugins.
I was experiencing this same issue as well. I've been installing and experimenting with a lot of different Python tools and UIs. I then uninstalled everything python related. I did a fresh install of Python 3.2, PyQT 3.2, and Eric5. No more errors with the QMySQL driver.
well i have had this issue, and after a lot of time, and different tools, i found that QT ( on windows, have not been able to test on Linux.) loads the "QSQLMYSQL.." when requested, but before runtime the lib ("QSQLMYSQL..") file must reside on one of the searched paths (QApp.libraryPaths()) inside a folder called "sqldrivers".. otherwise QT will just ignore the file, even if it is at some other point inside the searched path.
what i did was to monitor the dependency of a sample app, and when i removed the "QSQLMYSQL.." dll from "plugins\sqldrivers\" it failed, but when i maded a folder inside the app folder, called "sqldrivers" and placed the "QSQLMYSQL..." inside there, it loaded.
what i have is mysql 5.5, qt 4.7.4.
hope anyone can use this, and if anyone knows more about it, i would like to know where to find it(http://doc.qt.nokia.com/stable/sql-driver.html, is the closest you can get to the information about the folder structur). :P
This may also happen if your QMYSQL plugin is linked against the "wrong" mysql_client.a or it isn't in the LD_LIBRARY_PATH. I had this problem on OSX because mysql was installed via ports, and I fixed it with:
install_name_tool -change libmysqlclient.18.dylib /usr/local/mysql/lib/libmysqlclient_r.18.dylib libqsqlmysql.dylib

macdeployqt and third party libraries

I've got an application project that depends on a couple of shared libraries that I have created myself. According to the Qt 4.6 documentation "Deploying an Application on Mac OSX":
Note: If you want a 3rd party library
to be included in your application
bundle, then you must add an excplicit
lib entry for that library to your
application's .pro file. Otherwise,
the macdeployqt tool will not copy the
3rd party .dylib into the bundle.
I have added lib entries to my application's .pro file but the libraries that I have written do not get copied into the bundle when I execute macdeployqt. I have the following in my .pro file:
LIBS += -L../Libraries -lMyLib
Everything builds okay, its just when I try to run from the bundle that I run into problems i.e. "image not found" errors.
Is there a bug in macdeployqt or do I have to something more to my .pro file?
badcat is correct that the Qt 4.6 documentation has a grossly inflated view of what is possible with macdeployqt tool.
In my experience, the only things that are done by macdeployqt are:
Copy the Qt libraries into your app bundle in the foo.app/Contents/Frameworks/ directory
Adjusts the link libraries of one binary, namely foo.app/Contents/MacOS/foo (must have same name as app bundle, even if you mention another binary in Info.plist)
So, for every other binary and library you want to deploy in your app bundle, you must do the following:
Run macdeployqt to enjoy its useful but feebly inadequate benefits
macdeployqt <path_to_your_nascent_app_bundle>/foo.app
Install your extra libraries manually
cp <original_library_path> foo.app/Contents/Frameworks/<lib_name>
Find out what libraries each binary links to.
otool -L <binary_file_name>
Change the internal libary paths in your binaries
install_name_tool -change <original_library_path> #executable_path/../Frameworks/<lib_name> <binary_file_name>
I wrote a perl script that automates these steps for my application, but it's a bit too specific to my particular environment to post here.
You don't need to take care about manual deployment of third-party libraries. I am uploading a patch to Qt that makes it possible to specify additional library search paths, so that the macdeployqt tool finds the third-party dependencies:
https://codereview.qt-project.org/#change,47906
After this one there will be another commit that will add support for third party libraries' deployment.
Did you check the .app bundle to see if the libraries are really not there?
If that's the case, I'd assume there really is a bug in macdeployqt, or it simply can't find the library you are linking. Personally I've never seen macdeployqt actually copy any needed 3rd-party libraries into the bundle.
The interesting part is that macdeployqt never ever works directly with the .pro file. It just does some stuff to the produced application bundle. And after a quick glance into the documentation this Qt 4.7 documentation page obviously proves me right:
Note: If you want a 3rd party library to be included in your application bundle, then you must copy the library into the bundle manually, after the bundle is created.
I'd assume there is a bug in the 4.6 documentation. For me macdeployqt never placed any library files in my bundle (except for the Qt* ones, of course).
I did spend a lot of time with this stuff in my past, and ended up writing a simple little (Python) script that packs everything up into my bundle, changes the library names as needed and puts everything in a .dmg file with automatic naming.
Possibly not what you wanted to hear, but it works. ;)
https://github.com/auriamg/macdylibbundler
dylibbundler is a small command-line programs that aims to make bundling .dylibs as easy as possible. It automatically determines which dylibs are needed by your program, copies these libraries inside the app bundle, and fixes both them and the executable to be ready for distribution... all this with a single command on the teminal! It will also work if your program uses plug-ins that have dependencies too.

Resources