Qt QMake-如何将文件复制到输出

Qt QMake-如何将文件复制到输出,qt,qt-creator,qmake,Qt,Qt Creator,Qmake,如何使用qmake将文件从项目复制到输出目录 我在Linux上编译,但将来我会在Mac和Windows上编译。下面是我们一个项目的一个示例。它显示了如何将文件复制到Windows和Linux的DESTDIR linux-g++{ #... EXTRA_BINFILES += \ $${THIRDPARTY_PATH}/gstreamer-0.10/linux/plugins/libgstrtp.so \ $${THIRDPARTY_PATH}/gs

如何使用qmake将文件从项目复制到输出目录


我在Linux上编译,但将来我会在Mac和Windows上编译。

下面是我们一个项目的一个示例。它显示了如何将文件复制到Windows和Linux的
DESTDIR

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))
    }
}

如果使用make install,则可以使用。以下是一个例子:

images.path    = $${DESTDIR}/images
images.files   += images/splashscreen.png
images.files   += images/logo.png
INSTALLS       += images

然后执行
makeinstall

您可以使用qmake函数实现可重用性:

# 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)
}
然后按如下方式使用:

copyToDestdir($$OTHER_FILES) # a variable containing multiple paths
copyToDestdir(run.sh) # a single filename
copyToDestdir(run.sh README) # multiple files

我发现我必须修改sje397给出的答案。对于Qt5 Beta1以及QtCreator 2.5.2。我使用此脚本将qml文件复制到目标目录,作为构建完成后的一个添加步骤

My.pro文件包含以下代码

OTHER_FILES += \
    Application.qml

# Copy qml files post build
win32 {
    DESTDIR_WIN = $${DESTDIR}
    DESTDIR_WIN ~= s,/,\\,g
    PWD_WIN = $${PWD}
    PWD_WIN ~= s,/,\\,g
    for(FILE, OTHER_FILES){
        QMAKE_POST_LINK += $$quote(cmd /c copy /y $${PWD_WIN}\\$${FILE} $${DESTDIR_WIN}$$escape_expand(\\n\\t))
    }
}
unix {
    for(FILE, OTHER_FILES){
        QMAKE_POST_LINK += $$quote(cp $${PWD}/$${FILE} $${DESTDIR}$$escape_expand(\\n\\t))
}
}


请注意,我使用$$PWD\u WIN为copy命令提供源文件的完整路径。

在qmake用于复制的路径之一中创建一个文件
copy\u files.prf
。该文件应如下所示:

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}
然后将文件添加到
COPY_files
变量:

