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

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

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

Documentation error "qdoc can't run; no project set in qdocconf file"

I am trying to generate documentation for my code using QDoc. qtdoc command is already in my environment variable path. But when I try to run the command in the root directory of the project (qdocconf file also resides in project root),
qdoc projectname.qdocconf
I get the following error
qt.qdoc: "qdoc can't run; no project set in qdocconf file"
Here is my projectname.qdocconf file.
headers.fileextensions = "*.h *.hpp"
sources.fileextensions = "*.cpp *.qml *.qdoc"
outputdir = Documentation/Code
headerdirs += Code
sourcedirs += . \
Code
exampledirs = .
imagedirs += ./Images/icons \
./Images/logos
I have commented on my class functions as described in the documentation using the format
/*!
* \fn void inlineFunction()
*
* Some info here...
*/
Can you point me what am I doing wrong?
Also, can I create the documentation using QtCreator instead of running the command in terminal?
Well somehow I figured out that you need to add the following line in your .qdocconf file
project = YourProjectName
which is not present in the minimum qdocconf file presented in https://doc.qt.io/qt-5/qdoc-minimum-qdocconf.html. Even though the above issue was resolved, a lot of other issues were encountered such as:
While compiling, qt.qdoc: No include paths passed to qdoc; guessing reasonable include paths. For this you have to manually include all the source paths. Read: https://bugreports.qt.io/browse/QTBUG-67289
Some comment tags, e.g. \return, \param, present in QtCreator are not recognized by QDoc
Option 2
Alternatively, look for Doxygen which is much easier to use and generate documents with a simple to use GUI. It also recognizes all the comment tags in QtCreator.
Update:
Doxygen plugins for Qt Creator doesn't work anymore as the support has expired. Use Doxygen GUI directly.

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.

configure qmake for install headers to different subfolders

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," ",)

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