Comment copier un fichier de mon projet dans le répertoire de sortie avec qmake?
Je compile sur Linux mais à l'avenir, je le compilerai sur Mac et Windows.
Voici un exemple tiré de l'un de nos projets. Il montre comment copier des fichiers dans la DESTDIR
pour Windows et 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))
}
}
Vous pouvez utiliser une fonction qmake pour la réutilisation:
# 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)
}
puis utilisez-le comme suit:
copyToDestdir($$OTHER_FILES) # a variable containing multiple paths
copyToDestdir(run.sh) # a single filename
copyToDestdir(run.sh README) # multiple files
Si vous utilisez make install, vous pouvez utiliser la variable INSTALLS de qmake . Voici un exemple:
images.path = $${DESTDIR}/images
images.files += images/splashscreen.png
images.files += images/logo.png
INSTALLS += images
puis exécutez make install
.
Créez un fichier copy_files.prf
dans l’un des chemins que qmake utilise pour config features . Le fichier devrait ressembler à ceci:
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}
Comment ça marche
La première partie définit un extra compiler qui lira les noms de fichiers d’entrée à partir de la variable COPY_FILES
. La partie suivante définit la fonction qu’elle utilisera pour synthétiser un nom de fichier en sortie correspondant à chaque entrée. Ensuite, nous définissons les commandes utilisées pour appeler ce "compilateur", en fonction du type de Shell dans lequel nous nous trouvons.
Ensuite, nous définissons un extra makefile targetcopy_files.cookie
, qui dépend du compiler_copy_files_make_all
cible. Ce dernier est le nom de la cible que qmake génère pour le compilateur supplémentaire que nous avons défini à la première étape. Cela signifie que lorsque la cible copy_files.cookie
est construite, elle appelle le compilateur supplémentaire pour copier les fichiers.
Nous spécifions une commande à exécuter par cette cible, qui va touch
les fichiers copy_files.cookie
et compiler_copy_files_make_all
. En touchant ces fichiers, nous nous assurons que make
n'essaiera pas de les copier à nouveau à moins que leur horodatage ne soit plus récent que les fichiers touchés. Enfin, nous ajoutons copy_files.cookie
à la liste des dépendances de la cible make all
.
Comment l'utiliser
Dans votre fichier .pro
, ajoutez copy_files
à la variable CONFIG
:
CONFIG += copy_files
Ajoutez ensuite les fichiers à la variable COPY_FILES
:
COPY_FILES += docs/*.txt
J'ai trouvé que je devais modifier la réponse donnée par sje397. pour Qt5 Beta1 avec QtCreator 2.5.2 . J'utilise ce script pour copier les fichiers qml dans le répertoire de destination comme une étape supplémentaire une fois la construction terminée.
Mon fichier .pro a le code suivant
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))
}
}
Notez que j'utilise $$ PWD_WIN pour fournir le chemin complet du fichier source à la commande de copie.
Qt 5.6 ajouté ceci en tant que fonctionnalité non documentée:
CONFIG *= file_copies
Inventez un nom pour décrire les fichiers que vous souhaitez copier:
COPIES += myDocumentation
Répertoriez les fichiers que vous voulez copier, dans son membre .files
:
myDocumentation.files = $$files(text/docs/*.txt)
Spécifiez le chemin de destination dans le membre .path
:
myDocumentation.path = $$OUT_PWD/documentation
Spécifiez éventuellement un chemin de base à supprimer des chemins source:
myDocumentation.base = $$PWD/text/docs
Cela fonctionne fondamentalement en faisant les mêmes choses que beaucoup d’autres réponses ici. Voir file_copies.prf pour les détails sanglants.
L'interface est très similaire à celle de INSTALLS
.
En complément de la réponse de Jake et le commentaire @Phlucious, on peut utiliser la fonction qmake defineReplace
qui convient mieux à ce cas d'utilisation. Après avoir utilisé l'exemple fourni, j'ai rencontré un problème où qmake a ignoré la dernière action de lien de publication ajoutée. Cela pourrait être un problème avec l’exportation de la variable bien que le contenu ait plutôt bien l'air tout le temps. Longue histoire courte, voici le code modifié
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)
}
Cette fonction de copie générale peut être utilisée par certaines fonctions pratiques comme celle-ci.
defineReplace(copyToBuilddir) {
return($$copyToDir($$1, $$OUT_PWD))
}
Le second ne prend qu'un argument (un ou plusieurs fichiers) et fournit un chemin fixe. À peu près les mêmes que dans les réponses de références.
Mais notez maintenant la différence d'invocation
QMAKE_POST_LINK += $$copyToBuilddir(deploy.bat)
Comme vous pouvez le constater, vous pouvez attacher la commande renvoyée à QMAKE_PRE_LINK pour encore plus de flexibilité.
d’abord définir quelque part en dessous (qui provient du cadre 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)
}
et l'utiliser dans votre projet comme:
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"
et notez que tous les fichiers doivent être copiés avant que le lien ne soit terminé
Tout d’abord, définissez les deux fonctions suivantes pour la prise en charge de 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)
}
Ensuite, vous pouvez utiliser le code suivant pour appeler les fonctions définies précédemment afin de copier des fichiers dans un dossier spécifique, et également pour créer le répertoire si nécessaire. Ceci est testé sous Win32, les tests Linux sont les bienvenus.
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)