web-dev-qa-db-fra.com

QMake - comment copier un fichier dans la sortie

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.

40
Raphael

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

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
47
Jake Petroules

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.

13

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
3
Oktalist

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.

3
eatyourgreens

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 .

1
Oktalist

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é.

1
maxik

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é

0
Top-Master

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)
0
lygstate