Home > Back-end >  How can I use sub-projects in Qt?
How can I use sub-projects in Qt?

Time:03-17

I'm trying to move onto Qt to rewrite a win32 project that has a lot of static libraries so as a preliminary test project I tried creating a subdir project following the instructions in https://www.toptal.com/qt/vital-guide-qmake. I've seen plenty of other examples, and similar questions on this site, but none of them are a bare bones example that actually works when I build it so I'm presenting this minimal example in the hope that someone can tell me what it is that I'm missing.

Here's the file structure;

project/
    project.pro 
    app/
        app.pro
        main.ccp
    library/
        library.pro
        mainwindow.h
        library.pri

Both app and library projects are simple Qt Widgets Applications, created with the New Subproject wizard. The app project has main.cpp;

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

The library project has just the header file mainwindow.h defining the MainWindow class;

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {}
    ~MainWindow() {}
};
#endif // MAINWINDOW_H

Here are the pro. files;

project.pro;

TEMPLATE = subdirs
TARGET = project
SUBDIRS = app library
app.depends = library

app.pro;

TEMPLATE = app
TARGET = app

QT        = core gui

greaterThan(QT_MAJOR_VERSION, 4): QT  = widgets

CONFIG  = c  11

SOURCES  = \
    main.cpp

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS  = target

include(../library/library.pri)

library.pro;

TEMPLATE = lib
TARGET = library

QT        = core gui

greaterThan(QT_MAJOR_VERSION, 4): QT  = widgets

CONFIG  = c  11

HEADERS  = \
    mainwindow.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS  = target

DISTFILES  = \
    library.pri

Lastly, the library.pri file;

LIBTARGET = library
BASEDIR   = $${PWD}
INCLUDEPATH *= $${BASEDIR}/include
LIBS  = -L$${DESTDIR} -llibrary

The point of this is to check that I can write a project in Qt where a function in one project can reference a class in another. When compiled as a single project, with main.cpp and mainwindow.h in the same project, you get the usual application window on screen with no errors so I know both main.cpp and the MainWindow class are good; compiled as-is, with the two sub-projects, I get "'mainwindow.h' file not found" on line 1, main.cpp, and "unknown type name 'MainWindow'" on line 6, main.cpp, so the library project is obviously not getting referenced properly by the app project. I'm new to Qt and have absolutely no experience with qmake, any help would be appreciated, and as I know I'm not the only person struggling with this if anyone can help get this working I'll put it up on gtihub.

CodePudding user response:

To use library you need to setup two things: append INCLUDEPATH, and LIBS, you can do it in pri file, and then include in app, if error says "file *.h not found" it means INCLUDEPATH is incomplete.

Here's how you can do it:

Project structure

project/
├── app
│   ├── app.pro
│   └── main.cpp
├── library
│   ├── library.pri
│   ├── library.pro
│   ├── mainwindow.cpp
│   ├── mainwindow.h
│   └── mainwindow.ui
└── project.pro

project.pro

TEMPLATE = subdirs

SUBDIRS  = \
    app \
    library

app.depends = library

library.pri

INCLUDEPATH  = $$PWD

win32 {
    CONFIG(debug, debug|release) {
        LIBS  = -L$$PWD/debug
    } else {
        LIBS  = -L$$PWD/release
    }
} else {
    LIBS  = -L$$PWD
}
LIBS  = -llibrary

library.pro

QT  = gui widgets

TEMPLATE = lib
CONFIG  = staticlib

SOURCES  = \
    mainwindow.cpp

HEADERS  = \
    mainwindow.h

FORMS  = \
    mainwindow.ui

app.pro

QT  = gui widgets
SOURCES  = main.cpp
include($$PWD/../library/library.pri)

QtCreator uses shadow build by default (it can be disabled on projects page), so if you build from QtCreator IDE not from shell (command line), you are likely using shadow build. In this case all build artifacts including static libraries are build outide of source directory in a separate directory named build-${project-name}-${device-type}-${build-config} (build-project-Desktop-Debug in our case), so -L$$PWD wont work, there's OUT_PWD for that, unfortunately for some reason it points not to pri directory but to pro directory (build-project-Desktop-Debug/app in out case) and things get a little hairier. Here's library.pri that works for both shadow and normal build:

INCLUDEPATH  = $$PWD

win32 {
    CONFIG(debug, debug|release) {
        LIBS  = -L$$PWD/debug -L$$OUT_PWD/../library/debug
    } else {
        LIBS  = -L$$PWD/release -L$$OUT_PWD/../library/release
    }
} else {
    LIBS  = -L$$PWD -L$$OUT_PWD/../library
}
LIBS  = -llibrary

Full source: https://github.com/mugiseyebrows/app-and-library.git

  • Related