QMake - how to copy a file to the output
Solution 1
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 2
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 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
Raphael
I've been programming professionally for the past 9 years. Currently, my speciality is iOS development (though I still dwell in the backend world from time to time using Node or Python). I've been using Swift since it was first released in 2014 and the app that I've worked on for the past 3 years (Hole19) has been consistently rated 5 stars, with 99% of crash-free users and it was often featured on the App Store. On behalf of Hole19, I have attended WWDC 2016 in San Francisco. Before working on Hole19, I worked on a few consulting agencies and had extensive freelancing experience. Over the years, I have developed several mobile and web apps both big and small.
Updated on July 18, 2022Comments
-
Raphael almost 2 years
How can I copy a file from my project to the output directory with qmake?
I'm compiling on Linux but in the future I'll compile it on Mac and Windows.
-
Logan about 12 yearsJust a note: I used
$$OUT_PWD
instead of$$DESTDIR
to make it work. For reference$$OUT_PWD
is the folder that the program is built to, and$$PWD
is the folder that the program is Being built from -in other words it's where the .pro file is. -
Horst Walter almost 12 yearsCan I somehow always automatically call 'make install' in QT Creator whenever I build? I like this platform independent approach, but want some (few) files always being copied whenever I build in QT Creator.
-
Caleb Huitt - cjhuitt almost 12 years@HorstWalter: Look into the QMAKE_POST_LINK variable. You can define a custom command to be executed. Notably, however, it says that some backends don't support it, so I don't know how cross-platform it would be. If the files are always around, you could also make a custom target and make the resulting executable file depend on the custom target, which would copy those files.
-
Cuadue over 9 yearsHow can this be correct? On Linux Qt5.2.0
$${DESTDIR}
expands to the empty string. The path to${FILE}
is relative to the build directory, not to the source directory. -
Phlucious almost 9 yearsWhy does this have
defineTest
instead ofdefineReplace
? I couldn't get qmake to build this withdefineReplace
but I don't understand why. The docs say that "This type of function should be used in conditional expressions only" which is not true in this case. -
jkj yuio almost 8 yearsYes. worth having the version with destination directory. I needed this too since DESTDIR is not always set.
-
Ross Rogers over 7 yearsI ran into weird formatting problems with the MinGW platform when more than one file was copied. I had to modify the
QMAKE_POST_LINK
line toQMAKE_POST_LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DDIR)$$escape_expand(\\n\\t\\n\\t)
The multiple newlines were necessary because a windows path may end in `\`, but that escapes the line and makes it continue to the next. -
retif about 6 yearsNice function, although (with Qt 5.11) I had to replace
$$quote
with$$shell_quote
and$$DESTDIR
with$$OUT_PWD
. -
phyatt over 5 yearsAmazing! Thank you for posting.
$(COPY_DIR)
is pretty painful to inject without this. -
phyatt over 5 yearsFor modern Qt builds (5.6+) try looking at @Oktalist 's answer below. It uses
CONFIG += file_copies
and is really clean. -
brld almost 4 yearsI don't know why finding this was like finding a needle in a haystack but save yourself the trouble and use this method--it should be the accepted answer.
-
user3405291 over 3 yearsFor some reason it didn't work for me, not sure why. I'm using Qt 5.12.9 ...
-
Valimo Ral over 3 yearsThanks, works very well, save my day, use with qt5.14.2 and qt 5.15.2
-
aatwo over 3 yearsThis worked well for me, no modifications required (Qt 6.0.1). As a long time Qt user I find it bizarre how hard it is to perform simple operations with QMake. It's barely better than CMake.