Qt qmake cross platform development - c++

What is the correct way of defining cross platform behavior in qmake? I'm attempting to merge two projects that use the same codebase but have different parameters in the qmake project file for things like different compiler flags or icon files.
To clarify, if someone pulls the MyProject.pro from version control and attempts to run qmake on it on a mac, I want a couple lines to change when compared to the same operation on a windows machine. Is there any way of adding arguments to $> qmake ... or better, not have to change anything?

Yes, QMake does support conditional statements, in the form of scopes. Basically, you write something like this:
DEFINES = MY_DEF
win32 {
DEFINES += WE_ARE_ON_WINDOWS
debug {
DEFINES += DEBUG_WINDOWS
}
}
As the example shows, scopes can be nested. Operators such as | for OR are also possible.
For a full list of variables and functions, refer to QMake documentation.

You can write something like:
win32:{
# Do something Windows specific
} else {
# Options for other platforms
}
in your .pro file(s).

Related

Can I use QBS for creating user defined run configuration files?

I am building a program in QT that is going to need a user definable run configuration file, similar to .vimrc. In short, it will need to define what keypresses are responsible for basic commands in a curses like interface.
I have not quite decided what format to use, but thought that QBS might suit the bill as I am already using it for project management, and it would seem that on the surface that it would be well suited for this sort of thing.
The idea is to have the configuration file sitting in /home/me/.programrc, which is easy enough. I do not know however what interpreters exist for its syntax in Qt or C++, if any, or whether it is practically suited to serve as a run configuration in the first place.
Is this whole idea conceptualized properly, and do adequate tools exist for achieving this goal?
Thanks.
QBS is now deprecated in favor of CMake (along with QMake).
You can add a ".qmake.conf" file in the same dir where you .pro file resides.
In this file you can store parameters which you can use in .pro/.pri files.
.qmake.conf
BUILD_DIR=$$shadowed($$PWD)/build
BUILD_TESTS_DIR=$$shadowed($$PWD)/unit_tests
SCRIPTS_DIR=$$PWD/scripts
TOP_SRC_DIR=$$PWD
project.pro
DESTDIR = $$BUILD_DIR/
INCLUDEPATH += $$TOP_SRC_DIR/
You could add your keypress confiog in the DEFINES parameter, e.g. for TOP_SRC_DIR:
DEFINES += "TOP_SRC_DIR=\\\"$$TOP_SRC_DIR\\\""
TOP_SRC_DIR is now known in your source code as a define.
Of course you will need to rebuild the file(s) which use the define so you may bind the define(s) to centralized "extern" variable(s) which you link to and force re-linking when the parameters change (e.g. PRE_TARGETDEPS += $BUILD_DIR/myParams.a)

Use autotools installation prefix

I am writing a C++ program using gtkmm as the window library and autotools as my build system. In my Makefile.am, I install the icon as follows:
icondir = $(datadir)/icons/hicolor/scalable/apps
icon_DATA = $(top_srcdir)/appname.svg
EDIT: changed from prefix to datadir
This results in appname.svg being copied to $(datadir)/icons/hicolor/scalable/apps when the program is installed. In my C++ code, I would like to access the icon at runtime for a window decoration:
string iconPath = DATADIR + "/icons/hicolor/scalable/apps/appname.svg";
// do stuff with the icon
I am unsure how to go about obtaining DATADIR for this purpose. I could use relative paths, but then moving the binary would break the icon, which seems evident of hackery. I figure that there should be a special way to handle icons separate from general data, since people can install 3rd party icon packs. So, I have two questions:
What is the standard way of installing and using icons with autotools/C++/gtkmm?
Edit: gtkmm has an IconTheme class that is the standard way to use icons in gtkmm. It appears that I add_resource_path() (for which I still need the installation prefix), and then I can use the library to obtain the icon by name.
What is the general method with autotools/C++ to access the autotools installation prefix?
To convey data determined by configure to your source files, the primary methods available are to write them in a header that your sources #include or to define them as macros on the compiler command line. These are handled most conveniently via the AC_DEFINE Autoconf macro. Under some circumstances, you might also consider converting source files to templates for configure to process, but except inasmuch as Autoconf itself uses an internal version of that technique to build config.h (when that is requested), I wouldn't normally recommend it.
HOWEVER, the installation prefix and other installation directories are special cases. They are not finally set until you actually run make. Even if you set them via the configure's command-line options, you can still override that by specifying different values on the make command line. Thus, it is not safe to rely on AC_DEFINE for this particular purpose, and in fact, doing so may not work at all (will not work for prefix itself).
Instead, you should specify the appropriate macro definition in a command-line option that is evaluated at make time. You can do this for all targets being built by setting the AM_CPPFLAGS variable in your Makefile.am files, as demonstrated in another answer. That particular example sets the specified symbol to be a macro that expands to a C string literal containing the prefix. Alternatively, you could consider defining the whole icon directory as a symbol. If you need it only for one target out of several then you might prefer setting the appropriate onetarget_CPPFLAGS variable.
As an aside, do note that $(prefix)/icons/hicolor/scalable/apps is a nonstandard choice for the installation directory for your icon. That will typically resolve to something like /usr/local/icons/hicolor/scalable/apps. The conventional choice would be $(datadir)/icons/hicolor/scalable/apps, which will resolve to something like /usr/local/share/icons/hicolor/scalable/apps.
In your Makefile.am, use the following
AM_CPPFLAGS = -DPREFIX='"$(prefix)"'
See Defining Directories in autoconf's manual.

