【问题标题】:PRE_TARGETDEPS fails when using parallel builds使用并行构建时 PRE_TARGETDEPS 失败
【发布时间】:2018-05-29 12:06:58
【问题描述】:

我正在使用自定义资源管理(代替 qrc),我正在尝试将其集成到 QtCreaor。

我有一个 Python 脚本,可以生成要编译的源文件。我使用QMAKE_EXTRA_TARGETS/PRE_TARGETDEPS 告诉QMake,这个脚本必须在文件编译之前执行。所以我这样做了,在我的专业文件中:

CONFIG += ordered

generated_file.target   = my_custom_target
generated_file.commands = echo "Generating..." && d:/dev/vobs_ext_2015/tools_ext/python/Python34_light/python.exe $$PWD/pyc_res_generator.py -o $$PWD/generated/generated.cpp && echo "Generated!"
generated_file.depends  = FORCE

QMAKE_EXTRA_TARGETS            += generated_file

PRE_TARGETDEPS                 += my_custom_target

SOURCES                        += generated/generated.cpp

#DEPENDPATH = ./generated

pyc_res_generator.py 只是:

#! /usr/bin/env python
# -*- coding: utf8 *-*

import argparse

parser = argparse.ArgumentParser(description="", formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-o", type=str, help="Output file name")

args = parser.parse_args()

with open(args.o, 'w') as output_file:
    output_file.write( "// This is valid C++!" )

为了测试这一点,我在 generated.cpp 中编写了一些无效的 C++(如 fjkfkfk)。当我编译(目标是Android)时,我在日志中看到:

echo Generating... && python.exe pyc_res_generator.py -o generated/generated.cpp && echo Generated!
Generating... 
B:\Android\android-ndk-r11b/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ -c -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -DANDROID -Wa,--noexecstack -fno-builtin-memmove -std=c++11 -g -g -marm -O0 -fno-omit-frame-pointer -Wall -Wno-psabi -W -D_REENTRANT -fPIC -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I..\TestQt -I. -IB:\QtCreator5_6_1\5.6\android_armv7\include -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtWidgets -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtGui -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtCore -I. -isystem B:\Android\android-ndk-r11b\sources\cxx-stl\gnu-libstdc++\4.9\include -isystem B:\Android\android-ndk-r11b\sources\cxx-stl\gnu-libstdc++\4.9\libs\armeabi-v7a\include -isystem B:\Android\android-ndk-r11b\platforms\android-9\arch-arm\usr\include -IB:\QtCreator5_6_1\5.6\android_armv7\mkspecs\android-g++ -o main.obj ..\TestQt\main.cpp
B:\Android\android-ndk-r11b/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ -c -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -DANDROID -Wa,--noexecstack -fno-builtin-memmove -std=c++11 -g -g -marm -O0 -fno-omit-frame-pointer -Wall -Wno-psabi -W -D_REENTRANT -fPIC -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I..\TestQt -I. -IB:\QtCreator5_6_1\5.6\android_armv7\include -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtWidgets -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtGui -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtCore -I. -isystem B:\Android\android-ndk-r11b\sources\cxx-stl\gnu-libstdc++\4.9\include -isystem B:\Android\android-ndk-r11b\sources\cxx-stl\gnu-libstdc++\4.9\libs\armeabi-v7a\include -isystem B:\Android\android-ndk-r11b\platforms\android-9\arch-arm\usr\include -IB:\QtCreator5_6_1\5.6\android_armv7\mkspecs\android-g++ -o dialog.obj ..\TestQt\dialog.cpp
B:\Android\android-ndk-r11b/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ -c -Wno-psabi -march=armv7-a -mfloat-abi=softfp -mfpu=vfp -ffunction-sections -funwind-tables -fstack-protector -fno-short-enums -DANDROID -Wa,--noexecstack -fno-builtin-memmove -std=c++11 -g -g -marm -O0 -fno-omit-frame-pointer -Wall -Wno-psabi -W -D_REENTRANT -fPIC -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I..\TestQt -I. -IB:\QtCreator5_6_1\5.6\android_armv7\include -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtWidgets -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtGui -IB:\QtCreator5_6_1\5.6\android_armv7\include\QtCore -I. -isystem B:\Android\android-ndk-r11b\sources\cxx-stl\gnu-libstdc++\4.9\include -isystem B:\Android\android-ndk-r11b\sources\cxx-stl\gnu-libstdc++\4.9\libs\armeabi-v7a\include -isystem B:\Android\android-ndk-r11b\platforms\android-9\arch-arm\usr\include -IB:\QtCreator5_6_1\5.6\android_armv7\mkspecs\android-g++ -o generated.obj ..\TestQt\generated\generated.cpp
B:\QtCreator5_6_1\5.6\android_armv7\bin\moc.exe -DQT_QML_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -IB:/QtCreator5_6_1/5.6/android_armv7/mkspecs/android-g++ -IC:/Users/jp225611/Documents/TestQt -IB:/QtCreator5_6_1/5.6/android_armv7/include -IB:/QtCreator5_6_1/5.6/android_armv7/include/QtWidgets -IB:/QtCreator5_6_1/5.6/android_armv7/include/QtGui -IB:/QtCreator5_6_1/5.6/android_armv7/include/QtCore -I. -IB:\Android\android-ndk-r11b/sources/cxx-stl/gnu-libstdc++/4.9/include -IB:\Android\android-ndk-r11b/sources/cxx-stl/gnu-libstdc++/4.9/libs/armeabi-v7a/include -IB:\Android\android-ndk-r11b/platforms/android-9/arch-arm//usr/include ..\TestQt\dialog.h -o moc_dialog.cpp
..\TestQt\generated\generated.cpp:1:1: error: 'fjkfkfk' does not name a type
   // This is valid C++!
   ^
makefile:670: recipe for target 'generated.obj' failed
mingw32-make: *** [generated.obj] Error 1
mingw32-make: *** Waiting for unfinished jobs....
Generated!
13:59:08: Le processus "B:\QtCreator5_6_1\Tools\mingw492_32\bin\mingw32-make.exe" s'est terminé avec le code 2.
Erreur lors de la compilation/déploiement du projet TestQt (kit : android_armeabi-v7a)
When executing step "Make"
13:59:08: Temps écoulé : 00:03.

我看到generated\generated.cpp 是由pyc_res_generator.py 正确生成的(它现在包含// This is valid C++!)...但显然为时已晚,因为编译器看到fjkfkfk... 如您所见,输出报告:

Generating...
B:\Android\android-ndk-r11b/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ .... ..\TestQt\generated\generated.cpp
Generated...

虽然人们会期望:

Generating...
Generated...
B:\Android\android-ndk-r11b/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-g++ .... ..\TestQt\generated\generated.cpp

这仅在启用并行构建时发生(我将MAKEFLAGS 环境变量设置为'-j8`)

看起来我的自定义命令generated_file是在generated\generated.cpp编译之前启动的,但系统并没有等到它结束才真正编译generated\generated.cpp

我做错了吗?

【问题讨论】:

  • 引用:“所以如果我配置了 -j 标志,让它与其他构建作业并行运行我的脚本。这非常糟糕......”。如你所见。
  • @HansPassant:刚刚测试过,但不同的是链接的帖子正在生成一个头文件,然后DEPENDPATH 显然有帮助,就我而言,我正在生成一个源文件,我即使使用DEPENDPATH,也无法使其按预期运行。
  • 注意我填的是Qtbug bugreports.qt.io/browse/QTBUG-68553

标签: c++ qt-creator qmake


【解决方案1】:

PRE_TARGETDEPS(自定义目标)不是这里的好方法,因为generated_file.target 必须完全匹配 Makefile 目标名称,这可能因不同的选项而异:

  • 是否启用影子构建
  • 主机平台(使用斜杠或反斜杠作为文件夹分隔符)
  • 可能是针对编译器/平台的

但是,自定义编译器显然工作得更好。这就是moccing文件的完成方式。自定义编译器可以生成要编译的新文件(然后系统在编译之前等待文件生成,即使在执行并行构建时也是如此)。

# Set fuiles to be generated in a variable
TO_GENERATE = $$PWD/generated/generated.cpp

# Specify custom command output file:
custom_generator.output  = $$PWD/generated/generated.cpp
# Specify custom command:
custom_generator.commands = 'echo "Generating..." && python $$PWD/pyc_res_generator.py -o $$PWD/generated/generated.cpp && echo "Generated..."'
# dependency:
custom_generator.depends = FORCE
# link to input file variable
custom_generator.input = TO_GENERATE
# link to variable to store generated file to
custom_generator.variable_out = SOURCES
# add to qmake:
QMAKE_EXTRA_COMPILERS += custom_generator

那么,您甚至不需要指定SOURCES += $$PWD/generated/generated.cpp。而且,$$PWD/generated/generated.cpp 在清理后会被删除!

这完全符合预期!

【讨论】:

    【解决方案2】:

    您需要将目标的名称设置为它生成的文件的名称。这是一个适合我的完整项目文件(qmake 3.1,Qt 5.10.1):

    # Filename relative to the *build* directory.
    generated_file.target   = generated/generated.cpp
    generated_file.commands = 'echo "Generating..." && mkdir -p generated && echo "int main() {}" > generated/generated.cpp'
    generated_file.depends  = FORCE
    
    QMAKE_EXTRA_TARGETS     += generated_file
    
    # Filename relative to the *source* directory.
    SOURCES                 += $$OUT_PWD/generated/generated.cpp
    

    原因是generated_file.target成为Makefile中目标的名称,所以当需要generated.cpp时,会执行你的自定义规则来创建文件。

    您也可以从PRE_TARGETDEPS 中删除它,因为您已经将生成的文件添加到SOURCES instead,这会创建正确的依赖关系。

    请注意,这种方法在 build 目录中生成文件,而不是在 source 目录中。这就是为什么在将$$OUT_PWD 添加到SOURCES 时需要指定$$OUT_PWD 的原因:默认情况下,qmake 似乎假设SOURCES 是相对于源目录的。

    如果你想在 source 目录中生成它,你可能会认为你只是在任何地方加上 $$PWD 前缀,但是 qmake 有时使用绝对路径,有时使用相对路径,一切都失败了。您可能可以使用 $$absolute_path($$PWD) 解决这个问题,但我还没有尝试过。

    生成的Makefile 中的相关部分(cmets 是我的):

    # How to create generated/generated.cpp.
    # Depending on FORCE to make it always stale (fails if you create a file named FORCE :)).
    generated/generated.cpp: FORCE
        echo "Generating..." && mkdir -p generated && echo "int main() {}" > generated/generated.cpp
    
    # generated.o depends on generated/generated.cpp.
    # Note that it's not in the same directory; we don't care.
    generated.o: generated/generated.cpp 
        $(CXX) -c $(CXXFLAGS) $(INCPATH) -o generated.o generated/generated.cpp
    
    # The final executable depends on the compiled generated.o.
    OBJECTS = generated.o
    $(TARGET):  $(OBJECTS)  
        $(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
    

    qmake documentation 对此非常含糊,仅说明 target 应该是“自定义构建目标的名称。”。但是,该示例显示他们将其设置为输出文件的名称。 (作为奖励,它还展示了如何在 commands 中不重复该名称。)

    【讨论】:

    • 感谢您的帮助。但是,如果我执行generated_file.target = $$PWD/generated/generated.cpp,则不再调用自定义命令(有或没有PRE_TARGETDEPS 语句)。文件内容依然是fjkfkfk....
    • 尝试SOURCES += $$PWD/generated/generated.cpp 只是为了确保文件的位置是一致的。如果有疑问,请检查生成的Makefile
    • 我试过了。将$$PWD/generated/generated.cpp 用于generated_file.targetPRE_TARGETDEPSSOURCES:相同的行为。还尝试删除PRE_TARGETDEPS,但未调用 Python。还尝试删除 SOURCES 但随后 generated.cpp 没有被编译...所以这没有帮助,不幸的是。
    • 在 Makefile 中,我看到编译 generated/generated.cpp 和调用 python 的说明,但我没有看到在它们之间建立某种依赖关系的规则......
    • 对不起,是的,它有点复杂。更新了我的答案。
    【解决方案3】:

    另一种方法依赖于 TEMPLATE=subdirs,以在并行构建环境中尊重 libname.depends。每个应用程序文件夹中都需要两个 .pro 文件。一个在共享库文件夹中。您的开发区域中使用 TEMPLATE=subdirs 的任何其他文件夹都需要兼容。

    例如使用 LibLarry 的 TestApp。

    文件夹 TestApp 有 bld.pro 和 TestApp.pro。

    TestApp.pro:

    #This is a TEMPLATE=subdirs, which gmake will interpret;  
    # making sure the build dependencies are respected
    TEMPLATE = subdirs
    SUBDIRS += bld  mylib
    bld.file = bld.pro
    bld.depends = mylib # force library to be built first.
    mylib.file = $${PATH_TO_LIB_LARRY}/liblarry.pro
    

    bld.pro:

    TARGET=TestApp
    SOURCES+=TestApp.cpp
    PRE_TARGETDEPS+=$${PATH_TO_LIB_LARRY}/liblarry.a
    
    #boilerplate...
    QT -= gui
    CONFIG = ...
    include ($${PATH_TO_LIB_LARRY}/liblarry.pri) # contains include file info
    CONFIG += link_prl # allow lib larry to specify its position in the linker input command.
    

    文件夹 LibLarry 有 LibLarry.pro 包含

    LibLarry.pro:

    TARGET=larry
    TEMPLATE=lib
    CONFIG+=staticlib 
    CONFIG+=create_prl # export information, so apps can link correctly
    SOURCES+=my_shared_function.cpp
    include (liblarry.pri)
    

    liblarry.pri:

    HEADERS += $$PWD/my_shared_function.h
    INCLUDEPATH += $$PWD
    

    【讨论】:

      猜你喜欢
      • 2018-03-11
      • 1970-01-01
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      • 2021-11-11
      • 1970-01-01
      • 2018-10-13
      • 1970-01-01
      相关资源
      最近更新 更多