web-dev-qa-db-ja.com

QMake-ファイルを出力にコピーする方法

Qmakeを使用してプロジェクトから出力ディレクトリにファイルをコピーするにはどうすればよいですか?

Linuxでコンパイルしていますが、将来はMacとWindowsでコンパイルします。

44
Raphael

これが私たちのプロジェクトの例です。 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))
    }
}
23
sje397

再利用のために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
48
Jake Petroules

Make installを使用する場合、 qmakeのINSTALLS変数 を使用できます。次に例を示します。

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

次にmake installを実行します。

14

Qt 5.6 追加 これは文書化されていない機能として:

CONFIG += file_copies

コピーするファイルを説明する名前を作成します。

COPIES += myDocumentation

.filesメンバーにコピーするファイルをリストします。

myDocumentation.files = $$files(text/docs/*.txt)

.pathメンバーで宛先パスを指定します。

myDocumentation.path = $$OUT_PWD/documentation

必要に応じて、ソースパスからトリミングするベースパスを指定します。

myDocumentation.base = $$PWD/text/docs

基本的には、他の多くの回答と同じことを行うことで機能します。厄介な詳細については、 file_copies.prf を参照してください。

インターフェイスは、 INSTALLS のインターフェイスに非常に似ています。

4
Oktalist

Qmakeが config features に使用するパスの1つにファイル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}

仕組み

最初の部分は、COPY_FILES変数から入力ファイル名を読み取る extraコンパイラー を定義します。次の部分では、各入力に対応する出力ファイル名を合成するために使用する関数を定義します。次に、使用しているシェルの種類に応じて、この「コンパイラ」を呼び出すために使用するコマンドを定義します。

次に、ターゲットcopy_files.cookieに依存する extra makefile targetcompiler_copy_files_make_allを定義します。後者は、最初のステップで定義した追加のコンパイラ用にqmakeが生成するターゲットの名前です。これは、copy_files.cookieターゲットがビルドされると、追加のコンパイラーを呼び出してファイルをコピーすることを意味します。

このターゲットによって実行されるコマンドを指定します。これは、touchファイルcopy_files.cookieおよびcompiler_copy_files_make_allになります。これらのファイルに触れることにより、makeは、タイムスタンプがタッチされたファイルよりも新しい場合を除き、ファイルのコピーを再試行しないようにします。最後に、copy_files.cookieターゲットの依存関係のリストにmake allを追加します。

使用方法

.proファイルで、copy_filesCONFIG変数に追加します。

CONFIG += copy_files

次に、ファイルをCOPY_FILES変数に追加します。

COPY_FILES += docs/*.txt
3
Oktalist

Sje397で与えられた答えを修正しなければならなかったことがわかりました。 Qt5 Beta1QtCreator 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を使用して、コピーコマンドへのソースファイルへのフルパスを指定することに注意してください。

3
eatyourgreens

最初に、_functions.prf_ファイル内などのどこかで(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(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_スクリプト全体

ただし、copyFileLater(source, destination)のようなものが必要な場合は、ビルドが完了したらファイルをコピーするだけで、以下のコード(_Apache 2.0_ライセンス下のXDフレームワークから)の使用を検討してください。

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

xd_command_count = 0

#xd_prebuild(prefix, command)
defineTest(xd_prebuild) {
    #generate target name with number
    xd_command_count = $$num_add($$xd_command_count, 1)
    name = $$1$$xd_command_count
    #append command
    eval( $${name}.commands += ( \$\$2 ) );
    #the qmake generated "MakeFile" should contain "first"
    #   and we depend that on new command
    !contains( first.depends, $$name ) {
        !isEmpty(first.depends): first.depends += \\$$escape_expand(\\n)
        first.depends += $$name
    }

    QMAKE_EXTRA_TARGETS *= first $$name

    export(xd_command_count)
    export($${name}.commands)
    export(first.depends)
    export(QMAKE_EXTRA_TARGETS)

    #eval( warning(xd_Push_command: $${name}.commands += \$\${$${name}.commands}) )
}
#xd_postbuild(command)
defineTest(xd_postbuild) {
    !isEmpty(QMAKE_POST_LINK): QMAKE_POST_LINK = $$QMAKE_POST_LINK$$escape_expand(\\n\\t)
    QMAKE_POST_LINK = $${QMAKE_POST_LINK}$$quote(-$$1)

    export(QMAKE_POST_LINK)
}
#xd_escape(path)
#   resolves path like built-in functions (i.e. counts input relative to $$PWD)
defineReplace(xd_escape) {
    1 = $$absolute_path($$1)
    #using "Shell_path()" to correct path depending on platform
    #   escaping quotes and backslashes for file paths
    1 = $$Shell_path($$1)
    return($$quote($$1))
}

#copyFile(source, destination)
#   this will both copy and rename "source" to "destination", However like "copy_file()":
#       if "destination" is path to existing directory or ends with slash (i.e. "/" or "\\"),
#       will just copy to existing "destination" directory without any rename
#
#   note: this is executed before build, but after qmake did exit
#       so use "copy_file(...)" instead if the output file is required in qmake script
#       like for example if "write_file(...)" is called on the output...
defineTest(copyFile) {
    #note that "$(COPY_FILE)" is generated by qmake from "$$QMAKE_COPY_FILE"
    xd_prebuild(xd_copyfile, $(COPY_FILE) $$xd_escape($$1) $$xd_escape($$2) || echo copyFile-failed)
}

#copyFileLater(source, destination = $(DESTDIR))
#   note: this is executed after build is done, hence the name copy-later
defineTest(copyFileLater) {
    destDir = $$2
    isEmpty(destDir): destDir = $(DESTDIR)
    #append copy command
    xd_postbuild($(COPY_FILE) $$xd_escape($$1) $$xd_escape($$destDir) || echo copyFileLater-failed)

    #!build_pass:warning(copyFile: $$1 to: $$destDir)
}

#copyDir(source, destination)
defineTest(copyDir) {
    xd_prebuild(xd_copydir, $(COPY_DIR) $$xd_escape($$1) $$xd_escape($$2) || echo copyDir-failed)
}
#copyDirLater(source, destination = $(DESTDIR))
#   note: this is executed after build is done, hence the name copy-later
defineTest(copyDirLater) {
    destDir = $$2
    isEmpty(destDir): destDir = $(DESTDIR)
    #append copy command
    xd_postbuild($(COPY_DIR) $$xd_escape($$1) $$xd_escape($$destDir) || echo copyDirLater-failed)

    #!build_pass:warning(copyFile: $$1 to: $$destDir)
}

#makeDir(destination)
defineTest(makeDir) {
    xd_prebuild(xd_makedir, $(MKDIR) $$xd_escape($$1) || echo makeDir-failed: \"$$1\")
}
defineTest(makeDirLater) {
    xd_postbuild( $(MKDIR) $$xd_escape($$1) || echo makeDirLater-failed )
    #!build_pass:warning(makeDirLater: $$1)
}

defineTest(deleteFile) {
    xd_prebuild(xd_delfile, $(DEL_FILE) $$xd_escape($$1) || echo deleteFile-failed)
}
defineTest(deleteFileLater) {
    xd_postbuild( $(DEL_FILE) $$xd_escape($$1) || echo deleteFileLater-failed )
    #!build_pass:warning(deleteFileLater: $$1)
}
defineTest(deleteDir) {
    xd_prebuild(xd_delfile, $(DEL_DIR) $$xd_escape($$1) || echo deleteDir-failed)
}
defineTest(deleteDirLater) {
    xd_postbuild( $(DEL_DIR) $$xd_escape($$1) || echo deleteDirLater-failed )
    #!build_pass:warning(deleteFileLater: $$1)
}

#qmakeLater(qmake-script-file-path-to-run)
#   note that inside the script runned by this method
#   $$OUT_PWD will be same as original $$OUT_PWD of qmakeLater(...) caller project
#   since there is the "Makefile" that executes our custom qmake
defineTest(qmakeRun) {
    xd_postbuild( $(QMAKE) $$xd_escape($$1) -r -spec \"$$Shell_path($$QMAKESPEC)\" )
    #!build_pass:warning(qmakeLater: $$1)
}
defineTest(qmakeLater) {
    xd_postbuild( $(QMAKE) $$xd_escape($$1) -r -spec \"$$Shell_path($$QMAKESPEC)\" )
    #!build_pass:warning(qmakeLater: $$1)
}
_
1
Top-Master

Jake's answer および@Phluciousのコメントに加えて、この使用例に適したqmake defineReplace関数を使用できます。提供された例を使用した後、qmakeが最後に追加したポストリンクアクションをスキップするという問題が発生しました。コンテンツは常に非常によく見えますが、変数のエクスポートでは問題になる可能性があります。簡単に言えば、ここに修正されたコードがあります

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

2番目の引数は、1つの引数(1つ以上のファイル)のみを取り、固定パスを提供します。参考文献の回答とほぼ同じです。

しかし、呼び出しの違いに注意してください

QMAKE_POST_LINK += $$copyToBuilddir(deploy.bat)

ご覧のとおり、返されたコマンドをQMAKE_PRE_LINKに添付して、さらに柔軟性を高めることができます。

1
maxik

まず、Windows/Unixの両方をサポートするために、次の2つの関数を定義します。

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