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:
- Am I using QT Sub-Projects (more-or-less) correctly?
- Must the 'Common' code really be a QT-Project simply because it's a different directory?
- Must the 'Common' code really be a Library simply because it's in an independent directory?
- If so, static or dynamic linked libraries and how do I write the *.pro files correctly?
- 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 -
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
andsrc
both should beSUBDIRS
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
andHEADERS
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.
-
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 ) -
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/
- 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
-
-
-
Yes
$$PWD
is the right thing to do -
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.
-
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!