代码之家  ›  专栏  ›  技术社区  ›  Raphael

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

  •  43
  • Raphael  · 技术社区  · 15 年前

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

    9 回复  |  直到 11 年前
        1
  •  24
  •   sje397    15 年前

    这是我们一个项目的一个例子。它显示了如何将文件复制到 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))
        }
    }
    
        2
  •  49
  •   Jake Petroules    14 年前

    您可以使用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
    
        3
  •  14
  •   NG_    7 年前

    INSTALLS variable of qmake . 下面是一个例子:

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

    然后执行 make install

        4
  •  14
  •   phyatt    7 年前

    夸脱5.6 added 这是一个未记录的功能:

    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 .

        5
  •  3
  •   eatyourgreens    13 年前

    第5季度Beta1 一起 . 我使用此脚本将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))
    }
    

    }

        6
  •  3
  •   Oktalist    10 年前

    创建文件 copy_files.prf config features . 文件应该如下所示:

    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}
    

    工作原理

    第一部分定义了 extra compiler COPY_FILES 变量。下一部分定义它将用来合成与每个输入对应的输出文件名的函数。然后我们定义用于调用这个“编译器”的命令,这取决于我们所处的shell类型。

    然后我们定义 extra makefile target copy_files.cookie ,这取决于目标 compiler_copy_files_make_all . 后者是qmake为第一步中定义的额外编译器生成的目标的名称。这意味着当 目标已生成,它将调用额外的编译器来复制文件。

    touch 文件 编译器复制所有文件 . 通过接触这些文件,我们确保 make 复制文件.cookie 到的依赖项列表 make all

    如何使用

    在你的 .pro copy_files CONFIG 变量:

    CONFIG += copy_files
    

    复制文件 变量:

    COPY_FILES += docs/*.txt
    
        7
  •  1
  •   Community Mohan Dere    9 年前

    Jake's answer 和@Phlucious评论一个人可以使用qmake defineReplace 哪个函数更适合这个用例。使用提供的示例后,我遇到了一个问题,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_LINK以获得更大的灵活性。

        8
  •  1
  •   lygstate    8 年前

    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)
    
        9
  •  1
  •   Top-Master OMG Ponies    7 年前

    首先,定义如下(它来自 XD 框架)某个地方,比如里面 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 完整脚本

    copyFileLater(source, destination) ,若要仅在生成完成后复制文件,请考虑使用以下代码(来自 除息的 Apache 2.0 许可证):

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