configure qmake for install headers to different subfolders - qt

I have project where header files are in different subfolders (/config/.h; /thread/.h etc)
in qt project file they are included like:
HEADERS += $$PWD/src/*.h
HEADERS += $$PWD/src/config/*.h
then install is described as simple:
headers.files = $$HEADERS
headers.path = $$INSTALL_INC_DIR/proj
some other projects that use this lib will include files from that install dir and there problem occurs - all .h files are copied to same folder, without subfolders and in code they are included with subfolders (#include <proj/config/config.h>).
Is it possible to tell qmake (or actually nmake) that when copying files keep original folder stucture?

This works for me:
headerinstall.pri:
for(header, INSTALL_HEADERS) {
path = $${INSTALL_PREFIX}/$${dirname(header)}
eval(headers_$${path}.files += $$header)
eval(headers_$${path}.path = $$path)
eval(INSTALLS *= headers_$${path})
}
at the end of your .pro file:
INSTALL_PREFIX = /tmp/installprefix
INSTALL_HEADERS = $$HEADERS
include(headerinstall.pri)

I am sure, that the currently accepted answer from 2013 was valid for the time being.
However, it did not work well for me with all the slashes and dots and colons in the $${path}. Also we have to put $$list() around a list of files nowadays to use it in a for loop.
Here is the approach I came up with. I wrote that in a *.pri file and added it to my directory structure. No need for the extra INSTALL_HEADERS variable:
for(header, $$list($$HEADERS)) {
path = $$OUT_PWD/../include/$$dirname(header)
pathname = $$replace(path,/,)
pathname = $$replace(pathname,\.,)
pathname = $$replace(pathname,:,)
file = headers_$${pathname}
eval($${file}.files += $$header)
eval($${file}.path = $$path)
INSTALLS *= $${file}
}
Note that the replacement characters may vary for you. For example, my first approach above had still problems with whitespaces in the path, so I added:
pathname = $$replace(pathname," ",)

Related

QMake 5.15 don't understand wildcard adding files [duplicate]

I have a .pro file which looks like:
SOURCES += myfolder/source1.cpp \
myfolder/source2.cpp
HEADERS += myfolder/header1.h\
myfolder/header2.h
FORMS += myfolder/form1.ui\
myfolder/form2.ui
And everything works great. However, if I try to use an asterisk to include all the files, i.e.:
SOURCES += myfolder/*.cpp
HEADERS += myfolder/*.h
FORMS += myfolder/*.ui
qmake throws a file-not-found-error:
WARNING: Failure to find: myfolder\*.cpp
[...]
:-1: error: No rule to make target `myfolder/*.cpp', needed by `release/source1.o'. Stop.
In both cases, Qt-Creator can find the files.
Is there a way to use the asterisk? It's annoying to type the files manually.
Thank you!
[EDIT: Qt 4.8.4, Windows 7, Qt-Creator 2.6.1. Sry for forgetting this thought it isnt needed.]
[EDIT: Found solution: http://qt-project.org/forums/viewthread/1127 . Thank you anyway!]
In qmake 3.0, at least, it's possible to use something like:
SOURCES = $$files(*.cpp, true)
HEADERS = $$files(*.h, true)
The true argument will cause the files function to recursively find all files matching the pattern given by the first argument.
At first, using asterisk is bad practice - despite that qmake allows it, QtCreator cannot edit such *.pro correctly on adding new, renaming or deleting file. So try to add new files with "New file" or "Add existing files" dialogs.
QMake has for loop and function $$files(directory_path: String). Also append files to SOURCES or HEADERS variable respectively.
Brief example, which adds all files, but not directories, to variable FILES (not affect build or project tree):
files = $$files($$PWD/src)
win32:files ~= s|\\\\|/|g
for(file, files):!exists($$file/*):FILES += $$file
If you want to check if file is *.cpp, try to use contains($$file, ".cpp").
files = $$files($$PWD/src)
win32:files ~= s|\\\\|/|g
for(file, files):!exists($$file/*):contains($$file, ".cpp"):SOURCES += $$file

Copy a file to build directory after compiling project with Qt

I have seen several suggestions, but nothing really worked for me as I want. I just need to copy a file to the desired destination directory.
Say, for example from this answer:
install_it.path = %{buildDir}
install_it.files += %{sourceDir}/settings.ini
INSTALLS += install_it
Variables %{buildDir} and %{sourceDir} should be defined, to make this work. Ok, there's no problem with %{sourceDir}: it is just .. But how can I get %{buildDir}?
EDIT1
Say, I have a project my_project here:
/path/to/my_project
So, release build path is this: /path/to/my_project-build-Desktop-release,
debug build path is this: /path/to/my_project-build-Desktop-debug
I have files to be copied to destination directory here: /path/to/my_project/copy_to_install_dir
So, I want all files from /path/to/my_project/copy_to_install_dir to be copied to /path/to/my_project-build-Desktop-release when I do release build. And, the same way for debug build.
I can't find variable which contain full destination path, i.e. /path/to/my_project-build-Desktop-release for debug build.
Just in case: I use Windows, but anyway I'm looking for crossplatform solution.
EDIT2
Exact solution, for future readers:
install_it.path = $$OUT_PWD
install_it.files = copy_to_install_dir/*
INSTALLS += \
install_it
The selected answer is correct but it requires to call make install, which in my opinion is annoying or error prone. Instead, to copy files to the build directory use:
copydata.commands = $(COPY_DIR) $$PWD/required_files $$OUT_PWD
first.depends = $(first) copydata
export(first.depends)
export(copydata.commands)
QMAKE_EXTRA_TARGETS += first copydata
Where required_files must be replaced with your correct path. $$PWD is the path of current .pro file, you might not require this.
Note: I found this solution here. I recommend to read the whole article as it explains how it works.
Having had the pleasure of wasting a few hours with this, i thought i'd share my findings on the matter. This in a modified variant of Paglian's method here. Since i'm using windows (without mingw) that method doesn't work. So here is the modified variant:
# using shell_path() to correct path depending on platform
# escaping quotes and backslashes for file paths
copydata.commands = $(COPY_FILE) \"$$shell_path($$PWD\\archive.png)\" \"$$shell_path($$OUT_PWD)\"
first.depends = $(first) copydata
export(first.depends)
export(copydata.commands)
QMAKE_EXTRA_TARGETS += first copydata
Since this makes it cross platform you could of course also use this method in Linux, MacOS or what have you. Do note that i'm copying a single file, so instead of $(COPY_DIR) i'm using $(COPY_FILE). Adapt as needed.
If you want the file(s) copied to the exact path of where the binary ends up (since the binary will end up in a subfolder of $$OUT_PWD (debug or release, at least when building with Qt Creator with MSVC 14/cdb.exe/Code::Blocks Makefiles configuration) you need this:
# adapted from https://stackoverflow.com/a/2581068
CONFIG(debug, debug|release) {
VARIANT = debug
} else {
VARIANT = release
}
Beware that even though the binary ends up in a subfolder, QtCreator executes the binary from $$OUT_PWD, so it expects to find file resources in $$OUT_PWD, and NOT the debug subdir. That means you for example can't do QIcon("archive.png") and expect it to find it besides the executable.
This is of course easy to remedy by doing:
QDir exeDir(QCoreApplication::applicationDirPath());
QIcon qIcon(exeDir.filePath("archive.png"));
IF you decide this is what you want, you obviously need to edit the last argument of $$(COPY_FILE) (in .pro) like this: \"$$shell_path($$OUT_PWD)\\$$VARIANT\"
One other thing to note is that (in my case anyway) Qt Creator (4.0.1) doesn't always build the .pro file, since it's not detecting any changes in the configuration, so to have the above changes reflected in the Makefile (and thus run when you build your project) you have to actually build the .pro manually by running Build->run qmake from the application menu. To ensure everything goes smooth, look as the compile output by hitting Alt+4 (on Windows anyway).
This is what we are using in QtSerialPort:
target_headers.files = $$PUBLIC_HEADERS
target_headers.path = $$[QT_INSTALL_HEADERS]/QtSerialPort
INSTALLS += target_headers
mkspecs_features.files = $$QTSERIALPORT_PROJECT_ROOT/src/serialport/qt4support/serialport.prf
mkspecs_features.path = $$[QT_INSTALL_DATA]/mkspecs/features
INSTALLS += mkspecs_features
Basically, you set the files and path for the target, and then append that into the INSTALLS variable. What you still need is the $$OUT_PWD variable which we are also using extensively in QtSerialPort. That will provide you the root of the build directory.
It is one of those undocumented qmake features, but it is very useful.
Also, for the source directory in general at large, you should not assume "." and so forth because that may be different as you run through a wrapper application in which the "." will point to that and not what you expect: the qmake source project root. In those cases, it is safer to use the PWD variable which points to the source as opposed OUT_PWD which points to the build folder.
Just to give a rough example about the difference o those two variables with a real world scenario, here you can find what we are doing in QtSerialPort:
system("echo QTSERIALPORT_PROJECT_ROOT = $$PWD >> $$OUT_PWD/.qmake.cache")
system("echo QTSERIALPORT_BUILD_ROOT = $$OUT_PWD >> $$OUT_PWD/.qmake.cache")
where the former is the root for the source project, and the latter for the build directory. They may be the same, but in many cases they are not, e.g. when building through QtCreator just for one of those.
Maybe the following QMake code helps as a starting point. It copies the recently built binary to some other directory "TARGET_DEST":
TARGET_SRC = $${_PRO_FILE_PWD_}
TARGET_DEST = $${PWD}/src
CONFIG(debug, debug|release) {
TARGET_SRC = $${TARGET_SRC}/debug
} else {
TARGET_SRC = $${TARGET_SRC}/release
}
TARGET_SRC = $${TARGET_SRC}/$${TARGET}
TARGET_DEST = $${TARGET_DEST}/$${TARGET}
linux-g++{
if( equals(TEMPLATE, app) || equals(TEMPLATE, vcapp) ){
# nothing to do here
}
if( equals(TEMPLATE, lib) || equals(TEMPLATE, vclib) ){
TARGET_SRC = $${TARGET_SRC}.so
TARGET_DEST = $${TARGET_DEST}.so
}
QMAKE_POST_LINK += $$quote(cp $${TARGET_SRC} $${TARGET_DEST}$$escape_expand(\n\t))
}
win32 {
if( equals(TEMPLATE, app) || equals(TEMPLATE, vcapp) ){
TARGET_SRC = $${TARGET_SRC}.exe
TARGET_DEST = $${TARGET_DEST}.exe
}
if( equals(TEMPLATE, lib) || equals(TEMPLATE, vclib) ){
TARGET_SRC = $${TARGET_SRC}.dll
TARGET_DEST = $${TARGET_DEST}.dll
}
TARGET_SRC ~= s,/,\\,g # fix slashes
TARGET_DEST ~= s,/,\\,g # fix slashes
QMAKE_POST_LINK +=$$quote(cmd /c copy /y $${TARGET_SRC} $${TARGET_DEST}$$escape_expand(\n\t))
}
message("[INFO] Will copy $${TARGET_SRC} to $${TARGET_DEST}")
You can use DESTDIR and PWD qmake variables or OUT_PWD: http://qt-project.org/doc/qt-5.1/qmake/qmake-variable-reference.html#destdir
This in a modified variant of PKSWE's method.
dummyTarget.commands = #echo After building copy..
QMAKE_EXTRA_TARGETS += dummyTarget
PRE_TARGETDEPS += dummyTarget
toolsCopy.commands = $(COPY_DIR) $$shell_path($$PWD/copyDir/*) $$shell_path($$DESTDIR)
dummyTarget.depends += toolsCopy
QMAKE_EXTRA_TARGETS += toolsCopy
toolsCopyLib.commands = $(COPY_FILE) $$shell_path($$PWD/setting.ini) $$shell_path($${DESTDIR})
dummyTarget.depends += toolsCopyLib
QMAKE_EXTRA_TARGETS += toolsCopyLib
But, I have an other question, how to copy if changed? Since it takes too much time when it doesn't need to copy.

Qt - Using asterisk (*) in .pro-File with directories

I have a .pro file which looks like:
SOURCES += myfolder/source1.cpp \
myfolder/source2.cpp
HEADERS += myfolder/header1.h\
myfolder/header2.h
FORMS += myfolder/form1.ui\
myfolder/form2.ui
And everything works great. However, if I try to use an asterisk to include all the files, i.e.:
SOURCES += myfolder/*.cpp
HEADERS += myfolder/*.h
FORMS += myfolder/*.ui
qmake throws a file-not-found-error:
WARNING: Failure to find: myfolder\*.cpp
[...]
:-1: error: No rule to make target `myfolder/*.cpp', needed by `release/source1.o'. Stop.
In both cases, Qt-Creator can find the files.
Is there a way to use the asterisk? It's annoying to type the files manually.
Thank you!
[EDIT: Qt 4.8.4, Windows 7, Qt-Creator 2.6.1. Sry for forgetting this thought it isnt needed.]
[EDIT: Found solution: http://qt-project.org/forums/viewthread/1127 . Thank you anyway!]
In qmake 3.0, at least, it's possible to use something like:
SOURCES = $$files(*.cpp, true)
HEADERS = $$files(*.h, true)
The true argument will cause the files function to recursively find all files matching the pattern given by the first argument.
At first, using asterisk is bad practice - despite that qmake allows it, QtCreator cannot edit such *.pro correctly on adding new, renaming or deleting file. So try to add new files with "New file" or "Add existing files" dialogs.
QMake has for loop and function $$files(directory_path: String). Also append files to SOURCES or HEADERS variable respectively.
Brief example, which adds all files, but not directories, to variable FILES (not affect build or project tree):
files = $$files($$PWD/src)
win32:files ~= s|\\\\|/|g
for(file, files):!exists($$file/*):FILES += $$file
If you want to check if file is *.cpp, try to use contains($$file, ".cpp").
files = $$files($$PWD/src)
win32:files ~= s|\\\\|/|g
for(file, files):!exists($$file/*):contains($$file, ".cpp"):SOURCES += $$file

How to specify build directory in Qt Creator for shadow build without use of an absolute path?

Absolute paths are ridiculous. All we need - and all we are allowed, by the way - is to use a folder on the same level that the folder containing .pro file for shadow builds. There are bugs otherwise.
But you can't just specify ../mingw_debug for example. Yes, it is a relative path but relative to what? It turns out it is relative to current directory of Qt Creator, and this is completely meaningless.
%{sourceDir} is of no help either. %{sourceDir}/../mingw_debug dosen't work, at least on Windows. If there was a way to extract parent folder from sourceDir!
Does anybody know a way to solve the issue?
In Qt Creator 3.6.1 at least, this is fixed - relative paths work just fine. The resolved full path is shown in the tooltip. I don't know when in the past few years this was fixed.
Not exactly shadow builds as qt-creator defines them but I am using the following to get a neat build structure.
Excerpt from a pro-file for a library that I build for multiple targets and also
in test modes.
TARGET = ../lib/common
message("libcommon:")
contains(CONFIG,test){
message("Building Test")
DESTDIR = test
TARGET = $$TARGET-test
}else{
message("Building Program")
DESTDIR = program
TARGET = $$TARGET
}
contains(MEEGO_EDITION,harmattan){
message("Maemo Harmattan")
DESTDIR = $$DESTDIR-maemo6
TARGET = $$TARGET-maemo6
DEFINES += MAEMO MAEMO6
}
unix:!maemo5:!contains(MEEGO_EDITION,harmattan){#desktop
message("Desktop")
DESTDIR = $$DESTDIR-desktop
TARGET = $$TARGET-desktop
}
contains(CONFIG,test){
TEMPLATE = app
SOURCES += $$files(src_test/main.cpp)
HEADERS += $$files(src_test/*.h)
INCLUDEPATH += src_test
}else{
TEMPLATE = lib
CONFIG += staticlib
}
CONFIG(debug, debug|release) {
message("Debug")
DESTDIR = $$DESTDIR-debug
CONFIG += debug
DEFINES += DEBUG
TARGET = $$TARGET-debug
}else{
message("Release")
//DEFINES += QT_NO_DEBUG_OUTPUT
DESTDIR = $$DESTDIR-release
TARGET = $$TARGET-release
}
MOC_DIR = build/$${DESTDIR}/moc
OBJECTS_DIR = build/$${DESTDIR}/obj
UI_DIR = build/$${DESTDIR}/ui
So you get all your object,moc,gui files in separate directories (e.g libcommon/build/program-desktop-debug/moc) and your binaries in the same with different names. To trigger one build or another you simply set a CONFIG+= in the build target. And the best about it this structure only depends on the pro file and you can put parts of it in a common.pri and use it for all your projects. No need for shadow-build configuration anymore. By the way the pro file resides in libcommon/libcommon.pro as it should.
I'm using this code in *.pro file, it seems working fine.
CONFIG(debug, debug|release){
DESTDIR=$$shadowed($$ROOT_PWD)/debug
}else{
DESTDIR=$$shadowed($$ROOT_PWD)/release
}
There are several things that can be used to make this manageable:
$$_PRO_FILE_PWD_ (version >=4.5) variable contains the directory of the current pro file being read.
Use the .qmake.cache file in the root directory of the project, and define a variable for the directory:
PROJECT_DIR = $$PWD
Then use that to navigate around beginning from the root.

Qt Creator and conditional build

In our project, we added some source and header files if a MACRO is defined. We do this like that, in the .pro file:
contains(DEFINES, MY_DEF) {
message("Support MY_DEF")
INCLUDEPATH += \
my_include_dir
SOURCES += \
source1.cpp \
source2.cpp
HEADERS += \
my_include_dir/header1.h \
my_include_dir/header2.h
FORMS += \
myform.ui
}
This works fine during the build. The files are not compiled if MY_DEF is not defined. MY_DEF is defined like that:
DEFINES += MY_DEF
Curiously, Qt Creator always display the files in the project tree, whereas MY_DEF is defined or not. If not defined, they are not used for the build, but they still are displayed and editable, searches can scan them, etc... Is it a bug of Qt Creator?
This is not a big issue, just a little annoying, because we don't know clearly if a file is part of the project or not.
It's intentional even. There's a special "accumulating" parsing mode to collect all files that are mentioned in .pro files (essentially the same that's used to collect "translatable strings") for display in the project tree. Otherwise things like "Replace in all files in a project" would yield different results depending on the platform or the context it is run in. [And it's not half of qmake that's included, but close to all of it...]
This seems to be an issue with QtCreator and how it reads the .pro files - it doesn't seem to actually fully parse the files, opting instead to just pick out certain bits. I've got the same issue with files that are only included on one platform or another - in QtCreator, they always show up.
I expect that the reason is either that they don't want to re-implement half of qmake just to get the file lists, OR that there are situations where trying to parse it 'correctly' would get the wrong answer, and they've chosen to be predictably wrong instead of randomly wrong.
In addition to the conditional includes in QMake, I add #ifdef around such conditional source code. That way I also see it visually drop out of compilation when the conditions are not met. It's not as good as having the files drop out entirely from the project tree, but it's better than allowing them to still appear like they are part of the build when editing them if they are not applicable.
Just for the sake of completeness and answer correctness. Probably someone else needs this example of root .pro file with conditional source tree:
TEMPLATE = subdirs
SUBDIRS = device
CONFIG -= debug_and_release
_SANDBOX_DIR = $$dirname(PWD)
_PLAYER_PRO = $${_SANDBOX_DIR}/player/player.pro
SUBDIRS = device
device.subdir = $${_SANDBOX_DIR}/proxy/libproxy
contains(QMAKE_PLATFORM, android) {
unset(_PLAYER_PRO)
} else {
SUBDIRS += player
player.file = $${_PLAYER_PRO}
player.depends = device
}
SUBDIRS += app
app.subdir = $${_SANDBOX_DIR}/display/display
app.depends = device
contains(SUBDIRS, player) {
app.depends += player
}

Resources