2023-02-24

Qbs tutorial part 1/5: Main project file



After spending a few gruelling weeks porting my brain to "think in Qbs", I felt ready to take on the non-trivial task of comitting 100% to porting the build system of OctoMY™ from qmake to Qbs. This was in large part possible thanks to the super-human patience and wisdom demonstrated by the super awesome Qbs community, which lives on Discord. Shoutout to ABBAPOH, Psy-Kai and Janet Blackquill, your help was indispensible!

I thought I would document my decisions here for future reference and maybe to serve as a template for others trying to get into Qbs with their non-trivial projects. I will also introduce some concepts and tips & tricks that I picked up along the way.

So first up: top level project structure. OctoMY™ is divided coarsely into 3 parts:

  • Apps - The actual programs that we run when we want to use OctoMY™
  • Libs - The software components which contains the code of OctoMY™, liked into the apps
  • Tests - A bunch of programs, each testing one aspect of the codebase



The file structure of the project looks like this:
.
├── 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

So there is a lot to cover here, and I promise that we will go over one part at the time so that it will all make sense in the end!

First, qbs consist of strategically placed text files with the .qbs file extension. Inside these qbs files is a declarative syntax borrowed from QML. Expect to see a bunch of json-like blocks of data with some javascript sprinkled on top.

The top-level file of the project is OctoMY.qbs This marks the entrypoint for qbs, and it is this file which qbs will read first, and this is the file you open in QtCreator to load the project.

Qbs project in QtCreator



As you can see, I have used color coding thoruhgt this article so that you may easily see the link between views. For example, the main project file has been marked red, and the sub-project files that it references yellow in this entire article, so you can readily find them in the file structure above.


OctoMY.qbs looks like this:


import qbs.FileInfo

Project {
    name: "OctoMY™"
    qbsSearchPaths: [ FileInfo.joinPaths(path, "integration", "qbs") + FileInfo.pathSeparator()]
    references: [
           "src/libs.qbs"
          , "src/apps.qbs"
          , "test/tests.qbs"
    ]
}


As you can see, it has some important lines:

  • import qbs.FileInfo: This is how we get access to other types and script libraries in qbs. In this case, we need the FileInfo service provided with qbs that allows us to do file operations.
  • Project: This indicates that we are defining a new qbs project. "Project" is a qbs type that represents a project. It is used to collect other items inside of it similar to a folder in a filesystem. It can contain other items directly inside of it, or it can refer to files which in turn will contain such items. In our case we only refer to other files through the references property (see below).
  • name: This is what shows up inside QtCreator as the name of your project. If you leave it out, Qbs will use the file as a fallback. In other words, this property is optional.
  • qbsSearchPaths: This points to where qbs will look for our user defined reusable components, of which there are several in the OctoMY™ project. You don't have to use this feature, but it will serve you well to use it once your Qbs project grows beyond the trivial "Hello World" examples. In this case we tell qbs that this project will look for our components in ./integrations/qbs folder, and you can see (in theproject tree at the top of this article) that it contains some components that we will use from sub projects, such as OctoMYTestProbe.qbs.
  • references: References is a list of files that Qbs should read and include in the project. Since we are currently defining a project, we want to include the actual sources and libraries and tests of the project, and that is done by referring to the qbs files which we use to find them. In this case we include 3 sub-projects via the libs.qbs, apps.qbs and test.qbs files.
As you can see, I have color coded some files such as the main project file in red, and the sub-project files that it references in yellow in this entire article series, and so you can readily find them in the file structure.

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

In the next part we will look at test/tests.qbs and how it relates to the main project file.


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

No comments:

Post a Comment