Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create layered project structure in c++ using qmake

Under windows using MinGW, C++11, Qt 5 and qmake I have following project structure:

/my-project
   my-project.pro
   /my-app
      my-app.pro
      main.cpp
   /module-a
      module-a.pro
      modulea.h
      modulea.cpp
   /module-b
      module-b.pro
      moduleb.h
      moduleb.cpp

The dependencies between modules should look like this:

my-app ==> module-a ==> module-b

What I want to achieve is that my-app uses module-a, module-a uses module-b and my-app doesn't know anything about module-b. The module-a references module-b only through its implementation (the #include for module-b is located in .cpp of module-a).

I've tried to implement this by configuring module-a and module-b as static libraries in qmake. Unfortunately while compiling I receive linker error saying 'undefined reference to ModuleB::doSmthB()'

I understand the reason of this linking problem, my question is if it is somehow possible to achieve something similar to the proposed layered structure?

Sources:

my-project.pro:

TEMPLATE = subdirs
SUBDIRS += module-b
SUBDIRS += module-a
SUBDIRS += my-app
my-app.depends = module-a
module-a.depends = module-b

my-app.pro:

QT += widgets
TARGET = my-app
TEMPLATE = app
CONFIG += c++11
SOURCES += *.cpp
win32 {
    INCLUDEPATH += $$clean_path($$PWD/../module-a)
    DEPENDPATH += $$clean_path($$PWD/../module-a)
    LIBS += $$clean_path($$OUT_PWD/../module-a/debug/libmodule-a.a)
    PRE_TARGETDEPS += $$clean_path($$OUT_PWD/../module-a/debug/libmodule-a.a)
}

main.cpp:

#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>

#include "modulea.h"

int main(int argc, char *args[])
{
    QApplication app(argc, args);
    QGraphicsView view;
    QGraphicsScene *scene = new QGraphicsScene(0, 0, 300, 300, &view);
    ModuleA moduleA;
    scene->addText(QString::number(moduleA.doSmthA())); // undefined reference to ModuleB::doSmthB()
    view.setScene(scene);
    view.show();
    return app.exec();
}

module-a.pro:

QT -= core gui
TARGET = module-a
TEMPLATE = lib
CONFIG += staticlib
CONFIG += c++11
HEADERS += *.h
SOURCES += *.cpp
win32 {
    INCLUDEPATH += $$clean_path($$PWD/../module-b)
    DEPENDPATH += $$clean_path($$PWD/../module-b)
    LIBS += $$clean_path($$OUT_PWD/../module-b/debug/libmodule-b.a)
    PRE_TARGETDEPS += $$clean_path($$OUT_PWD/../module-b/debug/libmodule-b.a)
}

modulea.h:

#ifndef MODULEA_H
#define MODULEA_H

struct ModuleA
{
    int doSmthA();
};

#endif // MODULEA_H

modulea.cpp:

#include "modulea.h"
#include "moduleb.h"

int ModuleA::doSmthA() {
    ModuleB other;
    return other.doSmthB();
}

module-b.pro:

QT -= core gui
TARGET = module-b
TEMPLATE = lib
CONFIG += staticlib
CONFIG += c++11
HEADERS += *.h
SOURCES += *.cpp

moduleb.h:

#ifndef MODULEB_H
#define MODULEB_H

struct ModuleB
{
    int doSmthB();
};

#endif // MODULEB_H

moduleb.cpp:

#include "moduleb.h"

int ModuleB::doSmthB() {
    return 12345;
}
like image 648
marm Avatar asked Apr 19 '16 08:04

marm


People also ask

What is qmake command?

The qmake tool provides you with a project-oriented system for managing the build process for applications, libraries, and other components. This approach gives you control over the source files used, and allows each of the steps in the process to be described concisely, typically within a single file.

What is a qmake file?

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.

What is .pro file in Qt?

pro) File. I'm sure you already know about the Qt Project File since we have mentioned it countless times throughout the book. A .pro file is actually the project file used by qmake to build your application, library, or plugin.


1 Answers

To fix my example following changes are required:

1) Add CONFIG += create_prl to the .pro files of all app's direct dependencies (in my case module-a). It won't hurt to modify all modules like this.

Explanation here: http://doc.qt.io/qt-5/qmake-advanced-usage.html#library-dependencies

2) In the main .pro (in my example the my-project.pro) the subdir declaration of app (SUBDIRS += my-app) has to be placed AFTER the direct dependencies of app (after SUBDIRS += module-a).

A hint for the second point I've found here: https://stackoverflow.com/a/1417859/6223445

3) The LIBS property have to be defined using -L and -l options (at least under windows), e.g. instead of:

LIBS += $$clean_path($$OUT_PWD/../module-a/debug/libmodule-a.a)

use following:

LIBS += -L$$clean_path($$OUT_PWD/../module-a/debug/) -lmodule-a

The fixed solution looks like this (modified files only):

my-project.pro:

TEMPLATE = subdirs
SUBDIRS += module-b
SUBDIRS += module-a
SUBDIRS += my-app
my-app.depends = module-a
module-a.depends = module-b

my-app.pro:

QT += widgets
TARGET = my-app
TEMPLATE = app
CONFIG += c++11
SOURCES += *.cpp
win32 {
    INCLUDEPATH += $$clean_path($$PWD/../module-a)
    DEPENDPATH += $$clean_path($$PWD/../module-a)
    LIBS += -L$$clean_path($$OUT_PWD/../module-a/debug/) -lmodule-a
    PRE_TARGETDEPS += $$clean_path($$OUT_PWD/../module-a/debug/libmodule-a.a)
}

module-a.pro:

QT -= core gui
TARGET = module-a
TEMPLATE = lib
CONFIG += staticlib
CONFIG += c++11
CONFIG += create_prl
HEADERS += *.h
SOURCES += *.cpp
win32 {
    INCLUDEPATH += $$clean_path($$PWD/../module-b)
    DEPENDPATH += $$clean_path($$PWD/../module-b)
    LIBS += -L$$clean_path($$OUT_PWD/../module-b/debug/) -lmodule-b
    PRE_TARGETDEPS += $$clean_path($$OUT_PWD/../module-b/debug/libmodule-b.a)
}
like image 120
marm Avatar answered Sep 28 '22 06:09

marm