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