Entering scopes in template lib

In a C++/Qt project, we are using .pro-files and qmake to build. Part of the project is a static lib. The .pro file goes like this:
TEMPLATE = lib
CONFIG = staticlib
#general build instructions
linux{
#some os-specific build instructions
}
win32|win64{
#some os-specific build instructions
}
However, these scopes are never entered, not on a linux system (when the first scope should execute), nor on a windows system (for the second scope).
This only appears to be a problem in the staticlib-configuration/lib-template.
The Qt-documentation mentions the different templates, but I do not see anything mentioned as to why scopes would not work or how to solve this.
Those conditions are true if they're set in the CONFIG variable. By overwriting CONFIG with staticlib, you reset all preset flags, including the ones specifying the platform.
It should work if you do CONFIG += staticlib

What is the meaning of these commands when you add in a qmake file(.pro)

In short, I want to change the type of application to win32 app, then, I've used the following commands in .pro file
CONFIG -=windows
QMAKE_LFLAGS += $$QMAKE_LFLAGS_WINDOWS
After use the previous commands the application works fine as I want.
But the problem is I don't know what the meaning of each command of these commands.
Can anybody explain each command of these commands?
Let's see CONFIG -= windows.
Excerpt from qmake manual: CONFIG variable
CONFIG
The CONFIG variable specifies project configuration and compiler
options. The values will be recognized internally by qmake and have
special meaning. They are as follows.
[...]
The following options define the application/library type:
windows - The target is a Win32 window application (app only). The
proper include paths, compiler flags and libraries will automatically
be added to the project.
console - The target is a Win32 console application (app only). The
proper include paths, compiler flags and libraries will automatically
be added to the project.
Another excerpt from the manual: Operators
Operators
In many project files, the assignment (=) and append (+=) operators
can be used to include all the information about a project. The
typical pattern of use is to assign a list of values to a variable,
and append more values depending on the result of various tests. Since
qmake defines certain variables using default values, it is sometimes
necessary to use the removal (-=) operator to filter out values that
are not required.
The -= operator removes a value from the list of values in a variable:
DEFINES -= USE_MY_STUFF
The above line removes USE_MY_STUFF from the list of pre-processor
defines to be put in the generated Makefile.
So with CONFIG -= windows you are removing the value windows from the list of values in variable CONFIG. Looks like windows is among the default values of CONFIG on your platform and you need to remove that value. The value windows defines that your target is a Win32 window application. By removing it you declare that you would not like to have a Win32 window app. If your target is a Win32 console application instead then it is recommended to declare it explicitly: CONFIG += console.
And now let's see QMAKE_LFLAGS += $$QMAKE_LFLAGS_WINDOWS.
Excerpt from the manual: QMAKE_LFLAGS
QMAKE_LFLAGS
This variable contains a general set of flags that are passed to the
linker. If you need to change the flags used for a particular platform
or type of project, use one of the specialized variables for that
purpose instead of this variable.
[...]
QMAKE_LFLAGS_WINDOWS
This is used on Windows only.
This variable contains link flags when building Windows GUI projects
(i.e. non-console applications). The value of this variable is
typically handled by qmake or qmake.conf and rarely needs to be
modified.
This means that if you would like to change the flags then you should change either QMAKE_LFLAGS_CONSOLE or QMAKE_LFLAGS_WINDOWS. However you changed QMAKE_LFLAGS directly by adding the value of QMAKE_LFLAGS_WINDOWS which is strange because it contains link flags for building Win32 window apps and you declared with CONFIG -= windows that you would not like to have a Win32 window app.
CONFIG tells qmake that you're building for a specific platform, QMAKE_LFLAGS specifies which platform specific libraries you need.

Retrieve revision number in VS with qmake

My current workflow:
hg update (or whatever one uses to check out a revision)
MyProject.pro → qmake → MyProject.vcproj
Open Visual Studio, edit files
Build project
During the build step, how can I update my config.h header file with information from version control system (e.g. hg id)?
MyProject.vcproj is generated by qmake, so I shouldn't edit it by hand.
You can execute external commands from inside qmake. The easiest way to make the information available in your sources would be to use a define:
HGID = $$system(hg id)
DEFINES += HGID=\\\"$$HGID\\\"
I'm not sure if you can edit an external file from qmake. You could use an external tool, but on Windows you normally don't have things like sed, so it might be a little more problematic.
You can accomplish that using a custom build target and the PRE_TARGETDEPS keyword. Assuming config.h.in has the folowing format:
#define HGID $HGID
You can define a custom build target that will process hgid.h.in and output to hgid.h prior to building your main target as follows:
hgid.target = hgid
hgid.commands = sed s/\\\$$HGID/`hg id`/ hgid.h.in > hgid.h
QMAKE_EXTRA_TARGETS += hgid
PRE_TARGETDEPS += hgid
One opton is to enable the Keyword Extension. Put something like this in your hgrc (or Mercurial.ini if that's your thing):
[extensions]
hgext.keyword=
[keyword]
config.h =
[keywordmaps]
HGREV = {node}
Then in config.h put:
#define HGREV "$HGREV$"
You might need to parse the hex value out of the "$HGREV: deadbeefdeadbeef $" that you'll get, but that's easily done by whatever code is accessing the HGREV define.
In addition to Lukáš Lalinský and goodrone's comment, I'd like to mention that qmake can link directly to the script, not only to it's output. So one can say
DEFINES += REPO_ID=\\\"`./setlocalversion.sh`\\\"
and the script will be freshly executed for every single target.