QMake - how to copy a file to the output
Solution 1:
You can use a qmake function for reusability:
# Copies the given files to the destination directory
defineTest(copyToDestdir) {
files = $$1
for(FILE, files) {
DDIR = $$DESTDIR
# Replace slashes in paths with backslashes for Windows
win32:FILE ~= s,/,\\,g
win32:DDIR ~= s,/,\\,g
QMAKE_POST_LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DDIR) $$escape_expand(\\n\\t)
}
export(QMAKE_POST_LINK)
}
then use it as follows:
copyToDestdir($$OTHER_FILES) # a variable containing multiple paths
copyToDestdir(run.sh) # a single filename
copyToDestdir(run.sh README) # multiple files
Solution 2:
Here's an example from one of our projects. It shows how to copy files to the DESTDIR
for Windows and Linux.
linux-g++{
#...
EXTRA_BINFILES += \
$${THIRDPARTY_PATH}/gstreamer-0.10/linux/plugins/libgstrtp.so \
$${THIRDPARTY_PATH}/gstreamer-0.10/linux/plugins/libgstvideo4linux2.so
for(FILE,EXTRA_BINFILES){
QMAKE_POST_LINK += $$quote(cp $${FILE} $${DESTDIR}$$escape_expand(\n\t))
}
}
win32 {
#...
EXTRA_BINFILES += \
$${THIRDPARTY_PATH}/glib-2.0/win32/bin/libglib-2.0.dll \
$${THIRDPARTY_PATH}/glib-2.0/win32/bin/libgmodule-2.0.dll
EXTRA_BINFILES_WIN = $${EXTRA_BINFILES}
EXTRA_BINFILES_WIN ~= s,/,\\,g
DESTDIR_WIN = $${DESTDIR}
DESTDIR_WIN ~= s,/,\\,g
for(FILE,EXTRA_BINFILES_WIN){
QMAKE_POST_LINK +=$$quote(cmd /c copy /y $${FILE} $${DESTDIR_WIN}$$escape_expand(\n\t))
}
}
Solution 3:
Qt 5.6 added this as an undocumented feature:
CONFIG += file_copies
Invent a name to describe the files you want to copy:
COPIES += myDocumentation
List the files that you want to copy, in its .files
member:
myDocumentation.files = $$files(text/docs/*.txt)
Specify the destination path in the .path
member:
myDocumentation.path = $$OUT_PWD/documentation
Optionally specify a base path to be trimmed from the source paths:
myDocumentation.base = $$PWD/text/docs
It basically works by doing the same things as many of the other answers here. See file_copies.prf for the gory details.
The interface is very similar to that for INSTALLS
.
Solution 4:
If you use make install, you can use the INSTALLS variable of qmake. Here is an example:
images.path = $${DESTDIR}/images
images.files += images/splashscreen.png
images.files += images/logo.png
INSTALLS += images
then execute make install
.
Solution 5:
Create a file copy_files.prf
in one of the paths which qmake uses for config features. The file should look like this:
QMAKE_EXTRA_COMPILERS += copy_files
copy_files.name = COPY
copy_files.input = COPY_FILES
copy_files.CONFIG = no_link
copy_files.output_function = fileCopyDestination
defineReplace(fileCopyDestination) {
return($$shadowed($$1))
}
win32:isEmpty(MINGW_IN_SHELL) {
# Windows shell
copy_files.commands = copy /y ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
TOUCH = copy /y nul
}
else {
# Unix shell
copy_files.commands = mkdir -p `dirname ${QMAKE_FILE_OUT}` && cp ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
TOUCH = touch
}
QMAKE_EXTRA_TARGETS += copy_files_cookie
copy_files_cookie.target = copy_files.cookie
copy_files_cookie.depends = compiler_copy_files_make_all
win32:!mingw {
# NMake/MSBuild
copy_files_cookie.commands = $$TOUCH $** && $$TOUCH $@
}
else {
# GNU Make
copy_files_cookie.commands = $$TOUCH $< && $$TOUCH $@
}
PRE_TARGETDEPS += $${copy_files_cookie.target}
How it works
The first part defines an extra compiler which will read input filenames from the COPY_FILES
variable. The next part defines the function which it will use to synthesize an output filename corresponding to each input. Then we define the commands used to invoke this "compiler", depending on which kind of shell we are in.
Then we define an extra makefile target copy_files.cookie
, which depends on the target compiler_copy_files_make_all
. The latter is the name of the target which qmake generates for the extra compiler we defined in the first step. This means that when the copy_files.cookie
target is built, it will invoke the extra compiler to copy the files.
We specify a command to be run by this target, which will touch
the files copy_files.cookie
and compiler_copy_files_make_all
. By touching these files, we ensure that make
will not try to copy the files again unless their timestamps are more recent than the touched files. Finally, we add copy_files.cookie
to the list of dependencies of the make all
target.
How to use it
In your .pro
file, add copy_files
to the CONFIG
variable:
CONFIG += copy_files
Then add the files to the COPY_FILES
variable:
COPY_FILES += docs/*.txt