2023-02-24

Qbs tutorial part 5/5: Apps

The apps

In the last part we looked at how to select files with the group feature in Qbs , and in this last part of the series we will look at how to build our apps with src/apps.qbs.

But first our file tree as a reference:

.
├── OctoMY.qbs
├── src
│   ├── agent
│   │   ├── AgentMain.cpp
│   │   ├── AgentMain.hpp
│   │   ├── app.qbs
│   │   └── README.md
│   ├── apps.qbs
│   ├── combined
│   │   └── lib.qbs
│   ├── libs
│   │   ├── libagent
│   │   │   ├── agent
│   │   │   │   ├── Agent.cpp
│   │   │   │   ├── Agent.hpp
│   │   │   │   └── AgentWindow.ui
│   │   │   ├── lib.qbs
│   │   │   └── README.md
│   ├── libs.qbs
├── test
│   ├── common_test
│   │   ├── Common_test.hpp
│   │   ├── CommsTester.cpp
│   │   ├── CommsTester.hpp
│   │   ├── mock
│   │   │   ├── MockCourier.cpp
│   │   │   └── MockCourier.hpp
│   │   ├── resources
│   │   │   ├── icons
│   │   │   │   ├── profile.svg
│   │   │   │   ├── stress.svg
│   │   │   │   └── test.svg
│   │   │   └── test_resources.qrc
│   │   ├── Utility_test.cpp
│   │   └── Utility_test.hpp
│   ├── testLogHandler
│   │   ├── TestLogHandler.cpp
│   │   ├── TestLogHandler.hpp
│   │   └── test.qbs
│   ├── testTryToggle
│   │   ├── TestTryToggle.cpp
│   │   ├── TestTryToggle.hpp
│   │   └── test.qbs
│   └── tests.qbs
└── integration
   └── qbs
     └── imports
            ├── OctoMYApp.qbs
            ├── OctoMYLibProbe.qbs
            ├── OctoMYAutoLib.qbs
            ├── OctoMYTestProbe.qbs
            ├── OctoMYAutoTest.qbs
            ├── OctoMYFiles.qbs
            ├── OctoMYQtDepends.qbs
            └── utils.js

The final part of the puzzle is our app.qbs definition which looks like this:

OctoMYApp {
    name: "Agent"
    useCombinedLibs: true
    property string path2:path
}

Again, I hope you put two and two together to realize that OctoMYApp is defined in ./integrations/qbs/OctoMYApp.qbs and represents a reusable component that is included in all our app.qbs files for centralized management for convenience.

If we follow the white rabbit again, ./integrations/qbs/OctoMYApp.qbs looks like this:

import qbs.FileInfo

Application {
    name: "OctoMYApp"
    property string appDir: FileInfo.cleanPath(path2) + FileInfo.pathSeparator()
    property string srcDir: FileInfo.cleanPath(FileInfo.joinPaths(project.sourceDirectory, "src")) + FileInfo.pathSeparator()
    property string libsDir: FileInfo.cleanPath(FileInfo.joinPaths(srcDir, "libs")) + FileInfo.pathSeparator()
    property bool useCombinedLibs: true
    
    // Add dependency on all Qt components that we need
    OctoMYQtDepends {}

    // Add dependency on cpp
    Depends{
        name: "cpp"
    }

    // Enumerate OctoMY lib folders
    OctoMYLibProbe {
        id: octomyLibs
        searchPath: libsDir
    }

    //"QT_DISABLE_DEPRECATED_BEFORE=0x060000" // disables all the APIs deprecated before Qt 6.0.0
    // Tell cpp to look for header files in all the lib folders
    cpp.includePaths: base.concat(octomyLibs.libFolders)

    // Tell cpp all the auto-generated defines for OctoMY libraries
    cpp.defines: base.concat(octomyLibs.libDefines)

    // Tell cpp what version and stdlib we want
    cpp.cxxLanguageVersion: "c++20"
    cpp.cxxStandardLibrary: "libc++"

    install: true
    installDir: qbs.targetOS.contains("qnx") ? FileInfo.joinPaths("/tmp", name, "bin") : base

    OctoMYFiles{
        name: "app_sources"
        prefix: appDir
    }
    // We DON'T use combined libs, include all lib sources directly here
    OctoMYFiles{
        condition: !useCombinedLibs
        name: "lib_sources"
        prefix: libsDir
    }
    // We DO use combined libs, depend on combined lib here
    Depends { 
        condition: useCombinedLibs
        name: "combined"
    }
}

This time we use a bunch of helpers, some of which you already know:
  • OctoMYQtDepends: Our helper to include dependency on all the Qt modules that OctoMY™ needs
  • OctoMYLibProbe: Our helper to enumeratelibrary folders
  • OctoMYFiles: Our helper to list source files in a project that we care about (this is equivalent to tile fil Group in our StaticLibrary above).
Please note the user defined property we made called useCombinedLibs. It will include two different blocks depending on it's value. If it is true, then we have a Depends{ name: "combined"} and if it is not true we include a file group OctoMYFiles that basically lists all the source files of all our libraries in one big list.

This allows us to choose wether we want to build libraries separately and depnd on them or build the sources of the libraries directly into the app.



This concludes the fifth and final part in a series on using Qbs to our benefit  and joy in a non-trivial project, namely OctoMY™

I hope this series was useful, and that it helped you see the many benefits and few shortcommings of Qbs so that you may implement it in your own projects.

Good luck!


Illustrations borrowed from the amazing collection at https://ericjoyner.com/

No comments:

Post a Comment