QSql, QSqlDatabase includes do not exist
-
I am running 6.4 Qt and Qt Creator 8. I have a QML application organized as shown below. All directories have their own CMakeLists.txt and the application compiles and runs without issue - until I try and use Qt Sql.
I have no idea what is going wrong and appreciate any help.
All my other includes such as QObject, QCoreApplication work just fine.
My Qt installation is a download (not built by me) and updated to 6.4.
Project root directory
main.qml
main.cpp
my.qml
importdata directory
stuff for this - cpp, header, qml file
fldbase directory
stuff for this - cpp, headerI've gone through the docs and in my project root CMakeLists.txt I have
find_package(Qt6 Required Components Sql)
target_link_libraries(myapp PRIVATE Qt6:Sql)If I do #include <QSql> in main.cpp it is recognized. However if I go into the fldbase.h and put #include <QSql> I'm told QSql file is not found.
I've tried putting the find SQL and library in my fldbase CMakeLists.txt file but that did not work.
fldabase CMakeLists.txt file.
# CMakeLists.txt to build import backend. qt_add_library(fldbase_module STATIC) qt6_add_qml_module(fldbase_module URI fldbase VERSION 1.0 QML_FILES FLDBase.qml SOURCES fldbase.h fldbase.cpp ) And my main CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(FlightLog VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_CXX_STANDARD_REQUIRED ON)Set application name for use in building.
set(appName "FlightLogbook")
find_package(Qt6 COMPONENTS Quick REQUIRED)
Core is probably redundant due to Quick find
find_package(Qt6 REQUIRED COMPONENTS Core
Qml
Sql
)
#find_package(Qt6 COMPONENTS Qml REQUIRED)
#find_package(Qt6 REQUIRED COMPONENTS Sql)Standard project setup
#qt_standard_project_setup()
The executable
qt_add_executable(FlightLogbook
main.cpp
)#==============================================================================
Our subdirectories
add_subdirectory(
importdata
)
add_subdirectory(
fldbase
)#==============================================================================
QML and other files
qt_add_qml_module(FlightLogbook
URI FlightLog
VERSION 1.0
QML_FILES
main.qml
Initapp.qml
)set_target_properties(FlightLogbook PROPERTIES
MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
MACOSX_BUNDLE TRUE
WIN32_EXECUTABLE TRUE
)Added Core, Qml as private libraries
target_link_libraries(FlightLogbook
PRIVATE Qt6::Core
PRIVATE Qt6::Quick
PRIVATE Qt6::Qml
PRIVATE Qt6::Sql
)#==============================================================================
Our libraries
target_link_libraries(
FlightLogbook
PRIVATE import_moduleplugin
PRIVATE fldbase_moduleplugin
)Attempting to put the runtime result in the directory above the build
install(TARGETS FlightLogbook
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ..
) -
Hi,
Are you sure you are linking the library to all the modules you create ?
-
To be honest, no <G>! I thought I was by including it in the project root CMakeLists.txt but when that did not work I added the find and library link to the fldbase CMakeLists.txt and removed them from the main module but maybe I did it wrong.
This is what I put in the fldbase CMakeLists.txt
# CMakeLists.txt to build import backend. find_package(Qt6 REQUIRED COMPONENTS Sql) qt_add_library(fldbase_module STATIC) qt6_add_qml_module(fldbase_module URI fldbase VERSION 1.0 QML_FILES FLDBase.qml SOURCES fldbase.h fldbase.cpp ) target_link_libraries(fldbase_module PRIVATE Qt6::Sql)
-
Did you already saw the Building a QML application chapter in Qt's documentation ?
-
Yes, I've seen that many times as well as a lot of others such as the CMake and QML modules blogs plus lots of research. While that article is a good start it assumes everything is in one directory. I could have directories and one CMakeLists.txt file in the project root and just add modules and sources as somedir/something.cpp, etc without any other CMakeLists.txt and in fact that's what I did originally to get started. However, I wanted to break things into logical groupings using directories which is what Qt seems to recommend so I moved things to appropriate directories.
I am not sure what changed but I added the find and target link to the fldbase CMakeLists.txt and left it in the project root CMakeLists.txt and it now works. The QSql includes are recognized in my fldabase.h. So it appears I need them in the project CMakeLists.txt as well as any other CMakeLists.txt for modules that need them.
-
It depends whether the code used in these modules exposes the Qt SQL module.
If you have included QtSql in your class header, then all the applications/librairies that will use it must know the QtSQL module. Most of the time there's no need to include anything from the QtSql module in your own class headers.
-
I guess I'm not sure what you mean. Initially I added it in my class header #include <QtSql> but it said it couldn't find the file so then I remembered I had to tell CMakeList.txt to find the package so I did that in my top project CMakeList.txt but that still told me the fldbase.h could not find the file. So I then moved the find package and target_link_library to the fldbase/CMakeList.txt file but that didn't work.
I now have the find_packaged for Sql and the target_link_library in both the main project CMakeLists.txt and the fldbase CMakeList .txt and it works now.
-
That's exactly what I am describing. You library leaks the need for the SQL module because you use the module include in the header file.
- Never use the module includes in your code, they pull in at least all the classes modules. They are fine for demonstration purpose but that stops there.
- Apply the "include where you use" mantra. For the rest of the time, use forward include. That will make you builds both simpler and lighter.
-
@SGaist said in QSql, QSqlDatabase includes do not exist:
That's exactly what I am describing. You library leaks the need for the SQL module because you use the module include in the header file.
- Never use the module includes in your code, they pull in at least all the classes modules. They are fine for demonstration purpose but that stops there.
- Apply the "include where you use" mantra. For the rest of the time, use forward include. That will make you builds both simpler and lighter.
I am not sure I follow what you are saying so let me see if I understand.
What do you mean by module includes - is that like <QTSql> being included?
- Are you saying don't put #include <QtSql> in my class header file fldbase.h since it's in the CMakeLists.txt it will be used or am I NOT supposed to have it in the CMakeLists.txt file? What I ran into was that if I put #include <QSqlDatabase> in my header file I ended up with an unknown file error until I added them to the CMakeLists.txt files.
- That's what I do. I only use the fldbase.h header in the fldabase class at this point.
I will read up on the forward include. So far I do not use any of the classes anywhere except in themselves. I do not call them from anywhere else but that will change when I do the next phase.
Thanks.
-
Can you show your header file ?
I am currently suspecting that you are doing stuff that is discouraged in the documentation like for example keeping a QSqlDatabase member variable. -
@SGaist said in QSql, QSqlDatabase includes do not exist:
Can you show your header file ?
I am currently suspecting that you are doing stuff that is discouraged in the documentation like for example keeping a QSqlDatabase member variable.Thank you very much for you help.
I'll include the header. As far as I know I do not keep a QSqlDatabase member as I tried to use db.database(connectname, true) to connect to it as warned about in the documentation.
I did get it to work but I had to include the headers for the three modules, Q_IMPORT_QML_PLUGIN for each module and then use the engine.rootContext to get it to recognize the imports in the qml files. At this point I'm suffering from overload on how to do it. I see notes on do not use the setcontext method for some reason but in https://doc.qt.io/qt-6/qqmlcontext.html they use it. Then I see posts with qmlRegisterType<> in main.cpp but is that correct, good, bad, do not use? Given I'm new to Qt6 and it's been so long since I did Qt5 I want to learn the correct methods for working with cmake and Qt6 and not use Qt5 habits just because they work - at some point they will break probably.
I would very much like Qt to have a comprehensive document for Qt6 approved methods of building with cmake and integrating QML and C++ (using functions from C++ in QML and setting properties, etc) which includes how they want things registered in an approved fashion. Much is available but it's in bits and pieces across various class documentation so it becomes a treasure hunt and in some case uses methods were aren't supposed to use.
Here are the header files. I have three modules in three directories.
Project root directory
main.qml
main.cpp
fldbase directory
cpp, h, CMakeLists.txt files, qml file
importdata directory
cpp, h, CMakeLists.txt files, qml file
utils directory
cpp, h, CMakeLists.txt files, qml fileHeader for fldbase. I define a QSqlDatabse item in the header and then create a connection in the class constructor.
#ifndef FLDB_H #define FLDB_H // Qt Includes #include <QCoreApplication> #include "qqmlintegration.h" #include <QObject> #include <QtQml/qqmlregistration.h> // Our Includes #include <QDebug> // Database Includes #include <QSqlDatabase> #include <QSqlError> #include <QSqlQuery> #include <QSqlRecord> // File Includes #include <QFile> class FLDBase : public QObject { Q_OBJECT QML_ELEMENT public: explicit FLDBase(QObject *parent = nullptr); signals: public slots: bool fldbready(); //QString dbname, QString driverType, QString connName); void fldbclose(); int tests(int num); private: bool fdbexists(QString dbname, QString dbdriver); QSqlDatabase fldb; QString fldbconn = "fldbconnection"; QString driverType = "QSQLITE"; QString dbname = "flightlog.db"; int sqliterowcount(QSqlDatabase dbase); }; // End class FLDB definition #endif // FLDB_H
FLDBase class constructor.```
FLDBase::FLDBase(QObject *parent)
: QObject{parent}
{
fldb = QSqlDatabase::addDatabase(driverType, fldbconn);
fldb.setDatabaseName(dbname);
fldb.database(fldbconn, true);
}Header for import data
#ifndef IMPORTDATA_H
#define IMPORTDATA_H// Qt Includes
#include <QCoreApplication>
#include "qqmlintegration.h"
#include <QObject>
#include <QVariant>
#include <QUrl>
#include <QAbstractTableModel>
#include <QAbstractItemModel>
#include <QtQml/qqmlregistration.h>
#include <QVector>
#include <QFile>
#include <QTextStream>// Our Includes
#include <QDebug>class ImportData : public QObject
{
Q_OBJECT
QML_ELEMENTpublic: explicit ImportData(QObject *parent = nullptr);
signals:
void status(QVariant data);public slots:
void bark(); // For testing - remove later.
QString readdata(QString src, QString infile);private:
QString m_datafile;
QVector<QVector<QString>> m_rawdata;
QVector<QString> m_tmpdata;// For csv input data char m_csvdelim = ',';
}; // End class ImportData definition
#endif // IMPORT_H
Header for utils.
#ifndef UTILS_H
#define UTILS_H
// Qt Includes
#include <QCoreApplication>
#include "qqmlintegration.h"
#include <QtQml/qqmlregistration.h>
#include <QObject>
#include <QUrl>
#include <QDir>// Our Includes
#include <QDebug>class Utils : public QObject
{
Q_OBJECT
QML_ELEMENTpublic:
explicit Utils(QObject *parent = nullptr);Q_INVOKABLE QString urltonativepath(const QUrl& urlpath);
signals:
};
#endif // UTILS_H
And main.cpp
//Qt Includes
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml/QQmlExtensionPlugin>
#include <QQmlContext>
#include <QQuickView>// Our Includes
#include "importdata/importdata.h"
#include "fldbase/fldbase.h"
#include "utils/utils.h"
//class Utils;// Plugins
Q_IMPORT_QML_PLUGIN(importdataPlugin)
Q_IMPORT_QML_PLUGIN(fldbasePlugin)
Q_IMPORT_QML_PLUGIN(utilsPlugin)int main(int argc, char *argv[])
{
QCoreApplication::setOrganizationName("Dakota Pilot");
QCoreApplication::setOrganizationDomain("dakotapilot.com");
QCoreApplication::setApplicationName("Flight Log");QGuiApplication app(argc, argv); QQmlApplicationEngine engine;
//=============================================================================
// Add our stuff to the root context.
ImportData getdata;
FLDBase fldbase;
Utils utils;engine.rootContext()->setContextProperty("datain", &getdata); engine.rootContext()->setContextProperty("fldbase", &fldbase); engine.rootContext()->setContextProperty("utils", &utils);
//=============================================================================
// Standard Qt, QML items.
const QUrl url(u"qrc:/FlightLog/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);return app.exec();
}
-
private:
bool fdbexists(QString dbname, QString dbdriver);
QSqlDatabase fldb;This is exactly what you should not do.
-
@SGaist said in QSql, QSqlDatabase includes do not exist:
private:
bool fdbexists(QString dbname, QString dbdriver);
QSqlDatabase fldb;This is exactly what you should not do.
Thank you for taking the time to help me sort this out.
Okay. So how do I do that. Do I remove the QSqlDatabase fldb and then define it in the constructor for the class by doing the QSqlDatabase in there and then open it? What exactly does what I did do. I assume it creates a copy bound to the class and that is not good.
I'm still confused about the use of Q_PLUGIN_QML and registering the modules in main.cpp.
As I thought I understood the process it was that if I build the modules in CMakeLists.txt for the project and it's modules it would be able to find the modules and I could simply import them with import statements using the URI in the QML modules. But I see some posts and Qt documentation that say I need to use the Q_QML_PLUGIN and I need to add the set context property. If I don't do that then the QML modules import statements tell me they can't find the file.
-
@RangerQT said in QSql, QSqlDatabase includes do not exist:
Do I remove the QSqlDatabase fldb and then define it in the constructor for the class by doing the QSqlDatabase in there and then open it?
Yes. Only use
QSqlDatabase fldb
as a local variable in a function which needs it, such as when opening it initially. Why do you need it (the variable) after that anyway?QSqlQuery
etc. will automatically use it for you as your default database; if you do want to get at it for some reason use the static QSqlDatabase QSqlDatabase::database() call to access it.What exactly does what I did do. I assume it creates a copy bound to the class and that is not good.
Exactly that. And Qt does not like you doing this! It keeps a reference around in your class, and interferes with Qt's code to release it when closing down.