0

I am trying to build a simple application in QML that when a button was pressed an external program was lanch. I search a lot, but 99% of the solutions are similar to this. When I compile the error is:

Undefined symbols for architecture x86_64:
"ProcessStarter::qt_metacall(QMetaObject::Call, int, void**)", referenced from:
  vtable for QQmlPrivate::QQmlElement<ProcessStarter> in main.o
"ProcessStarter::qt_metacast(char const*)", referenced from:
  vtable for QQmlPrivate::QQmlElement<ProcessStarter> in main.o
"ProcessStarter::staticMetaObject", referenced from:
  int qmlRegisterType<ProcessStarter>(char const*, int, int, char const*) in main.o
  QtPrivate::MetaObjectForType<ProcessStarter*, void>::value() in main.o
  QMetaTypeIdQObject<ProcessStarter*, 8>::qt_metatype_id() in main.o
"ProcessStarter::metaObject() const", referenced from:
  vtable for QQmlPrivate::QQmlElement<ProcessStarter> in main.o
"typeinfo for ProcessStarter", referenced from:
  typeinfo for QQmlPrivate::QQmlElement<ProcessStarter> in main.o
"vtable for ProcessStarter", referenced from:
  ProcessStarter::ProcessStarter(QObject*) in main.o
NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

The code of main.cpp is:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

#include <QProcess>
#include <QVariant>
#include <QQmlContext>

class ProcessStarter : public QProcess
{
    Q_OBJECT

public:
    ProcessStarter(QObject *parent = 0) : QProcess(parent) { }
    virtual ~ProcessStarter() = default;

    Q_INVOKABLE void start(const QString &program, const QVariantList &arguments)
    {
        QStringList args;

        // convert QVariantList from QML to QStringList for QProcess

        for (int i = 0; i < arguments.length(); i++)
            args << arguments[i].toString();

        QProcess::start(program, args);
    }

    Q_INVOKABLE QByteArray readAll() {
        return QProcess::readAll();
    }

};

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qmlRegisterType<ProcessStarter>("Process", 1, 0, "ProcessStarter");

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    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();
}

Instead the main.qml is:

import QtQuick 2.12
import QtQuick.Controls 2.0
import QtQuick.Window 2.12

import Process 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    ProcessStarter {
        id: process
        onReadyRead: console.info(readAll())
    }

    Button {
        onClicked: {
            process.start("../prova", [ "-a", "-b"])
        }
    }

}

I can't understand where is the mistake! Regards Marco

warcomeb
  • 13
  • 5
  • 1
    You have a problem with MOC, the process in qt compilation that adds some functions to your class (for example `qt_metacall`). This might be due to putting the class in main.cpp, while MOC only scans .h files. Try putting it in a separate .h + .cpp file – Amfasis Feb 25 '21 at 08:46
  • it works! Tanks! It's the first time that I put a class into main.cpp and I never experienced this issue. – warcomeb Feb 26 '21 at 09:03

0 Answers0