Retrieve revision number in VS with qmake - c++

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.

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)

Using External Binary Resource

I'm on a project that used to have Compiled-in Resources.
Now, the user can choose the theme that he wants to work on. No problems until there, in a little research I started to use the External Binary Resource approach.
My resources were build successfully and the QResource::registerResource("/path/to/myresource.rcc"); returns true.
It is not working properly though. Apparently the compiled-in resource is still there, in the executable. I can't see the different icons stored in my external binary resource.
How do I remove this compiled-in resource? Do I need to do that to work properly?
Assuming you are using a .pro file for your project, you need to remove the resource file from the RESOURCES list. If you still want it to be listed in your project, you can use OTHER_FILES.
Before:
RESOURCES += file1.qrc file2.qrc
After:
RESOURCES += file2.qrc
OTHER_FILES += file1.qrc
If you want to go a step further you can automate the build of qrc files:
RCC_BINARY_SOURCES += file1.qrc
asset_builder.commands = $$[QT_HOST_BINS]/rcc -binary ${QMAKE_FILE_IN} -o ${QMAKE_FILE_OUT} -no-compress
asset_builder.depend_command = $$[QT_HOST_BINS]/rcc -list $$QMAKE_RESOURCE_FLAGS ${QMAKE_FILE_IN}
asset_builder.input = RCC_BINARY_SOURCES
asset_builder.output = $$OUT_PWD/$$DESTDIR/${QMAKE_FILE_IN_BASE}.qrb
asset_builder.CONFIG += no_link target_predeps
QMAKE_EXTRA_COMPILERS += asset_builder
OTHER_FILES += $$RCC_BINARY_SOURCES
You have to change the way the resources are compiled. By default, every resource file (resources.qrc, for example) included in a Qt project is compiled to C++ code (the qrc_resources.cpp you've probably seen after compiling the project). That makes the resource is compiled and linked with your executable (or library). The Qt for Visual Studio plugin does exactly that: adds a custom build step to every QRC file. Open the properties of the QRC file to take a look (right-click on the QRC file, then Properties):
Command line: "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" -no-compress "%(FullPath)" -o .\GeneratedFiles\qrc_%(Filename).cpp
Outputs: .\GeneratedFiles\qrc_%(Filename).cpp
%(Filename) is, as you can figure out, the extension-less name of the file
To avoid this behaviour just remove the QRC file from the project. Of course, the problem is that you'll have to manually build the .rcc file. You can do it using a script as part of your makefile.
On the other hand, if you're using Visual Studio, you can change the command used to compile it, adding the -binary option to the rcc tool so it compiles to an external file. In this way it will be included in your usual compilation workflow:
Command line: "$(QTDIR)\bin\rcc.exe" -name "%(Filename)" "%(FullPath)" -binary -o "%(Outputs)"
Outputs: $(OutDir)\%(Filename).rcc - it is different from screenshot because I took it from an existing project, use the one in the text to place the RCC file in the same dir of your executable.
Important note: be sure you change the build tool for all the configurations.
If you use a makefile or Qt Creator instead, you can use this as a base to create the needed script.
Hope this can help you.

Qt qmake cross platform development

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).

Can you use environmental variables in qt creator?

So I use a bunch of libraries in the code I'm currently working in. Right now I include them by doing things like win32:LIBS += "C:/my/location/Tools/libcurl/trunk/lib/Debug/curllib.lib". However, I have an environmental variable that defined %TOOLS% as C:/my/location/Tools/. I tried to simply change my include to win32:LIBS += "%TOOLS%libcurl/trunk/lib/Debug/curllib.lib", but it could not find the files. I looked online and this should be doable. Am I missing something simple, like a way to tell Qt creator to look at window's environmental variables?
Thanks!
To get the content of an environment variable when qmake is processed, you can use the following :
win32:LIBS += $$(TOOLS)/libcurl/trunk/lib/Debug/curllib.lib
TOOLS should be an environment variable set to C:/my/location/Tools.
But you don't necessarily need an environment variable for this. You can simple define a variable in your .pro file :
TOOLS="C:/my/location/Tools"
And use it's value by prefixing it with $$ :
win32:LIBS += $$TOOLS/libcurl/trunk/lib/Debug/curllib.lib
Try the following:
$$VAR => QMake variable's value at the time qmake is run
$${VAR} => QMake variable's value at time qmake is run (subtle difference)
$(VAR) => Contents of an Environment variable at the time Makefile (not qmake) is run
In your Case:
$$(TOOLS) return the Path you need.

Automatic increment of build number in Qt Creator

