1

when using a Rule inside a Module with a Dependency to a Product, a FileTagger breaks the resolution of dependencies in qbs.

We have a CodeGenerator in our project which is build by the project itself. This CodeGenerator generates C++-Classes from *.asd-Files. A Product called "Core" uses that CodeGenerator to generate Classes from Core.asd Files.

I am not sure if this is a bug in qbs, but since qbs 1.8 this part of our project does not work anymore.

I created a small test project that illustrates that problem:

RuleUsesProduct.qbs

import qbs

Project {
    minimumQbsVersion: "1.8.0"

    references: [
        "Core/Core.qbs",
        "CodeGenerator/CodeGenerator.qbs"
    ]

    qbsSearchPaths: "QBS"
}

Core.qbs

import qbs

CppApplication {
    Depends { name: "Qt.core" }

    cpp.cxxLanguageVersion: "c++11"

    cpp.defines: [
    ]

    consoleApplication: true
    files: [
        "main.cpp",
        "core.asd"
    ]

    Depends{ name:"CodeGenerator"}
    Depends{ name:"CodeGeneration"}

    Group {     // Properties for the produced executable
        fileTagsFilter: product.type
        qbs.install: true
    }
}

Db2cppModule.qbs
This is indirectly included via the qbsSearchPath from RuleUsesProductTest.qbs

import qbs 1.0
import qbs.Environment
import qbs.FileInfo
import qbs.TextFile
import qbs.Process
import qbs.File

Module {

    FileTagger {
        patterns: ["*.asd"]
        fileTags: ["asd"]
    }

    Rule {
        id: dbRule
        inputs: ["asd"]

        inputsFromDependencies: ["application"]
        multiplex: true

        outputFileTags: ["cpp", "hpp"]
        outputArtifacts: {
            // dummy code that should call the CodeGenerator.exe with some parameters...
            var process = new Process();
            console.warn("# " + inputs["application"][0].filePath)
            var cmdExp = "" + inputs["application"][0].filePath;
            process.exec(cmdExp, [], false);

            return []
        }

        prepare: {
            console.warn("*" + inputs["application"][0].filePath)
            var cmdExp = "" + inputs["application"][0].filePath;
            var cmd = new Command(cmdExp, []);
            return cmd
        }
    }
}

CodeGenerator.qbs

import qbs

CppApplication {
    Depends { name: "Qt.core" }

    cpp.cxxLanguageVersion: "c++11"

    cpp.defines: [
    ]

    consoleApplication: true

    files: [
        "codegenerator.cpp"
    ]

    Group {     // Properties for the produced executable
        fileTagsFilter: product.type
        qbs.install: true
    }

}

Any help is much appreciated!

1 Answers1

2

Qbs knows two types of rules: Multiplex and non-multiplex ones. Details can be found here: https://doc.qt.io/qbs/rule-item.html. The important point for you is that non-multiplex rules invoke their prepare script once for every input. This means that in your example, the prepare script runs twice: Once for the asd input and once for the application input. The respective other inputs are not visible. This does not fit your use case, because you want to see both inputs at the same time. Therefore, you need to make your rule a multiplex rule:

multiplex: true

In the prepare script, you need to create one command for every input of type asd (unless your generator can take several inputs at once).

Rule of thumb (no pun intended): If your rule declares more than one input tag, it probably should be a multiplex rule.

  • That did the trick ! Thank you a lot Christian ! As Jake commented in the bugtracker, I guess a lot of people would love to see an Example for a CodeGenerator. – marc hüskens Jun 17 '17 at 09:21