[SOLVED] Qt Quick SUBDIRS dependency problem
-
wrote on 8 Mar 2015, 15:31 last edited by DRoscoe 3 Aug 2015, 18:43
I have a large Qt Quick SUBDIRS project that is driving me nuts. I can find no clear way of specifying linking dependencies between subprojects. The project consists of many statically linked libraries and a single application which links them all:
CONFIG += c++11
TEMPLATE = subdirsSUBDIRS +=
aop_logger
aop_xml
aop_serial
aop_util
aop_measure
MathUtilities
DataCollection
DebugLogger
MoreMath
AvionicsBus
AircraftDataModel
WindModel
TableLookups
dna
aop_data
aop_comm
tap_data
configuration
AtosUtils
tap_messaging
BufferedSharedMemory
aop_interface
tap_new_display_appAccording to the documentation I was able to find, I configured all of my library subprojects as:
TEMPLATE = lib
CONFIG += staticlib create_prl c++11I have confirmed that the .PRL files are being created.
The application project, which is another subproject of the primary SUBDIRS project is configured as:
TEMPLATE = app
CONFIG += c++11 link_prlQT += qml quick widgets
SOURCES += $$files(.cpp)
HEADERS += $$files(.hpp)RESOURCES += qml.qrc
QML_IMPORT_PATH =
include(deployment.pri)
All of the libraries compile as does the main app project. When Qt tries to link the projects, I get messages like these:
Undefined symbols for architecture x86_64:
"dna::Repository::Repository()", referenced from:
ACE_Singleton<dna::Repository, ACE_Recursive_Thread_Mutex>::ACE_Singleton() in libaop_interface.a(FmcGeneralOutputChannelData.o)Here is the .PRO file for libaop_interface.a:
include(../top_srcdir.pri)
include(../ace_path.pri)QT -= core gui
TARGET = aop_interface
TEMPLATE = lib
CONFIG += staticlib c++11 create_prl link_prlINCLUDEPATH += $$aop_srcdir/core/aop_comm
$$aop_srcdir/core/configuration
$$aop_srcdir/core/aop_data
$$aop_srcdir/core/aop_data/nav_db
$$aop_srcdir/core/aop_data/navigation
$$aop_srcdir/core/aop_data/route
$$aop_srcdir/core/aop_data/hazards
$$aop_srcdir/core/dna
$$aop_srcdir/core/aop_logger
$$aop_srcdir/core/aop_interface
$$aop_srcdir/core/aop_interface/exception
$$aop_srcdir/core/aop_interface/data_format
$$aop_srcdir/core/aop_measure
$$aop_srcdir/core/aop_measure/dimensions
$$aop_srcdir/core/aop_measure/properties
$$aop_srcdir/core/aop_measure/units
$$aop_srcdir/core/aop_serial
$$aop_srcdir/core/aop_util
$$aop_srcdir/core/aop_xml
$$cto4_srcdir
$$cto4_srcdir/Communication
$$cto4_srcdir/Communication/AvionicsBus
$$cto4_srcdir/RouteContainerSOURCES += $$files($$aop_srcdir/core/aop_interface/data_format/.cpp)
SOURCES += $$files($$aop_srcdir/core/aop_interface/exception/.cpp)
SOURCES += $$files($$aop_srcdir/core/aop_interface/*.cpp)HEADERS += $$files($$aop_srcdir/core/aop_interface/data_format/.hpp)
HEADERS += $$files($$aop_srcdir/core/aop_interface/exception/.hpp)
HEADERS += $$files($$aop_srcdir/core/aop_interface/*.hpp)unix {
target.path = /usr/lib
INSTALLS += target
}The library libdna.a does exist and it has the symbol(s) mentioned above. The problem is that Qt doesn’t know how to link libdna from libaop_interface.a. Since the create_prl and link_prl semantics are supposed to allow Qt to follow library dependencies, I checked the .PRL file for libaop_interface.a and I see the following:
QMAKE_PRL_BUILD_DIR = /Users/droscoe/Documents/workspace/dar_tap_display_20150209_view/aop/external/build-tap_new_display-Desktop_Qt_5_4_0_clang_64bit-Debug/aop_interface
QMAKE_PRO_INPUT = aop_interface.pro
QMAKE_PRL_TARGET = libaop_interface.a
QMAKE_PRL_CONFIG = lex yacc debug exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin sdk rez qt warn_on link_prl app_bundle incremental global_init_link_order lib_version_first plugin_no_soname clang_pch_style qpa no_mocdepend qt_framework osx macx mac darwin unix posix gcc clang llvm debug x86_64 declarative_debug qml_debug staticlib c++11 create_prl link_prl have_target static staticlib debug_info objective_c thread
QMAKE_PRL_VERSION = 1.0.0
QMAKE_PRL_LIBS =Notice, the QMAKE_PRL_LIBS line lists no libs. On a hunch, I manually added the path to libdna.a to QMAKE_PRL_LIBS and the problem was resolved. This is not a solution since this PRL will be re-created every time I run make or clean/rebuild the project.
My questions are:
-
How can I tell Qt that libaop_interface is dependent on libdna and several other libraries, such that the PRL file contains the correct library paths.
-
Is there a better/preferred way to do this? I have read that I could modify the .depends of the library, but this only works for makefile-based projects. My project needs to run on Windows, MacOS and iOS and not all of these support make
I appreciate any help.
-
-
In a SUBDIRS project, you can use the "ordered" configuration to tell qmake to parse and build subdirs in the order they are specified:
CONFIG+=ordered
I think this should help you make sure everything is compiled when it should and has all the dependencies.
-
wrote on 8 Mar 2015, 16:43 last edited by
Ordering the build does not solve the problem. The individual libraries all build by themselves, regardless of order. Because they are statically linked, the dependencies are not checked until they are linked at the end. Its the linking at the end that isn't working.
-
wrote on 8 Mar 2015, 18:23 last edited by
I have some new information. Because some libraries are common to several other libraries, I have .pri files which handle setting up the library dependency information. For example, libdna, which is required by libaop_interface (see original post). Here is what the dna.pri file looks like:
include (top_srcdir.pri)
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../dna/release/ -ldna
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../dna/debug/ -ldna
else:unix: LIBS += -L$$OUT_PWD/../dna/ -ldnaINCLUDEPATH += $$aop_srcdir/core/dna
DEPENDPATH += $$aop_srcdir/core/dnawin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/release/libdna.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/debug/libdna.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/release/dna.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/debug/dna.lib
else:unix: PRE_TARGETDEPS += $$OUT_PWD/../dna/libdna.aWhen I include this file in my aop_interface project file, I still have the same problem as stated above. Here is the resulting .PRL file for libaop_interface.a:
QMAKE_PRL_BUILD_DIR = /Users/droscoe/Documents/workspace/dar_tap_display_20150209_view/aop/external/build-tap_new_display-Desktop_Qt_5_4_0_clang_64bit-Debug/aop_interface
QMAKE_PRO_INPUT = aop_interface.pro
QMAKE_PRL_TARGET = libaop_interface.a
QMAKE_PRL_CONFIG = lex yacc debug exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin sdk rez qt warn_on link_prl app_bundle incremental global_init_link_order lib_version_first plugin_no_soname clang_pch_style qpa no_mocdepend qt_framework osx macx mac darwin unix posix gcc clang llvm debug x86_64 declarative_debug qml_debug staticlib c++11 create_prl link_prl have_target static staticlib debug_info objective_c thread
QMAKE_PRL_VERSION = 1.0.0
QMAKE_PRL_LIBS =Note that QMAKE_PRL_LIBS is blank. However, if I use the Qt Creator "Add Library" wizard and specify "dna" as an internal library, the resulting .PRL appears to be correct:
QMAKE_PRL_BUILD_DIR = /Users/droscoe/Documents/workspace/dar_tap_display_20150209_view/aop/external/build-tap_new_display-Desktop_Qt_5_4_0_clang_64bit-Debug/aop_interface
QMAKE_PRO_INPUT = aop_interface.pro
QMAKE_PRL_TARGET = libaop_interface.a
QMAKE_PRL_CONFIG = lex yacc debug exceptions depend_includepath testcase_targets import_plugins import_qpa_plugin sdk rez qt warn_on link_prl app_bundle incremental global_init_link_order lib_version_first plugin_no_soname clang_pch_style qpa no_mocdepend qt_framework osx macx mac darwin unix posix gcc clang llvm debug x86_64 declarative_debug qml_debug staticlib c++11 create_prl link_prl have_target static staticlib debug_info objective_c thread
QMAKE_PRL_VERSION = 1.0.0
QMAKE_PRL_LIBS = -L/Users/droscoe/Documents/workspace/dar_tap_display_20150209_view/aop/external/build-tap_new_display-Desktop_Qt_5_4_0_clang_64bit-Debug/aop_interface/../dna/ -ldnaThis makes no sense to me. The effect of including the dna.pri file and using the wizard are virtually identical, yet one method produces the correct behavior and the other does not. Here is what the "Add Library" wizard added to my aop_interface.PRO file:
win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../dna/release/ -ldna
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../dna/debug/ -ldna
else:unix: LIBS += -L$$OUT_PWD/../dna/ -ldnaINCLUDEPATH += $$PWD/../../../core/dna
DEPENDPATH += $$PWD/../../../core/dnawin32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/release/libdna.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/debug/libdna.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/release/dna.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$OUT_PWD/../dna/debug/dna.lib
else:unix: PRE_TARGETDEPS += $$OUT_PWD/../dna/libdna.aThe only difference between the two is the definition of $$aop_srcdir which is defined by including top_srcdir.pri. This is so I have a common starting point for relative paths. I have confirmed that the variable expands to be essentially the exact same location in the source tree, so the behavior baffles me
-
wrote on 8 Mar 2015, 18:47 last edited by
Ok, I think I have resolved the problem. Apparently, you have to make sure you explicitly tell qmake which libraries you depend on via "Add Library" or other means, such as my approach, which is including a common .pri file. The reason it didn't work before is because I did not re-run qmake after making the change. When I saved the file, It parsed the file, etc, but apparently did not completely rebuild the project files. The project previously built and run, but I was apparently not actually referencing any external library functions from my application and Qt was smart enough to know that there were no dependencies introduced. It wasn't until my application actually tried to use an imported library function that it started complaining.
The documentation in this regard is really rather vague and I have found myself having to plod through, trying to figure this things out as I went along. In hindsight it makes sense that I should have to explicitly spell out the dependencies, otherwise how will qmake know what to add to the PRL file?
1/5