I would like to have a variable (or #define) in C++ source that will increment each time I use Qt Creator to build source code. Is there any way I can do this, perhaps some Qt Creator plugin or similar? If there is a way to do it if I use "make" on command line to build?
In your .pro file, you can create a variable that contains the results of a command-line program. You can then use that to create a define.
BUILDNO = $$(command_to_get_the_build_number)
DEFINES += BUILD=$${BUILDNO}
If you just want a simple incrementing number, you could use a pretty simple script:
#!/bin/bash
number=`cat build_number`
let number += 1
echo "$number" | tee build_number #<-- output and save the number back to file
I should note that this would cause the build number to increment every time you build, and also increment if you try to build but it fails. A better way is to get a build number based on the state of the code, and many version control tools can get you a text string for that, if not a number.
The Windows equivalent for Joerg Beutel's improved solution https://stackoverflow.com/a/5967447/1619432:
.pro:
build_nr.commands = build_inc.bat
build_nr.depends = FORCE
QMAKE_EXTRA_TARGETS += build_nr
PRE_TARGETDEPS += build_nr
HEADERS += build.h
build_inc.bat:
#echo off
set /p var= <build.txt
set /a var= %var%+1
echo %var% >build.txt
echo #define BUILD %var% >build.h
echo %var%
Usage
#include "build.h"
...
qDebug() << "Build number:" << BUILD;
As I wrote before after some testing I found that the original solution has a problem since the version number is not updated every time a new build is done. In a lot of cases I had edited a source file, run the build, but still got the same build number ... The building process just decided that nothing was changed and skipped the step which would have updated the build number. I first attempted to find a way to force that step, but couldn't figure it out. Finally I decided to go a different way. Now I use the script to generate a header file
build_number.h which contains a #define BUILD with the updated number behind. So Calebs script is now a bit modified (build_number.sh) :
#!/bin/bash
number=`cat build_number`
let number++
echo "$number" | tee build_number #<-- output and save the number back to file
echo "#define BUILD ""$number" | tee ../MyProject/build_number.h
The incrementing number is still stored within a file called build_number. I could have avoided a third file by parsing the generated header-file for the number, but decided against it. Note that the script and the generated header are located in the projects directory while the build_number file is in the build directory. That's not perfect, but I can live with it.
In order to put things together there are now some more things to do. First the generated header-file needs to be added to the project in the Qt Designer ... Right-click on Header-Files and "Add existing file". Second, it has to be included in the C++-file where the BUILD define inside is accessed ... #include "build_number.h" ... and last but not least some additions have to be made to the project file (MyProject.pro). Note that I deleted the stuff from Calebs solution, so we start from scratch here :
build_nr.commands = ../MyProject/build_number.sh
build_nr.depends = FORCE
QMAKE_EXTRA_TARGETS += build_nr
PRE_TARGETDEPS += build_nr
These lines (I put them before the HEADERS section) force the execution of the script, which reads the last build number from build_number, increments it, writes it back and also generates an updated version of the build_number.h file. Since that's part of the source of the project the new value gets linked into the code every time.
There's one thing to mention - now the building process is never at the opinion that nothing has changed. So even if you leave your code unchanged a new run of make will generate a new version number and build a new binary. The old solution left the number when code changed, this new solution forces a new build even when the source is unchanged, since I force a change in that one header file. One would have prefered something in between but since the header is only included in one place the rebuild is very fast and doesn't hurt much. But still, if somebody knows how to get the best of both worlds please advise. At least now I'll not have two different binaries with the same version number.
Caleb's suggestion is great, but didn't work "out of the box" in my case. I got some errors instead and it took some reading to fix them. The changes are very minor. I was using Qt 4.7 on Ubuntu Linux ... The first change, if you can believe it, was in the shell script to go from let number += 1 to let number++ ... I normally use/program Windoze, so I can't explain that, but when I run the script from a command line (shell prompt) in the original case I get errors reported, in the changed case all goes well and incrementing numbers are returned ...
Since it's not completely reported by Caleb - I used build_number.sh as the name of the shell script and made another file with the name build_number (without .sh) and put just a zero inside, nothing else.
The last and most obnoxious bug was fixed by replacing BUILDNO = $$(command_to_get_the_build_number) with BUILDNO = $$system(./build_number.sh) in the Qt project file. Note the system after $$ and the required ./ in front of the file name. The later is elementary for a regular Linux user, but not as much so for a Windows user.
Hope this makes it more straight forward for people new to all this, like myself. You can read more in the Qt Designer Help section if you seek for qmake, including the function reference, Advanced Use etc.
Oh, one last word ... I also had to change DEFINES += -DBUILD=$${BUILDNO} to DEFINES += BUILD=$${BUILDNO}, so the -D is gone. Inside your C++ code you would use BUILD as if you had written #define BUILD 1234 at the top of your file.
Here's a solution for Win7 I came up with based on handle's solution.
This solution also makes Windows give yer version # when you right-click yer target, and choose Properties | Details. It works in Win7, and probably most earlier versions.
Ok, you make yer build_inc.bat:
#echo off
copy /b myapp.rc +,,
set /p var= <build.txt
set /a var= %var%+1
echo %var% >build.txt
echo #define BUILD %var% >build.h
and put it in yer proj folder. (copy /b myapp.rc +,, is inscrutable Microsoft-eese for "touch" - to update a file's time-stamp.) So far, so good - so what?!!
This part is optional, if you don't need the version encoded into the binary. Create a .rc file, e.g.:
#include "build.h"
1 VERSIONINFO
FILEFLAGS 32
FILEVERSION 1, 0, BUILD, 0
PRODUCTVERSION 1, 0, BUILD, 0
FILEOS 4
FILETYPE 1
{
BLOCK "StringFileInfo"
{
BLOCK "040904B0"
{
VALUE "FileDescription", "program"
VALUE "OriginalFilename", "program.exe"
VALUE "CompanyName", "you"
VALUE "FileVersion", "Release"
VALUE "LegalCopyright", "Copyright (c) 2016, you, fool!"
VALUE "ProductName", "Yer proggie"
VALUE "ProductVersion", "Release"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0409, 0x04B0
}
}
A more full-blown version is available here: Versioning DLLs. BTW: It won't work without the VarFileInfo block. This .rc is used for stuff like right-clicking and getting this info in Properties | Details. I have both a M$ .rc file for this info and the app icon, and add other resources in Qt Creator under Resources.
Not so optional: Here's the part I've spent some time hacking to find. In Qt Creator, with yer proj opened, click the little computer icon and put it in release mode. Click on "Projects". Click on "Add Build Step", choose Custom Process Step, and click the hat icon "^" until it is at the top of the list. Say you've named yer .rc, "myapp.rc". Make tha build step read as follows:
Command: cmd.exe
Arguments:/c build_inc.bat
Working Directory: %{CurrentProject:Path}
While a qmake-based version might work well from the command line or command line tools called from an IDE, in Qt Creator, the build steps are preferable, I believe. Qt Creator doesn't actually run qmake for each build; but build steps are run every build.
Now, add this to yer .pro file:
RC_FILE += myapp.rc
Also, add myapp.rc to yer proj. It'll show up under "Other Files".
Now rebuild. Every rebuild will trigger a touch of the resource file, thereby running "rc" every time. Otherwise, the build number won't get encoded into the binary right. It runs quickly for me. Every rebuild will increment this number. I've only bothered to add them to the "Release" build; so debug builds don't increment this. They'll just use the number of the last build. You will need to run it once in release to avoid an error, I believe. This works without separately re-running qmake each time in Qt Creator; and gives you a different build number each time. It doesn't trigger any other recompiles. You have the overhead of running "rc" and linking each time, as opposed to doing nothing if everything is up to date; but OTOH, I do it for release builds only; you almost always link for a build or run anyway; and again, "rc" is fast.
Optional: You can move the BUILD preprocessor symbol wherever you want in yer vers. #. (Note: You can also add yer app icon with something like this:
IDI_ICON1 ICON DISCARDABLE "Icons/myicon.ico"
This makes it show up in Explorer even before the file is run.)
You can also add "build.h" to yer proj formally in Qt Creator, include it in a file you want to use the build # in, and use it as a string, e.g. with:
#include <QDebug>
#include "build.h"
#define STR_EXPAND(tok) #tok
#define STR(tok) STR_EXPAND(tok)
qDebug() << QString("(build ")+STR(BUILD)+")";
I just noticed a side effect: If you do it this way, it will rebuild before every run in Release. I guess that's not too bad a price to pay. I guess I can always copy the runtimes into the release directory, and run it from Explorer; or just put up with the extra compile of my about.h, the run of "rc" and the link with each run in release. For that matter, I could just create an external tool to run it with a keyboard shortcut. I'm certainly open to any improvements on this. For the time being, I'm not bothering, as just compiling "about.cpp", running "rc" and linking with every run doesn't take very long. Still, people: automatic build numbers!
☮!
Edit: Optional: In order to get it to increment the build number only when you build or rebuild your project, but not when you run it (even though a build will always occur in Release), go to Projects | Build and Run | Run, click "Add a Deploy Step" and choose "Custom Process Step":
Command: cmd.exe
Arguments: /c if exist build.old copy /y build.old build.txt
Working Directory: %{CurrentProject:Path}
Then, add
copy /y build.txt build.old
after #echo off in the .bat file. It is even possible, although involved, to make custom new project templates: Extending Qt Creator Manual
Edit: I've now made it work with one, not two, custom build steps.