[SOLVED] Qt Quick SUBDIRS dependency problem



  • 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 = subdirs

    SUBDIRS +=
    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_app

    According to the documentation I was able to find, I configured all of my library subprojects as:

    TEMPLATE = lib
    CONFIG += staticlib create_prl c++11

    I 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_prl

    QT += 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_prl

    INCLUDEPATH += $$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/RouteContainer

    SOURCES += $$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:

    1. 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.

    2. 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.


  • Moderators

    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.



  • 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.



  • 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/ -ldna

    INCLUDEPATH += $$aop_srcdir/core/dna
    DEPENDPATH += $$aop_srcdir/core/dna

    win32-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.a

    When 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/ -ldna

    This 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/ -ldna

    INCLUDEPATH += $$PWD/../../../core/dna
    DEPENDPATH += $$PWD/../../../core/dna

    win32-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.a

    The 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



  • 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?


Log in to reply
 

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