【问题标题】:qmake extra compiler with multiple outputs per fileqmake 额外编译器,每个文件有多个输出
【发布时间】:2013-06-12 19:19:45
【问题描述】:

Undocumented qmake 中所述,我在我的 qmake 项目文件中声明了一个额外的编译器:

TEST = somefile.h

test_c.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}_1.cpp
test_c.input = TEST
test_c.commands = C:/somedir/some.exe /i ${QMAKE_FILE_IN} /o ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}_1.cpp
test_c.variable_out = SOURCES
test_c.name = MyTestC

QMAKE_EXTRA_COMPILERS += test_c

这很好用。但我也想生成一个头文件。我可以轻松地制作第二个自定义工具来解析此文件(或文件,如果 >1 将在 TEST 中),但我不想将每个文件解析两次。我试过了:

test_c.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}_1.cpp \
    ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}_2.cpp

只是为了测试额外的编译器每次运行可以生成两个文件。我预计会出现像“file somefile_2.cpp doesn't exist”这样的错误,但项目编译没有错误,第二个输出文件被忽略。在 Makefile 中 somefile_2.cpp 不存在。

现在我在考虑两种变体:

  1. 制作一个额外的编译器来生成一个存档,所有需要的输出文件都将立即保存在其中。设置tool1.variable_out = TOOL_1_OUT,并使用toolN.input = TOOL_1_OUT 添加另外两个额外的编译器来“解压缩”存档文件(每个工具一个)并将它们附加到一些变量中。

    在这种情况下,每个输入文件将调用三个执行。这不是最优的,但至少解析器每个文件只运行一次。

  2. 使用.output_function 选项进行实验。创建一个 qmake 函数,该函数返回与 .output 现在相同的名称,但还将第二个文件名附加到 HEADERS

附:我正在使用 MinGW x32 4.7、QtCreator 2.7.1、Qt 5.1.0、C++11。

【问题讨论】:

    标签: qmake


    【解决方案1】:

    您的变体 #2 是正确的想法。这对我有用:

    defineReplace(addToHeaders) {
        source = $$1
        source_split = $$split(source, ".")
        source_without_extension = $$first(source_split)
        HEADERS += ${QMAKE_VAR_OBJECTS_DIR}$${source_without_extension}_1.h
        return(${QMAKE_VAR_OBJECTS_DIR}$${source_without_extension}_1.cpp)
    }
    defineReplace(FILE_IN_addToHeaders) {
        # qmake emits a warning unless this function is defined; not sure why.
    }
    
    TEST = somefile.h
    
    test_c.output_function = addToHeaders
    test_c.input = TEST
    test_c.commands = cp ${QMAKE_FILE_IN} ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}_1.cpp ; cp ${QMAKE_FILE_IN} ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}_1.h
    test_c.variable_out = SOURCES
    test_c.name = MyTestC
    
    QMAKE_EXTRA_COMPILERS += test_c
    

    它生成一个 Makefile,它构建 somefile_1.cpp 和 somefile_1.h,其中 somefile_1.cpp 添加到 SOURCES,somefile_1.h 添加到 HEADERS。

    【讨论】:

    • 我无法使这个变体工作。我根据需要对其进行了修改,但无法使其正常工作。我担心变体 #2,认为这是 hack。我怀疑由于自定义工具的 output_function 的返回值,qmake 可能知道第一个(file_1.cpp)依赖于源(file.h),但这不涉及第二个(file_1.h)。 Makefile 可能会在制作 file_1.h 之前尝试构建依赖于 file_1.h 的东西
    【解决方案2】:

    这工作正常(变体 #1):

    MY_COMP = src/precompiled.h \
        src/file2.h
    
    GENERATE_FOLDER = generated/
    
    # build package file
    my_build.clean = $${GENERATE_FOLDER}gen_${QMAKE_FILE_BASE}.pack
    my_build.depends = [somepath]/my_precompiler.exe
    my_build.output = $${GENERATE_FOLDER}gen_${QMAKE_FILE_BASE}.pack
    my_build.input = MY_COMP
    my_build.commands = [somepath]/my_precompiler.exe /i ${QMAKE_FILE_IN} /o $${GENERATE_FOLDER}gen_${QMAKE_FILE_BASE}.pack
    my_build.variable_out = MY_PACKAGES
    my_build.name = "package build"
    
    # unpack cpp
    my_unpack_cpp.clean = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.cpp
    my_unpack_cpp.depends = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.h
    my_unpack_cpp.output = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.cpp
    my_unpack_cpp.input = MY_PACKAGES
    my_unpack_cpp.commands = [somepath]/my_precompiler.exe /unpack cpp /i ${QMAKE_FILE_IN} /o $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.cpp
    my_unpack_cpp.variable_out = GENERATED_SOURCES
    my_unpack_cpp.dependency_type = TYPE_C
    my_unpack_cpp.name = "unpack code"
    my_unpack_cpp.CONFIG = no_link
    
    # unpack header
    my_unpack_h.clean = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.h
    my_unpack_h.output = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.h
    my_unpack_h.input = MY_PACKAGES
    my_unpack_h.commands = [somepath]/my_precompiler.exe /unpack h /i ${QMAKE_FILE_IN} /o $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.h
    my_unpack_h.variable_out = HEADERS
    my_unpack_h.name = "unpack header"
    my_unpack_h.CONFIG = no_link
    
    QMAKE_EXTRA_COMPILERS += my_build my_unpack_h my_unpack_cpp
    

    使用这种技术,每次解析的输出文件数量可能会有所不同,但对于项目中的所有文件来说可能是恒定的。

    my_precompiler 中,如果unpack 选项未保留,我将解析文件并将两个文件 (cpp + h) 构建到两个 QBuffer 中。之后我只是将构建的数据写入 QFile:

    QDataStream ds(&file);
    ds.setVersion(QDataStream::Qt_5_1);
    
    ds << qCompress(output_cpp.data(), 9);
    ds << qCompress(output_h.data(), 9);
    
    file.close();
    

    事实上,现在 qCompress 没有盈利,因为生成的文件太小而无法压缩,超过了头文件 zlib - sizeof(.pack) > size(.h + .h) 的大小。

    开箱:

    QByteArray ba;
    
    QDataStream ds(&file);
    ds.setVersion(QDataStream::Qt_5_1);
    
    ds >> ba;
    
    if(unpack != "cpp")
    {
     ds >> ba;
    }
    file.close();  
    
    ba = qUncompress(ba);
    
    file.setFileName(output);
    if(!file.open(QFile::WriteOnly | QFile::Truncate)) return 1;
    
    file.write(ba);
    file.close();
    

    生成时:

    1. 在生成的标头开头写入#include“原始标头”
    2. 在生成代码的开头写入#include“生成的标头”

    因此我设置了这个:

    my_unpack_cpp.depends = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.h
    

    所以 /unpack cpp(因此,构建)在构建所需的头文件之后执行。还有这个:

    my_build.depends = [somepath]/my_precompiler.exe
    

    设置构建的包(因此,生成的 cpp+h)取决于 my_precompiler,所以如果我修改和重建预编译器,所有将被重建。

    附:恕我直言,这些行必须在重建之前充当清洁工:

    my_build.clean = $${GENERATE_FOLDER}gen_${QMAKE_FILE_BASE}.pack
    my_unpack_cpp.clean = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.cpp
    my_unpack_h.clean = $${GENERATE_FOLDER}${QMAKE_FILE_BASE}.h
    

    但他们没有 :( 目前我忽略了这一点,但现在如果构建 .pack 失败,则使用之前构建的包文件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-27
      • 1970-01-01
      • 2015-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多