How to include shared code/headers from another directory? /src/widget/ using /src/common/



  • I'm merging two client-side device controller applications. Originally 'Device.h' was an all-inclusive God-Class and near identical copies appeared in both programs. Having broken-out all the common-code I'm having trouble compiling, and worse linking after the dependent common-code classes are moved into a separate directory (and QT Project). Simple '#includes' and 'INCLUDEPATH+=' don't seem to cut ice.
    (File Excerpts Below)

    QUESTIONS:

    1. Am I using QT Sub-Projects (more-or-less) correctly?
    2. Must the 'Common' code really be a QT-Project simply because it's a different directory?
    3. Must the 'Common' code really be a Library simply because it's in an independent directory?
    4. If so, static or dynamic linked libraries and how do I write the *.pro files correctly?
    5. Why am I unable to simply "#include" files from the next folder over?

    TRIALS / RESULTS:

    • Common .pro with NO "+=staticlib" produces a common.dll but no common.lib file on Windows and matching linking error. Mac-OSX produces libcommon.dylib but no *.a and seems to run successfully.

    • Common .pro, WITH the "+= staticlib" produces a *.a file on Mac-OSX, a *.lib on Windows 10 and technically everything IS working. HOWEVER this just doesn't feel right to me or I don't properly understand why it's required. Nor what future impacts it will have. Can someone please clarify?

    FINAL CAVEAT: Feature.h/cpp and it's *.qml files have not been moved to /common/ yet, (nor sub-divided). That's this weekends project and I'm afraid of what land-mines I may step on.

    FOLDER STRUCTURE:
    app/builds/
    app/docs/
    app/src/
    
    src/root/
        programRoot.pro
        (programRoot.sln)           # Auto generated on days I use VisualStudio.
    
    src/common/
        common.pro
        DeviceBase.h/cpp
        NetworkWrapper.h/cpp
        Stuff.h/cpp
        Feature1.h/cpp,  f1a.qml,  f1b.qml ...      # To be done this weekend. Not migrated from Device folders yet.
        Feature2.h/cpp,  f2a.qml,  f2b.qml ...      # To be done this weekend. Not migrated from Device folders yet.
    
    src/device1/
        Device_1.h/cpp
        Device_1.pro
        Device_1.qrc
        main.cpp
        main.qml
        foo.h/cpp
        foo.qml
        bar.qml
    
    --
    src/device2/
        Device_2.h/cpp
        Device_2.pro
        Device_2.qrc
        main.cpp
        main.qml
        baz.h/cpp
        baz.qml
        qaz.qml
    

    File Excerpts:

    --- src/root/programRoot.pro   --  (entire file) ---
        TEMPLATE = subdirs
        SUBDIRS += \
            ../common \
            ../device1 \ 
            ../device2 \
    ---
    
    --- src/common/Common.pro ---
    TEMPLATE = lib
    CONFIG += staticlib
        ...
    unix {
        target.path = /usr/lib
        INSTALLS += target
    }
    ---
    
    --- src/device1/Device_1.pro ---
    TEMPLATE = app
        ...
    win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../common/release/ -lcommon
    else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../common/debug/ -lcommon
    else:unix: LIBS += -L$$OUT_PWD/../common/ -lcommon
    
    INCLUDEPATH += $$PWD/../common
    DEPENDPATH += $$PWD/../common
    ---
    
    
    --- src/device1/Device_1.h---
    // #include "../common/DeviceBase.h"
       #include "DeviceBase.h"
    
    class Device_1 : public DeviceBase {
        private:
            Feature1 mf1;
            Feature2 mf2;
    }
    
    

    [edit]
    Abbreviated list of resources I've read:
    https://forum.qt.io/topic/26005/how-to-get-a-lib-file-instead-of-a-dll-solved // Most helpful so far.
    http://doc.qt.io/qtcreator/creator-project-creating.html
    http://doc.qt.io/qtcreator/creator-project-qmake-libraries.html
    http://doc.qt.io/qt-5/qmake-variable-reference.html#includepath
    https://stackoverflow.com/questions/41514620/qt-creator-how-to-run-subdirs-projects/41515424#41515424
    https://stackoverflow.com/questions/2752352/how-to-add-include-path-in-qt-creator


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    A library is not mandatory although it avoids you to compile the same sources multiple time.

    Your SUBDIRS use is wrong. i.e. app and src both should be SUBDIRS projects.

    If you'd like to avoid the library, you can write a .pri file in your common subfolder that will contains the INCLUDEPATH, SOURCES and HEADERS directive needed to use the files in it and include that .pri file in your other projects.

    Hope it helps.



  • @SGaist Thank you for your warm welcome and valuable response! I've experimented extensively with your suggestions the last few days with mixed-successes. I have some follow-up questions and may need more detail.

    For the moment Im operating with `/app/src/src.pro` as root node.
    
    1. From your input I got a non-lib /src/common/common.pri working and /src/Device1/ linking against it! Initially however, QT-Creator found the common.pri but not it's header or source files. Ultimately I had to $$PWD/ for every file listed in the common.pri (see below). Is this correct?
      (reference: http://jingfenghanmax.blogspot.com/2010/01/use-qmake-include-file-pri.html )

    2. Next: can a project such as 'Device1' contain both a *.pro and a *.pri so other projects can leverage it? For instance - currently Device1/ and Device2/ are producing independent executables, while linking against common code. I've now been asked for a program that includes Device1 and Device2 components within a unified interface and single executable. (C++ wise and GUI wise this makes sense. It's the QT-Framework/Buildsystem I'm still grasping.) I think it will looks like:

    /app/src/Device1/ [Device1.pro | TEMPLATE=App]  [Device1.pri ?]
    /app/src/Device2/ [Device2.pro | TEMPLATE=App]  [Device2.pri ?]
    /app/src/common/  [common.pri]
    /app/src/UnifiedApp/ [UnifiedApp.pro | TEMPLATE=App]
    /app/builds/
    /app/docs/
    
    1. Last and least, why do you recommend /app/ have a qt .pro file? Is it because of the /app/builds/ folder? After trying both I currently have things working with /apps/src/src.pro [TEMPLATE=SUBDIRS] as the top QT-Project node to open in QT-Creator. Can you offer clearer insight why, if /app/app.pro is still best?

    Just to clarify /app/ is our overall Application's top-level including .git root and non-QT folders such as /docs/. The only two QT related dirs are: non-versioned /apps/builds/ for transient QT generated binaries and /apps/src/ which was the intended root for all source-code, projects and everything QT.

    Your first response was a big help! Sorry I'm so verbose, I greatly appreciate any further guidance you (or the community :) can offer.

    /app/src/src.pro:
    -------------------
    TEMPLATE = subdirs
    SUBDIRS += \
        Device1 \
        Device2 \
    
    #eof
    
    
    /app/src/common/common.pri
    -------------------
    # http://jingfenghanmax.blogspot.com/2010/01/use-qmake-include-file-pri.html
    
    # QT += qml quick network
    INCLUDEPATH += $$PWD
    
    HEADERS += \
        $$PWD/DeviceBase.h \
        $$PWD/NetworkWrapper.h \
        $$PWD/Stuff.h \
    
    SOURCES += \
        $$PWD/DeviceBase.cpp \
        $$PWD/NetworkWrapper.cpp \
        $$PWD/Stuff.cpp
    
    #eof
    
    
    /app/src/Device1/Device1.pro
    -------------------
    TEMPLATE = app
    QT += quick qml network
    
    DEPENDPATH += $$PWD/../common/
    INCLUDEPATH += $$PWD/../common/
    TARGET = Device1
    
    HEADERS += \
        Device1.h \
        foo.h
    
    SOURCES += \
        Device1.cpp \
        foo.cpp \
        main.cpp
    
    RESOURCES += device1.qrc
    include(../common/common.pri)
    
    
    # These files display in project-tree below 'QML',
    # at the same level as 'Sources' and 'Headers' where I would expect.
    DISTFILES += \
        foo.qml \
        bar.qml
    
    # *ALL* my QML files (including main.qml) auto-magically appear in the project-tree under:
    # 'Resources | device1.qrc | / | [*.qml]
    
    #eof
    

  • Lifetime Qt Champion

    1. Yes $$PWD is the right thing to do

    2. Yes they can, nothing wrong with that. Furthermore, if you write Device1.pri correctly you can include it in Device1.pro so you have code duplication.

    3. Because a project is not only code, you could have other things like unit tests, documentation to generate etc.

    Also, I avoid having build artefacts in my sources and do out of source builds to keeps things cleanly separated.



  • @SGaist
    I sincerely want to thank you for your help! This project took six-months and your assistance was crucial in getting over the goal line in the final week. If I missed that hard deadline my six-month contract-to-hire would have been terminated. Partly because of your assistance I made it work and was hired full-time permanent! We shipped Version 1.0 and two weeks later I delivered a significant V1.1 follow up!.

    I momentarily had it setup as a (static?)linked library but backtracked to direct #includes from the /common/ folder, mainly because I understood it better. I intend to switch again to the library method because of compile times as you suggested. I was also scared off by an article suggesting I would need to add C++ #EXTERN statements, etc. to create a public interface for the library. Is that true, or can the .pro/.pri files define that folder as a library with NO changes to the C++?

    I still have to migrate *.qml files to the /common/ but I assume it's basically the same pattern as the C++. I haven't replied because I thought I had more questions but the project has been moving too rapidly.

    Thank you!



Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.