如何使用qmake将文件从项目复制到输出目录?
我正在编译Linux,但将来我会在Mac和Windows上编译它 .
在qmake用于config features的路径之一中创建文件 copy_files.prf . 该文件应如下所示:
copy_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}
How it works
第一部分定义了extra compiler,它将从 COPY_FILES 变量中读取输入文件名 . 下一部分定义了它将用于合成与每个输入相对应的输出文件名的函数 . 然后我们定义用于调用此"compiler"的命令,具体取决于我们所处的shell类型 .
COPY_FILES
然后我们定义一个extra makefile target copy_files.cookie ,它取决于目标 compiler_copy_files_make_all . 后者是qmake为我们在第一步中定义的额外编译器生成的目标的名称 . 这意味着当构建 copy_files.cookie 目标时,它将调用额外的编译器来复制文件 .
copy_files.cookie
compiler_copy_files_make_all
我们指定要由此目标运行的命令,该命令将 touch 文件 copy_files.cookie 和 compiler_copy_files_make_all . 通过触摸这些文件,我们确保 make 不会再次尝试复制文件,除非它们的时间戳比触摸的文件更新 . 最后,我们将 copy_files.cookie 添加到 make all 目标的依赖项列表中 .
touch
make
make all
How to use it
在 .pro 文件中,将 copy_files 添加到 CONFIG 变量:
.pro
copy_files
CONFIG
CONFIG += copy_files
然后将文件添加到 COPY_FILES 变量:
COPY_FILES += docs/*.txt
如果使用make install,则可以使用INSTALLS variable of qmake . 这是一个例子:
images.path = $${DESTDIR}/images images.files += images/splashscreen.png images.files += images/logo.png INSTALLS += images
然后执行 make install .
make install
作为Jake's answer和@Phlucious评论的补充,可以使用qmake defineReplace 函数,该函数适用于此用例 . 在使用提供的示例后,我遇到了一个问题,其中qmake跳过了我添加的最后一个帖子链接操作 . 这可能是变量导出的问题,尽管内容看起来一直很好 . 长话短说,这里是修改后的代码
defineReplace
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_LINK以获得更大的灵活性 .
您可以使用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
首先定义下面的某个地方(来自 XD 框架):
XD
# -------------------------------------- # 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(copy) { #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 copy($$PWD/myfile1.txt, $$DESTDIR/myfile1.txt) copy($$PWD/README.txt, $$DESTDIR/README.txt) copy($$PWD/LICENSE, $$DESTDIR/LICENSE) copyDir($$PWD/redist, $$DESTDIR/redist) #copy "redist" folder to "$$DESTDIR"
并注意在链接完成之前应复制所有文件
我发现我必须修改sje397给出的答案 . for Qt5 Beta1 和 QtCreator 2.5.2 . 我使用此脚本将qml文件复制到目标目录,作为构建完成后的添加步骤 .
我的.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_WIN将源文件的完整路径提供给copy命令 .
以下是我们其中一个项目的示例 . 它显示了如何将文件复制到Windows和Linux的 DESTDIR .
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)) } }
首先,定义以下两个函数以支持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)
8 回答
在qmake用于config features的路径之一中创建文件
copy_files.prf
. 该文件应如下所示:How it works
第一部分定义了extra compiler,它将从
COPY_FILES
变量中读取输入文件名 . 下一部分定义了它将用于合成与每个输入相对应的输出文件名的函数 . 然后我们定义用于调用此"compiler"的命令,具体取决于我们所处的shell类型 .然后我们定义一个extra makefile target
copy_files.cookie
,它取决于目标compiler_copy_files_make_all
. 后者是qmake为我们在第一步中定义的额外编译器生成的目标的名称 . 这意味着当构建copy_files.cookie
目标时,它将调用额外的编译器来复制文件 .我们指定要由此目标运行的命令,该命令将
touch
文件copy_files.cookie
和compiler_copy_files_make_all
. 通过触摸这些文件,我们确保make
不会再次尝试复制文件,除非它们的时间戳比触摸的文件更新 . 最后,我们将copy_files.cookie
添加到make all
目标的依赖项列表中 .How to use it
在
.pro
文件中,将copy_files
添加到CONFIG
变量:然后将文件添加到
COPY_FILES
变量:如果使用make install,则可以使用INSTALLS variable of qmake . 这是一个例子:
然后执行
make install
.作为Jake's answer和@Phlucious评论的补充,可以使用qmake
defineReplace
函数,该函数适用于此用例 . 在使用提供的示例后,我遇到了一个问题,其中qmake跳过了我添加的最后一个帖子链接操作 . 这可能是变量导出的问题,尽管内容看起来一直很好 . 长话短说,这里是修改后的代码这种通用复制功能可以被像这样的一些便利功能使用
第二个只接受一个参数(一个或多个文件)并提供固定路径 . 与参考答案几乎相同 .
但现在请注意调用差异
如您所见,您可以将返回的命令附加到QMAKE_PRE_LINK以获得更大的灵活性 .
您可以使用qmake函数来重用:
然后使用如下:
首先定义下面的某个地方(来自
XD
框架):并在您的项目中使用它,如:
并注意在链接完成之前应复制所有文件
我发现我必须修改sje397给出的答案 . for Qt5 Beta1 和 QtCreator 2.5.2 . 我使用此脚本将qml文件复制到目标目录,作为构建完成后的添加步骤 .
我的.pro文件包含以下代码
}
请注意,我使用$$ PWD_WIN将源文件的完整路径提供给copy命令 .
以下是我们其中一个项目的示例 . 它显示了如何将文件复制到Windows和Linux的
DESTDIR
.首先,定义以下两个函数以支持Windows / Unix .
然后,您可以使用以下代码调用之前定义的函数将文件复制到特定文件夹,并在必要时创建目录 . 这是在Win32下测试的,欢迎Linux测试 .