CONFIG += copy_files
COPY_FILES += docs/*.txt
作为对和@Phlucious注释的补充,可以使用qmake
definerereplace
函数,该函数更适合此用例。使用提供的示例后,我遇到了一个问题,其中qmake跳过了我添加的最后一个post-link操作。这可能是变量导出的一个问题,尽管内容一直都很好。长话短说,这里是修改后的代码

defineReplace(copyToDir) {
    files = $$1
    DIR = $$2
    LINK =

    for(FILE, files) {
        LINK += $$QMAKE_COPY $$shell_path($$FILE) $$shell_path($$DIR) $$escape_expand(\\n\\t)
    }
    return($$LINK)
}
这个通用的复制功能可以被像这样的一些方便的功能使用

defineReplace(copyToBuilddir) {
    return($$copyToDir($$1, $$OUT_PWD))
}
第二个参数只接受一个参数(一个或多个文件),并提供固定路径。与参考答案基本相同

但现在请注意调用的差异

QMAKE_POST_LINK += $$copyToBuilddir(deploy.bat)

如您所见,您可以将返回的命令附加到QMAKE_PRE_链接以获得更大的灵活性。

首先,定义以下两个函数以支持Windows/Unix

defineReplace(nativePath) {
    OUT_NATIVE_PATH = $$1
    # Replace slashes in paths with backslashes for Windows
    win32:OUT_NATIVE_PATH ~= s,/,\\,g
    return($$OUT_NATIVE_PATH)
}

# Copies the given files to the destination directory
defineReplace(copyToDestDirCommands) {
    variable_files = $$1
    files = $$eval($$variable_files)
    DDIR = $$nativePath($$2)
    win32:DDIR ~= s,/,\\,g
    POST_LINK = echo "Copying files to $$DDIR" $$escape_expand(\\n\\t)

    win32 {
        POST_LINK += $$QMAKE_MKDIR $$quote($$DDIR) 2>&1 & set errorlevel=0 $$escape_expand(\\n\\t)
    }
    !win32 {
        POST_LINK += $$QMAKE_MKDIR -p $$quote($$DDIR) $$escape_expand(\\n\\t)
    }

    for(ORIGINAL_FILE, files) {
        FILE = $$nativePath($$ORIGINAL_FILE)
        POST_LINK += $$QMAKE_COPY $$quote($$FILE) $$quote($$DDIR) $$escape_expand(\\n\\t)
    }

    return ($$POST_LINK)
}
然后,您可以使用以下代码调用之前定义的函数,将文件复制到特定文件夹中,并在必要时创建目录。这是在Win32下测试的,欢迎使用Linux测试

BATOS_FILES = \
    $$BATOS_BIN_ROOT/batos-core.dll \
    $$BATOS_BIN_ROOT/batos-pfw.dll \
    $$BATOS_BIN_ROOT/dre.dll \
    $$BATOS_BIN_ROOT/log4qt.dll

QMAKE_POST_LINK += $$copyToDestDirCommands(BATOS_FILES, $$DESTDIR)

BATOS_PLUGINS_FILES = \
    $$BATOS_BIN_ROOT/plugins/com.xaf.plugin-manager.dll \
    $$BATOS_BIN_ROOT/plugins/org.commontk.eventadmin.dll

QMAKE_POST_LINK += $$copyToDestDirCommands(BATOS_PLUGINS_FILES, $$DESTDIR/plugins)
首先,在某个地方定义以下内容(来自
XD
framework),比如
functions.prf
文件中:

# --------------------------------------
# This file defines few useful functions
# --------------------------------------

#copyDir(source, destination)
# using "shell_path()" to correct path depending on platform
# escaping quotes and backslashes for file paths
defineTest(copyDir) {
    #append copy command
    !isEmpty(xd_copydir.commands): xd_copydir.commands += && \\$$escape_expand(\n\t)
    xd_copydir.commands += ( $(COPY_DIR) \"$$shell_path($$1)\" \"$$shell_path($$2)\" || echo \"copy failed\" )
    #the qmake generated MakeFile contains "first" and we depend that on "xd_copydir"
    first.depends *= xd_copydir
    QMAKE_EXTRA_TARGETS *= first xd_copydir

    export(first.depends)
    export(xd_copydir.commands)
    export(QMAKE_EXTRA_TARGETS)
}

#copy(source, destination) (i.e. the name "copyFile" was reserved)
defineTest(copyFile) {
    #append copy command
    !isEmpty(xd_copyfile.commands): xd_copyfile.commands += && \\$$escape_expand(\n\t)
    xd_copyfile.commands += ( $(COPY_FILE) \"$$shell_path($$1)\" \"$$shell_path($$2)\" || echo \"copy failed\" )
    #the qmake generated MakeFile contains "first" and we depend that on "xd_copyfile"
    first.depends *= xd_copyfile
    QMAKE_EXTRA_TARGETS *= first xd_copyfile

    export(first.depends)
    export(xd_copyfile.commands)
    export(QMAKE_EXTRA_TARGETS)
}
并在项目中使用它,如:

include($$PWD/functions.prf) #optional

copyFile($$PWD/myfile1.txt, $$DESTDIR/myfile1.txt)
copyFile($$PWD/README.txt, $$DESTDIR/README.txt)
copyFile($$PWD/LICENSE, $$DESTDIR/LICENSE)
copyDir($$PWD/redist, $$DESTDIR/redist) #copy "redist" folder to "$$DESTDIR"
请注意,所有文件都将在链接操作完成之前被复制(这可能很有用)

xd_functions.prf
完整脚本

但是,当您需要像<代码> CopyFieleTalter(源,目的地)< /代码>时,仅在构建完成后复制文件,然后考虑使用下面的代码(这是从<代码> XD< /COD>框架下<代码> Apache 2 许可证):

Qt 5.6这是一项未记录的功能:

CONFIG += file_copies
创建一个名称来描述要复制的文件:

COPIES += myDocumentation
在其
成员中列出要复制的文件

myDocumentation.files = $$files(text/docs/*.txt)
myDocumentation.path = $$OUT_PWD/documentation
.path
成员中指定目标路径:

myDocumentation.files = $$files(text/docs/*.txt)
myDocumentation.path = $$OUT_PWD/documentation
(可选)指定要从源路径修剪的基本路径:

myDocumentation.base = $$PWD/text/docs
它基本上是通过做与这里的许多其他答案相同的事情来工作的。有关血淋淋的详细信息,请参阅


该界面与的界面非常相似。

只需注意:我使用了
$$OUT\u PWD
而不是
$$DESTDIR
使其工作。作为参考,
$$OUT\u PWD
是生成程序的文件夹,而
$$PWD
是生成程序的文件夹-换句话说,它是.pro文件所在的文件夹。为什么它有
defineTest
而不是
definerereplace
?我无法让qmake使用
definerereplace
构建这个,但我不明白为什么。他们说“这种类型的函数应该只在条件表达式中使用”,这在本例中是不正确的。当复制了多个文件时,我在MinGW平台上遇到了奇怪的格式问题。我不得不将
QMAKE\u POST\u链接
行修改为
QMAKE\u POST\u链接+=$$QMAKE\u COPY$$quote($$FILE)$$quote($$DDIR)$$escape\u expand(\\n\\t\\n\\t)
多个换行是必需的,因为windows路径可能以“\\”结尾,但这会换行并使它继续到下一个.Nice函数,尽管如此(使用Qt 5.11)我不得不用
$$shell
替换
$$quote
,用
$$OUT\u PWD
替换
$$DESTDIR
。这对我来说很好,不需要修改(Qt 6.0.1)。作为一个长期使用Qt的用户,我发现使用QMake执行简单操作有多么困难,这很奇怪。它几乎不比CMake好。我可以在每次构建时自动调用QT Creator中的“make install”吗?我喜欢这种与平台无关的方法,但希望在QT Creator中构建时总是复制一些(少数)文件。@HorstWalter:查看QMAKE\u POST\u LINK变量。您可以定义要执行的自定义命令。然而,值得注意的是,它说一些后端不支持它,所以我不知道它会有多跨平台。如果文件始终存在,您还可以创建一个自定义目标,并使生成的可执行文件依赖于自定义目标,该目标将复制这些文件。这怎么可能是正确的?在Linux Qt5.2.0上
$${DESTDIR}
扩展为空字符串。
${FILE}
的路径是相对于生成目录的,而不是相对于源目录的。对于现代Qt生成(5.6+),请查看下面@Oktalist的答案。它使用
CONFIG+=file\u复制
,而且非常干净。是的。值得拥有具有目标目录的版本。我也需要这个,因为DESTDIR并不总是设置好的。太棒了!谢谢你的发帖
$(COPY\u DIR)
在没有这个的情况下注射是非常痛苦的。我不知道为什么找到这个方法就像大海捞针一样,但省去麻烦,使用这个方法——它应该是公认的答案。出于某种原因,它对我不起作用,不知道为什么。我正在使用Qt5.12.9…谢谢,效果很好,节省时间,使用