Let us assume you have a project build with Qt version 5.x. You have your Qt installation on your system either Windows, Linux or Mac Os X, doesn't really matter as long as you are compiling your application from Qt creator. What to do if you want to automate this process and you can't install Qt on your, let us assume, build machine. There are several different reasons why you don't want to install Qt on each machine you are building it on. In my particular case application is hosted on TeamFoundation server and code is being pulled and build from there using Python scripts. Whole idea is to make build and deployment process self sufficient and easy to maintain. Python script should get latest code from source control and basically build Qt project from command line with same code on both Windows and Mac Os X.
Qt projects consist of .pro file which is basically your project file where you define you build settings, which files you want to build, c, c++, h etc. This file is very basic version of make file, but it's NOT. Alongside your standard C++ files you will probably have UI files if you are building application with windows. Those files are basically xml files describing your UI, windows, controls etc. Qt has a special tool inside it's bin directory call "uic" or "uic.exe" depending on which system and this executable is responsible for converting those UI files into "reasonable" C++ code, normally into .h files which all C++ compilers can actually recognise and compile. This tool will come later become my problem on Mac Os X system.
Qt build process
How Qt creator and actual qt build process works is quite simple. Inside Qt installation "bin" folder there is a tool named "qmake". Qmake has a task to take your .pro project file and create universal make file which can be compiled with any extern make program. Make is essentially tool that based on configuration in background calls compiler which eventually compiles your code into library or executable for particular underlaying operating system. If you click on Projects icon inside Qt creator you can see this steps with command line parameters being used.
Build or copy Qt installation
To be able to compile your application outside qt creator you will need content from Qt installation. One way is to install on local system and copy content of the installation or to build from source. Building from source can be very time consuming and frustrating. Building from source can take hours even if you exclude components you don't need such as example code etc. Basically you have different compilers plus different operating system you need to compile for, it adds up. It is definitely easier to download installer and install it locally and copy content from there.
Qt installation folder
In my case I had Qt 5.2.0 and under 5.2.0 folder which is a version there is "clang_64" folder and this means this Qt was build with/for clang 64bit compiler (not to go into many details here). In case of Windows installation this folder will be called for example "msvc2010" if you have version for Visual Studio 2010 C++ compiler.
To be able to build Qt from command line you will entire content from this folder. Bin subfolder contains various tools such as aforementioned Qmake and uic , lib folder is where Qt prebuild libraries lie, include folder contains header files and "mkspecs" folder contains instructions for Qmake how to build make file for each particular compiler.
Build from command line
Almost there. Let us assume we copied Qt installation on following locations C:\QT5_build for Windows and /Users/yourname/QT5_build for OS X. Build is two step process. First you run Qmake agains your .pro project file and based on your settings it will generate Make, Make.Debug and Make.Release files.
Note:
Since we are not using installed version of Qt we need to instruct Qmake where hour Qt headers and libraries are. This is done with qt.conf file. Make qt.conf text file and save it into "bin" folder where Qmake executable is. Content should be as simple as this
[Paths]
Prefix = C:/QT5_build
Notice forward slash. Forward slash must be used for both Windows and OS X. Also single slash instead of double
In first step execute your Qmake against your project file to generate make files.
Windows
For a Windows it would be:
C:\QT5_build\bin\qmake.exe [Path to your .pro file] -r spec C:\QT5_build\mkspecs\win32-msvc2010
By specifying "win32-msvc2010" I am telling Qmake to generate Make file for Visual Studio 2010 compiler. This same thing does Qt creator, passes same parameters to QMake and then afterwords calles JOM make tool to compile from those make files. Jom is clone of Microsoft Nmake and it just supports running multiple commands in parallel.
In second step you call Nmake with your generated Make file like this:
nmake /f [Path to your Make file] [Debug/Release]
Last thing to do Windows would be to check your application, run it and if necessary add needed Qt runtime libraries since build tools will not do that for you.
Mac OS X
This process is quite simple when it's done on Windows, it's quite other story on OS X. Steps are the same, first you run Qmake against your project file and then you call simple Unix make against make files, BUT. Since we took Qt build out of actual installation tools inside bin folder will not work since they have static links and will look for dependent libraries under absolute path where they were installed.
So first running QMake:
./Users/yourname/QT5_build/bin/qmake [Your .pro file] -r -spec /Users/yourname/QT5_build/mkspecs/macx-clang
In my case this returns with following error:
sh: line 1: 25283 Trace/BPT trap: 5 /Users/bbizic/QT5_11_Build/bin/uic -d Forms/advancedviewsettingsdialog.ui
dyld: Library not loaded: /Users/bbizic/Qt5.2.0/5.2.0/clang_64/lib/QtCore.framework/Versions/5/QtCore
Referenced from: /Users/bbizic/QT5_11_Build/bin/uic
Reason: image not found
So what happened is QMake called tool named "uic" to convert .UI into C++ header files. Uic returned error saying it can't find dependent library from absolute path where it was originally installed. If we run "otool -L" tool against uic we can see where it is actually looking for this library.
otool -L uic
uic:
/Users/bbizic/Qt5.2.0/5.2.0/clang_64/lib/QtCore.framework/Versions/5/QtCore (compatibility version 5.2.0, current version 5.2.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
Only way I found to work around this was to use install_name_tool. I am not saying it's the only or the best way, it's just the way I solved it. install_name_tool is command line tool which comes, I think with installation of XCode.
install_name_tool
It allows you to change those absolute paths inside dynamic libraries or executables.
There are several ways of locating shared libraries:
- @executable_path: relative to main executable
- @loader_path: relative to the referring binary
- @rpath: relative to any of a list of paths
Syntax is as follows:
install_name_tool -change /currentPath @rpath/newpath myexecutable
Note that first parameter after -change must be exactly what is inside executable.
See man dyld and man install_name_tool for more information.
Finally when uic tool is patched with correct paths you can run your Qmake.
After Qmake is finished generating make files you run following command to finally build your project.
make -f [Path to your make file] [debug/release]
Finally on Mac OS X deploying necessary Qt libraries with your application can be done using tool macdeployqt. You can read more about deployment on Mac Os X here. Since this tools is also part of QT installation bin folder it may also need be patched with correct paths with install_name_tool like described above.
That is it, it should compile and run. If you find better solution or any other thoughts or question on subject please leave comment below.