Skip to content
Kimmo edited this page Jun 5, 2018 · 72 revisions

Creating and debugging Qt projects

Explanation of the contents of a topic page @ Topic reference page

Back to Week 1

Comment: This is quite long. Should we split projects and debugging into two 1.00/1.01?

E: We could do a split, sure, if it feels necessary. I don't really know if this is that long. We could further discuss where we want to split the debugging into, is 1.01 the natural option or would it place better somewhere else?

E: Noting that during skype meeting we agreed that we will look into whether or not debugging will be split later once the material for week 1 is more complete and we can see if it needs to be moved, and where the most logical place for it would be.

Outline

Objective: Being able to create, build, debug and run a trivial Qt project (.pro files, qmake, debug output with QDebug and qDebug(), qWarning etc.)

Comment: I'd like to add the qmake project: Being able to create, build, debug, and run a trivial Qt project

Comment: Two objectives, Qt project, .pro files and qmake. Debug output with QDebug and qDebug(), qWarning etc.

E: Should we introduce the Qt Namespace and/or the Global Qt Declarations pages as reference documents in general somehow? I'm not sure if it's relevant but at a glance they seem exhaustive for some intents and purposes

Comment: Namespace and global declarations introduction makes sense. The debug macros exist there, so could be nice to have little bit wider introduction.

E: I'll add them to the introduction. If we use Kimmo's idea with the empty project exercise we could use the opportunity to introduce the namespace and global declarations there, if our expectation is basically just a project that builds and no more. "Go to these pages and pull something out of them and put them where they belong and build your project so that it builds", I don't know, it shouldn't be too hard to figure out.

Beginner

  • What are includes?
  • How do you use includes?
  • What is Hello?
  • What is World?

Intermediate

  • How do I create Qt projects?
  • What does the exercise project structure look like?
  • What is a .pro file?
  • What is qmake?
  • What is the Qt Namespace?
  • What are the Global Qt Declarations?
  • What are modules?
  • What is QDebug?
  • How do I output debug information (qDebug, qWarning, qCritical, qFatal)?
  • What are shadow builds?

E: Some of these were mentioned in the introduction but we planned on only being mentioning them briefly (qmake, .pro files). They may be omitted from the introduction and moved here (but we should be careful of bloat). Kimmo brought up the question of shadow builds, they are also mentioned as a topic that may require introduction on the intropage but giving it some thought seems probably to be more suited to be introduced in 1.00). These need to be cleaned up later.

Comment: Training attendees often ask about the shadow build, so its good to cover it. Keep qmake at the minimal level (Makefile generator + possibly a short intro of QT, SOURCES; HEADERS - even those can be omitted) as it easily bloats itself and if it will be replaced by QBS

E: I'll try to figure out where to place shadow builds

Expert

  • Will this run on my Solaris OS toaster?

Omitted

  • How do I use the Qt Creator debugger?

Course material content

[PLACEHOLDER FOR TOPIC SHORT TOPIC AND THEMES INTRODUCTION]

Hello! Welcome aboard our Qt mooc course!

This topic will cover most of the basic things you should need when working on this course. In this topic we will discuss Qt projects in general and from the perspective of this course in the form of our exercises. We will run trough some of the documentation of key concepts that will help you understand the fundamentals of working with Qt. It should also let you get familiar with the documentation of Qt that we will be using as a study aide alongside this course. We will also discuss some aspects of builds, qmake and debugging messages.

If all of this is familiar to you, you may proceed to completing the exercise and moving on to the more specific topics. We won't hold it against you when you come crawling back to read about the basics when you have no idea what's going on after completing once another Hello World.

Qt Projects, Qt Namespace, Global Qt Declarations and macros

http://wiki.qt.io/Basic_Qt_Programming_Tutorial
http://wiki.qt.io/Getting_Started_on_the_Commandline
http://doc.qt.io/qtcreator/creator-project-creating.html
http://doc.qt.io/qtcreator/creator-configuring-projects.html
http://doc.qt.io/qtcreator/creator-project-managing.html

E: At the start (or in general, during the course, I guess?) we will for the most part not require the student to create their own Qt Project from scratch. We could include the basics of creating a Qt project (it was mentioned as a question) in a sandbox kind of manner, as in some cases it could perhaps be of help to the student to have their own designated sandbox in which to test code and stuff outside of touching exercise codes? These are mainly scope questions with ideas thrown in the air.

