Xavier Bigand
Xavier Bigand

Reputation: 347

How to force synchronisation between qbs products with dependencies?

I have a Project with multiple products, some of them are depending about generated code (cpp and hpp files). This generated code is it self depending about the code_generator product that is a CppApplication.

I want that the code_generator to be rebuilt if his sources changed, and then always run. It will modify the output files only if they change (it internally generate them in a temporary folder and check changes with checksum before moving them to the right place). Then once files are generated the compilation of other products can start.

My issue is that the StaticLibrary in which I put the generated files start to be build before the code_generator.exe is built. And other products that are depending on the StaticLibrary can also start to be build before the .hpp files are generated.

So my question is: is there some mechanisms that can be used to make a product waiting until a particular dependency is completely built?

I am open to any kind of solution, the generated code can be in any kind of Module, I just tried with a StaticLibrary as it seems more convenient.

PS: The code_generator product generated a lot of files and take few inputs that I didn't precise in the qbs as it can always run and it can be considered as an input itself as it can change. This is why I am not sure that using Rule is really interesting for me.

Here is an extract of my qbs file:

    CppApplication
    {
        name: "code_generator"

        consoleApplication: true

        files: [
            "../sources/code_generator/code_generator.cpp",
            "../sources/code_generator/code_generator.hpp",
            ...
        ]

        Depends { name: "default-cpp-configuration" }
        Depends { name: "tinyxml2" }

        destinationDirectory: "../" // @Warning we move the binary to ease his usage by the "generated_code" module
    }

    StaticLibrary    // @Warning as static library to build those sources only once
    {
        name: "generated_code"

        Depends { name: "default-cpp-configuration" }
        Depends { name: "code_generator" }

        Rule {
            multiplex: true
            alwaysRun: true
//            inputs: [project.buildDirectory + "/../code_generator.exe"]

            Artifact { filePath: "generated/common/directx/driver_call_table.cpp"; fileTags: "cpp" }
            Artifact { filePath: "generated/common/directx/driver_call_table.hpp"; fileTags: "hpp" }
            Artifact { filePath: "generated/common/directx/d3d11.def"; fileTags: "def" }
            Artifact { filePath: "generated/common/directx/uuid_helpers.cpp"; fileTags: "cpp" }
            Artifact { filePath: "generated/common/directx/uuid_helpers.hpp"; fileTags: "hpp" }


            prepare: {
                var code_generator_path = project.buildDirectory + "/../code_generator.exe";

                var cmd = new Command(code_generator_path, ["DirectX", "Outdir=${GENERATED_SOURCES_PATH}", "Indir=${CMAKE_SOURCE_DIR}/lib/specs", "CompilerPath=${CMAKE_CXX_COMPILER}", "--preprocess"]);
                cmd.description = "generating sources";
                return cmd;
            }
        }
    }

    CppApplication
    {
        name: "client"

        consoleApplication: true

        files: [
            "../sources/client/main.cpp",
        ]

        Depends { name: "default-cpp-configuration" }
        Depends { name: "generated_code" }
        Depends { name: "openssl" }
    }

Upvotes: 2

Views: 175

Answers (1)

Christian Kandeler
Christian Kandeler

Reputation: 831

Product dependencies just make the product's artifacts available in the depending product's rules. They do not cause synchronization by themselves. Synchronization happens on the artifact level; otherwise, parallelization would be hindered. Your problem is that your rule does not state that it depends on the code generator executable. Here's what it should look like (untested):

Rule {
    multiplex: true
    inputsFromDependencies: "application" // These are tags, not paths!
    Artifact { 
        filePath: "generated/common/directx/driver_call_table.cpp"
        fileTags: "cpp" 
    }
    Artifact { 
      filePath: "generated/common/directx/driver_call_table.hpp"
      fileTags: "hpp" 
    }
    Artifact { 
      filePath: "generated/common/directx/d3d11.def"
      fileTags: "def" 
    }
    Artifact { 
        filePath: "generated/common/directx/uuid_helpers.cpp"
        fileTags: "cpp" 
    }
    Artifact { 
        filePath: "generated/common/directx/uuid_helpers.hpp"
        fileTags: "hpp" 
    }
    prepare: {
        var code_generator_path = inputs.application[0].filePath;
        var args = [
            "DirectX", "Outdir=${GENERATED_SOURCES_PATH}", 
            "Indir=${CMAKE_SOURCE_DIR}/lib/specs", 
            CompilerPath=${CMAKE_CXX_COMPILER}", "--preprocess"
        ];
        var cmd = new Command(code_generator_path, args);
        cmd.description = "generating sources";
        return cmd;
    }
}

Upvotes: 2

Related Questions