E: Kimmo suggested that we could simply have an exercise that is empty and the student gets point from just submitting it (as long as it builds on the test server). The exercise would basically just be to use our instructions to make your own sandbox project with some relevant structure to use during the course for personal testing purposes of code and such. This way we would go trough the basics of say, .pro files, qmake, shadow builds or whatever else that seems important to go trough once (library linking, macros, includes in Qt) that wont be used much as most of our exercise templates will have alot of the stuff included already.

Comment: Creating an empty project and adding .pro file/main.cpp manually in Qt Creator is not very beneficial but time-consuming. I like Kimmo's idea.

E: Yes, it's a good idea and would allow to explain some basic stuff. I'm thinking of adding the namespace and global declarations into it aswell

Before we start with the heavy lifting, we are going to introduce some basic concepts to help you get started with the wonderful world of creating with Qt! We are also going to introduce some parts of the documentation of Qt, as it will be an important tool for you in addition to the course materials. We want to provide you with what we feel will be of use for any student working on this course.

The basic concepts that we will take a closer look at are global declarations, modules and namespaces in Qt.

Let's talk about the global declarations in Qt. You can find an exhaustive list of global declarations at http://doc.qt.io/qt-5/qtglobal.html.
The global declarations include types, functions and macros. You do not have to memorize this list before proceeding into the next chapter, but it is important that you know what it is and what you can use it for, as you may find it useful on various occasions while working on this course. In the end of this topic we will discuss some useful debugging functions found in the global declaration.

The type definitions are partly convenience definitions for basic types (some of which guarantee certain bit-sizes on all platforms supported by Qt), partly types related to Qt message handling. The functions are related to generating messages, Qt version handling and comparing and adjusting object values. And finally, some of the declared macros enable programmers to add compiler or platform specific code to their applications, while others are convenience macros for larger operations.

We will explicitly refer you to the global declarations list in assignments or learning topics where we feel it is necessary.

Next, let's talk about the modules in Qt. Here is a list of the modules in Qt.
To include modules into your project you need to include them in your projects' .pro file. If you are using qmake, the Core and GUI modules will be included by default. If you aren't using the GUI module in your project (which we for the most parts won't during the first week, anyway), simply disable it by writing QT -= GUI in your projects .pro file. All of the other Qt modules rely on the Qt Core module.

Next, it's time to take a look at some essentials regarding namespaces and their use in Qt. Here is a list of the main namespaces in Qt: https://doc.qt.io/qt-5.10/namespaces.html.
We will not be using all of these namespaces during the course, but before getting our hands dirty, we feel that you will have some benefit of having been introduced to this list beforehand. In general, we will summarize exhaustive reference materials in a link list at the end of each topic.

Let's have an example of including namespaces! Say you want to include the QtConcurrent namespace in your code. Let's take a closer look at the documentation page for QtConcurrent:

To include the QtConcurrent namespace, you will need to make a specific mention of it in two places: the header of the relevant file (#include <QtConcurrent>), and the project .pro file (QT += concurrent).

We followed the instructions, but the Qt Creator is telling me the file is missing! What do we do? We could always try pressing SHIFT+TAB at the end of the include name and see what happens next.

The QtConcurrent is visible in the dropdown list that appeared! Are we good to go here?

Well, it looks like we have our include all sorted now, however this doesn't look like what the documentation suggested?

The reason as to why simply writing #include <QtConcurrent> wasn't enough is that we didn't specify the flag QT += concurrent in the .pro profile file and save it first. Having done so, let's now look at what happens when we want to #include <QtConcurrent>:

Much better. Consider this your crash course in using includes in Qt.

In this list, we can see that there exists a namespace for Qt at https://doc.qt.io/qt-5.10/qt.html.
Here you can find miscellaneous identifiers used throughout the Qt library. This is the list we are expecting you to memorize before proceeding to the next chapter of this topic.

Just kidding! We're just letting you know it's there if you happen to need to use it as reference material for anything.

Comment: This is great. A nice way to introduce the name space and .pro file basics. Excellent! And the English language is some much better than mine.

Exercise structure

https://github.com/TestMyQt/Qt-CreatorTMC/wiki/Test-case-directory-and-project-structure-in-tmc-langs

Having finished covering the basics, it's time to take a look at the structural composition of the exercises.
Each exercise is located in its own subdirectory in the main exercise directory of each week. The exercise consists of a .pro file at the root level, in addition to a couple of directories.
The .pro file at the root level is the project file for the exercise project. We will further discuss project files later in this chapter. But for now, we will focus on the project structure.

The local tests that will be testing your exercises are located in the test_runner directory.

If you are having problems figuring out why your exercise isn't passing the tests and you have exhausted all other alternatives, it may be worth looking at the test runner files. Figuring out what the tests are testing may give you a clue as to what may be the problem in your code. You may even alter the local tests if it helps you understand the problem better. On a rare occasion, the problem may be that the tests themselves are faulty. In this case we recommend joining the course channel to see if others are having the same problem. We have done everything we can to make sure this does not happen, but there are always edge cases.

Please take note that the local tests are only there to tell you if your exercise is fully completed and ready to be submitted. You cannot alter the tests to your liking, and expect to pass the exercise by submitting an incomplete assignment! We will test your exercise on the server before you receive points for it! Some times there may even be hidden tests serverside, for making sure that you aren't trying to complete the exercises based on what the tests are testing for instead of completing the actual exercise to support your learning.

The src directory is where the magic, by which we mean your coding, will take place.

It includes the relevant source and header files for each exercise project. In some cases there may be additional directories included for libraries, and in some cases we may ask you to create new directories. Nobody knows if! Nobody knows when! Nobody knows how! But we'll figure that out later.

Have you already noticed how every directory has its own .pro file? What does this all mean? It's like trying to figure out the plot line of Lost! The reason for this is, that every subdirectory we have included in the exercise directory are actually projects within the actual exercise project (spoiler: this is also the plot line of Lost)! Let us elaborate and take look at the root level .pro file:

TEMPLATE = subdirs
SUBDIRS += \
      src \
      test_runner

      test_runner.depends = src

This tells qmake, which we will discuss next in this chapter, that the exercise project follows a build template called subdirs, and defines the subdirectories to be included in this project. Using the subdirectories template requires each declared subdirectory to be its own project and have its own project file included in said subdirectory. In the end, we declare the test runner subdirectory to be dependent of the source directory. This is because we want to build your exercise before we build the test runner so the test runner has something to test.

Having gotten this far, you should have some questions by now.
Move on to the next chapters and we will fairly certainly have provided the answers you seek.

qmake

http://doc.qt.io/qt-5/qmake-variable-reference.html
http://doc.qt.io/qt-5/qmake-environment-reference.html

The qmake tool helps simplify the build process for development projects across different platforms. It automates the generation of Makefiles so that only a few lines of information are needed to create each Makefile. You can use qmake for any software project, whether it is written with Qt or not.

qmake generates a Makefile based on the information in a project file. The project files use the extension .pro, and are usually created by project templates in Qt Creator. Project files are worked on by the developer to specify the instruction set they want qmake to use for their project, and are usually simple. However, more sophisticated project files can be created for complex projects. We will further discuss project files later in this chapter, but as qmake uses the information stored in project files, we cannot completely avoid talking about their contents when talking about qmake.

The fundamental behavior of qmake is influenced by variable declarations that define the build process of each project. Some of these declare resources, such as headers and source files, that are common to each platform. Others are used to customize the behavior of compilers and linkers on specific platforms.
Let us elaborate by once again referring to our exercise structure, specifically the .pro file of the source directory:

QT -= gui

TARGET = main

CONFIG += c++11 console
CONFIG -= app_bundle

win32 {
     CONFIG -= debug_and_release debug_and_release_target
}

DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
     main.cpp \
     hello.cpp

 HEADERS += \
      hello.h

At your own discretion, you may refer to the exercise directory structure and file composition of exercise [PLACEHOLDER FOR HELLO WORLD EXERCISE NAME]. You may also refer to the qmake variable reference and reflect on the declarations in the aforementioned .pro file code. Can you figure out what we are trying to tell qmake and why? The win32 bit may not be entirely self-explanatory. We may provide an explanation for this one later on.

Platform-specific variables follow the naming pattern of the variables which they extend or modify, but include the name of the relevant platform in their name. For example, LIBS can be used to specify a list of libraries that a project needs to link against. Here is an example:

unix:LIBS += -L/usr/local/lib -lmath
win32:LIBS += c:/mylibs/math.lib

If you feel like doing some exploring on your own, we recommend you take a look at (http://doc.qt.io/qt-5/qmake-variable-reference.html) for a full list of qmake variables to browse at your own discretion.

E: All this is blatantly copied from two of the aforementioned qmake links. Question is, what specifically of qmake would be of essence for the student to learn? The existence of qmake in general? Working on the TMC plugin talking about the CONFIG variable comes to mind.

Comment The general idea is important and it's well-defined here in my opinion. When students add qtquick/qml or create a library, for example the documentation provides could examples how to do that. I would postpone the syntax details there. And LIBS is typically used by developers, QMAKE_LIBS more by qmake itself.

E: Postponing syntax details for qtquick/qml. Were you thinking something more along the lines of http://doc.qt.io/qtcreator/creator-project-qmake-libraries.html regarding the libraries? Do you want me to go trough the process of how to add libraries and have the student do it in their sandbox, or just provide documentation as to how to do it (or include this link, and save the actual library creation exercise for a later week where it may be done?) Is this relevant for week 1 or could we save actual library explanations for an exercise where the student will need to make use of libraries?

Comment. My sentences were not very clear indeed. Simply meaning that just mentioning the scope, like wins32 and LIBS as an example is just sufficient here. I would not go into details of LIBS variable itself.

.pro files

http://doc.qt.io/qt-5/qmake-project-files.html

Project files contain all the information required by qmake to build your application, library, or plugin. Generally, you use a series of declarations to specify the resources in the project, but support for simple programming constructs enables you to describe different build processes for different platforms and environments.

The project file format used by qmake can be used to support both simple and fairly complex build systems. Simple project files use a straightforward declarative style, defining standard variables to indicate the source and header files that are used in the project. Complex projects may use control flow structures to fine-tune the build process.

The following sections describe the different types of elements used in project files. (E: Do something about this)

Comment: In my opinion, about everything said in these three paragraphs is already mentioned in qmake. There is no much new information, so they can be removed.

In a project file, variables are used to hold lists of strings. In the simplest projects, these variables inform qmake about the configuration options to use, or supply filenames and paths to use in the build process.

qmake looks for certain variables in each project file, and it uses the contents of these to determine what it should write to a Makefile. For example, the lists of values in the HEADERS and SOURCES variables are used to tell qmake about header and source files in the same directory as the project file.

As long as you are using qmake, the Core and GUI modules are included by default.

Comment: QT? worth mentioning. For example that QT contains core and gut modules? Something should be said about the modules

E: I'll add this here once I figure out how to put it into writing so it fits here. Mentioned modules in the first segment of this topic, there may be some repetition here and there about some things, but things like these can always be cleaned up and restructured better.

Variables can also be used internally to store temporary lists of values, and existing lists of values can be overwritten or extended with new values.

The following snippet illustrates how lists of values are assigned to variables:

HEADERS = mainwindow.h paintwidget.h

The list of values in a variable is extended in the following way:

SOURCES = main.cpp mainwindow.cpp \    
          paintwidget.cpp
CONFIG += console

Note: The first assignment only includes values that are specified on the same line as the HEADERS variable. The second assignment splits the values in the SOURCES variable across lines by using a backslash ().

E: We could replace the example with something in our own test projects later on - the example is copypasted and can work on its own or just stay there as a placeholder

Qt resource system

The Qt resource system is a platform independent way to store application resources (images, icons, translation files, data, etc.) inside the application's executable. Resources are specified inside the resource collection .qrc file:

<!DOCTYPE RCC><RCC version="1.0">
<qresource>
    <file>images/icon.png</file>
    <file>data.txt</file>
</qresource>
</RCC>

The file is then included in the .pro file with RESOURCES = application.qrc. The specified files will be then compressed and included as a static C++ array. They can be accessed with QFile or image types like any other file like so:

QIcon icon(":/images/icon.png")
QFile file(":/data.txt");

The QDebug class

The QDebug class provides an output stream for debugging information.

QDebug is used whenever the developer needs to write out debugging or tracing information to a device, file, string or console.

Basic Use

In the common case, it is useful to call the qDebug() function to obtain a default QDebug object to use for writing debugging information.

qDebug() << "Date:" << QDate::currentDate();
qDebug() << "Types:" << QString("String") << QChar('x') << QRect(0, 10, 50, 40);
qDebug() << "Custom coordinate type:" << coordinate;

This constructs a QDebug object using the constructor that accepts a QtMsgType value of QtDebugMsg. Similarly, the qWarning(), qCritical() and qFatal() functions also return QDebug objects for the corresponding message types.

The class also provides several constructors for other situations, including a constructor that accepts a QFile or any other QIODevice subclass that is used to write debugging information to files, sockets, other processes, etc. The constructor that accepts a QString is used to write to a string for display or serialization.

Comment: I'd add a sentence about the usefulness of the IO device in a form that it becomes clear to everyone, i.e. that we can read/write to a buffer, socket, even to another process with QIODeice.

Formatting Options

QDebug formats output so that it's easily readable. It automatically adds spaces between arguments, and adds quotes around QString, QByteArray, QChar arguments.

You can tweak these options through the space(), nospace() and quote(), noquote() methods. Furthermore, QTextStream manipulators can be piped into a QDebug stream.

QDebugStateSaver limits changes to the formatting to the current scope. resetFormat() resets the options to the default ones.

Writing Custom Types to a Stream

Many standard types can be written to QDebug objects, and Qt provides support for most Qt value types. To add support for custom types, you need to implement a streaming operator, as in the following example:

QDebug operator<<(QDebug debug, const Coordinate &c)
{
    QDebugStateSaver saver(debug);
    debug.nospace() << '(' << c.x() << ", " << c.y() << ')';

    return debug;
}

Outputting debug information trough the use of qDebug, qWarning, qCritical and qFatal

qDebug, qWarning, qCritical and qFatal are functions defined in the Qt global declarations. The functions take a format string and a list of arguments, similar to the C printf() function. The format should be a Latin-1 string. To suppress any of these types, you may install your own message handler using qInstallMessageHandler(). The functions call the message handler with the defined debug/critical/fatal/warning message. They call call the message handler, or if no message handler is present, print out the message to stderr. On Windows, for the most parts, the message is sent to the debugger.

qDebug(const char \*message, ...)

Under Windows the message is sent to the console, if it is a console application; otherwise, it is sent to the debugger. This function does nothing if QT_NO_DEBUG_OUTPUT was defined during compilation.

For example:

qDebug("Items in list: %d", myList.size());

If you include <QtDebug>, a more convenient syntax is also available:

qDebug() << "Brush:" << myQBrush << "Other value:" << i;

With this syntax, the function returns a QDebug object that is configured to use the QtDebugMsg message type. It automatically puts a single space between each item, and outputs a newline at the end. It supports many C++ and Qt types.

qCritical(const char *message, ...)

It exits if the environment variable QT_FATAL_CRITICALS is not empty.

For example:

void load(const QString &fileName)
{
     QFile file(fileName);
     if (!file.exists())
          qCritical("File '%s' does not exist!", qUtf8Printable(fileName));
}

If you include <QtDebug>, a more convenient syntax is also available:

qCritical() << "Brush:" << myQBrush << "Other value:" << i;

A space is inserted between the items, and a newline is appended at the end.

qWarning(const char *message, ...)

This function does nothing if QT_NO_WARNING_OUTPUT was defined during compilation; it exits if at the nth warning corresponding to the counter in environment variable QT_FATAL_WARNINGS. That is, if the environment variable contains the value 1, it will exit on the 1st message; if it contains the value 10, it will exit on the 10th message. Any non-numeric value is equivalent to 1.

For example:

void f(int c)
{
    if (c > 200)
        qWarning("f: bad argument, c == %d", c);
}

If you include <QtDebug>, a more convenient syntax is also available:

qWarning() << "Brush:" << myQBrush << "Other value:" << i;

This syntax inserts a space between each item, and appends a newline at the end.

qFatal(const char *message, ...)

If you are using the default message handler this function will abort to create a core dump. On Windows, for debug builds, this function will report a _CRT_ERROR enabling you to connect a debugger to the application.

For example:

int divide(int a, int b)
{
    if (b == 0)                                // program error
         qFatal("divide: cannot divide by zero");
    return a / b;
}

Instructions and description for the exercise of topic 1.00

Write "Hello world" as qDebug message and "Don't panic!" as a qWarning message.

TBA

Shadow builds

Now that you've successfully built your first Qt project, you might be interested in the built binaries. By default, Qt Creator builds the project in to a separate directory (build-ProjectName-*) as a shadow build, which is separated from the source directory. qmake can also generate an in-source build, but this is not recommended. The benefit in shadow builds is keeping that directory clean, which makes changing between Kits or build configurations faster.

Exhaustive reference material mentioned in this topic

http://doc.qt.io/qt-5/qt.html
http://doc.qt.io/qt-5/qtglobal.html
http://doc.qt.io/qt-5/qmake-environment-reference.html
http://doc.qt.io/qt-5/qmake-variable-reference.html

Further reading topics/links:

E: We decided to omit discussing the debugger explicitly. Included here is a link to the debugger documentation, we could include it for students to familiarize with on their own discretion as discussed.

Clone this wiki locally