Use ECMGenerateExportHeader to manage deprecated API better
ClosedPublic

Authored by kossebau on Mon, Oct 7, 1:26 PM.

Details

Summary

Allows

  • projects linking to KXmlGui to hide deprecated API up to a given version or silence deprecation warnings after a given version, using
    • -DKXMLGUI_DISABLE_DEPRECATED_BEFORE_AND_AT
    • -DKXMLGUI_NO_DEPRECATED
    • -DKXMLGUI_DEPRECATED_WARNINGS_SINCE
    • -DKXMLGUI_NO_DEPRECATED_WARNINGS

      or
    • -DKF_DISABLE_DEPRECATED_BEFORE_AND_AT
    • -DKF_NO_DEPRECATED
    • -DKF_DEPRECATED_WARNINGS_SINCE
    • -DKF_NO_DEPRECATED_WARNINGS
  • to build KXmlGui optionally with deprecated API excluded from the build, using "EXCLUDE_DEPRECATED_BEFORE_AND_AT" cmake argument.
Test Plan

Builds with EXCLUDE_DEPRECATED_BEFORE_AND_AT set to 0, 4.1.0, 5.0.0,
CURRENT.

Diff Detail

Repository
R263 KXmlGui
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.
kossebau created this revision.Mon, Oct 7, 1:26 PM
Restricted Application added a project: Frameworks. · View Herald TranscriptMon, Oct 7, 1:26 PM
Restricted Application added a subscriber: kde-frameworks-devel. · View Herald Transcript
kossebau requested review of this revision.Mon, Oct 7, 1:26 PM

If no-one objects, would be pushing on Monday evening, Oct. 14th.

kossebau updated this revision to Diff 67733.Fri, Oct 11, 5:31 PM
  • disable KF group deprecation macros for now
  • set DEPRECATED_BASE_VERSION=0, to not disable any API by default
mlaurent accepted this revision.Sat, Oct 12, 7:00 AM
This revision is now accepted and ready to land.Sat, Oct 12, 7:00 AM
dfaure added inline comments.Sat, Oct 12, 7:44 PM
src/kactioncollection.h
278

Does this work? It's a signal. Won't this only warn at emit time? (while QT_MOC_COMPAT is what leads to a warning at connect time)

Asking because you didn't do this in D24465 for the windowChanged() signals, so something seems inconsistent.

314–315

(pre-existing) QT_MOC_COMPAT for a slot? Any idea what this might do?

kossebau added inline comments.Sat, Oct 12, 8:39 PM
src/kactioncollection.h
314–315

No idea. I started a few times to look up what QT_MOC_COMPAT actually is about, but never had quick results, so delayed into the future.

Just had a look again, but as before stranding with MethodCompatibility from qmetaobject_p.h, which seems though nowhere really used.

So far my guess has been this is some relict from Qt3 times no-one ever properly cleaned up?

kossebau added inline comments.Sat, Oct 12, 9:13 PM
src/kactioncollection.h
278

This being one of my experimental repos chance is I forgot to remove the KXMLGUI_DEPRECATED_VERSION here, and was blind when I checked the patch before uploading.
Let me check again if the deprecated attribute actually gets triggered on memberfunction-pointer based connect, not sure right now,

dfaure added inline comments.Sat, Oct 12, 9:30 PM
src/kactioncollection.h
314–315

Taking this from the other side: warnings when connecting to deprecated signals actually work. They happen in check_and_warn_compat in qobject.cpp

... this does support warning about connecting to compat slots, so my comment was bogus, this is fine.

For the usual case, compat signals, the code checks signal.attributes() & QMetaMethod::Compatibility.

Ah and I found where MethodCompatibility (which has the value 0x10) is actually set...
the generated moc code says

6,    2,   89,    2, 0x06 /* Public */,
8,    2,   94,    2, 0x16 /* Public | MethodCompatibility */,

See the second line, it has the 0x10 value in there, which means MethodCompatibility is set.... by value, not by name.

I'm just still a bit confused about the relation between the 0x10 metaobject flag and the signal attribute which has value 0x1...

enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };

But it must work, tst_qobject.cpp tests that QT_MOC_COMPAT ends up setting QMetaMethod::Compatibility in attributes().

Anyhow, I still believe that using the *_DEPRECATED macro on a signal only makes sense if we want to prevent subclasses from emitting the signal. Theoretical possibility, extremely unlikely for KActionCollection, but... why not. We can do this consistently everywhere without the need to consider the likeliness of subclasses, I suppose.

kossebau added inline comments.Mon, Oct 14, 12:58 PM
src/kactioncollection.h
314–315

Okay, so "QT_MOC_COMPAT" is still a (just undocumented) thing, and thus something we should use for deprecated signal/slots then as before, right?

Had now another look based on your info, and found that the magic to map 0x10 onto 0x1 happens in the getter of the method attributes:

int QMetaMethod::attributes() const
{
    if (!mobj)
        return false;
    return ((mobj->d.data[handle + 4])>>4);
}

So that mystery seems solved :)

For adding deprecation attributes via _DEPRECATED to signals, yes, would agree to do this consistently then, following your argumentation. Will add this to the howtodeprecateallkindsofapi text I yet have to write, so far delayed to first gather experience.

kossebau added inline comments.Mon, Oct 14, 1:10 PM
src/kactioncollection.h
314–315

Just remembered though: seems that Qt code itself no longer uses QT_MOC_COMPAT? At least I had no hits for actual usages in Qt classes when searching in my local Qt headers, via code.woboq.org or github search, there only for the old unsplit qt repo (which once made me think this is a Qt3 relict).

And given the #ifndef QT_NO_DEBUG does this warning land in normal Qt builds? (sorry, not build Qt in a decade).
till have to test with my openSUSE TW, will do later today.

Maybe Qt doesn't have any deprecated signals?

Maybe Qt doesn't have any deprecated signals?

That would be nice :) A few there are though, e.g. see here some for QComboBox, only using QT_DEPRECATED_SINCE & QT_DEPRECATED_VERSION_X, but not QT_MOC_COMPAT:
https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qcombobox.h.html#223

Perhaps people forgot about it, the macro also not being documented anywhere.

Now finally got around to do some test code to check deprecation with signal/slots:

#include <QObject>
#include <QCoreApplication>
#include <QDebug>

class Object : public QObject
{
    Q_OBJECT

public Q_SLOTS:
    Q_DECL_DEPRECATED
    QT_MOC_COMPAT
    void slotIt() {
        qDebug() << "handling signal";
    }

Q_SIGNALS:
    Q_DECL_DEPRECATED
    QT_MOC_COMPAT
    void signalIt();
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    Object object;
    QObject::connect(&object, SIGNAL(signalIt()), &object, SLOT(slotIt()));
    QObject::connect(&object, &Object::signalIt, &object, &Object::slotIt);

    emit object.signalIt();

    return 0;
}

#include "main.moc"

When building this gives:

main.cpp: In function ‘int main(int, char**)’:
main.cpp:29:40: warning: ‘void Object::signalIt()’ is deprecated [-Wdeprecated-declarations]
   29 |     QObject::connect(&object, &Object::signalIt, &object, &Object::slotIt);
      |                                        ^~~~~~~~
main.cpp:20:10: note: declared here
   20 |     void signalIt();
      |          ^~~~~~~~
main.cpp:29:68: warning: ‘void Object::slotIt()’ is deprecated [-Wdeprecated-declarations]
   29 |     QObject::connect(&object, &Object::signalIt, &object, &Object::slotIt);
      |                                                                    ^~~~~~
main.cpp:13:10: note: declared here
   13 |     void slotIt() {
      |          ^~~~~~
main.cpp:31:26: warning: ‘void Object::signalIt()’ is deprecated [-Wdeprecated-declarations]
   31 |     emit object.signalIt();
      |                          ^
main.cpp:20:10: note: declared here
   20 |     void signalIt();
      |          ^~~~~~~~

and when running just

handling signal
handling signal

so no runtime warning about the compat signal or slot. Possibly as QT_NO_DEBUG is said to be defined for Qt release builds, so check_and_warn_compat will not be run.

So having a _DEPRECATED with signal makes sense also for consumers connecting to the signal with memberfunction-pointer based connect. Will adapt the other patches accordingly.

Not sure what to do about the QT_MOC_COMPAT, so far it should not hurt to keep them, but the question is how useful adding new ones is and whether this is future-proof.

Thanks for the investigation.

check_and_warn_compat does not warn for this testcase because the slot is deprecated too.
Try a deprecated signal and a non-deprecated slot :-)

2714│     if (signal.attributes() & QMetaMethod::Compatibility) {
2715│         if (!(method.attributes() & QMetaMethod::Compatibility))
2716│             qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)",
2717│                      sender->className(), signal.methodSignature().constData());

check_and_warn_compat does not warn for this testcase because the slot is deprecated too.
Try a deprecated signal and a non-deprecated slot :-)

2714│     if (signal.attributes() & QMetaMethod::Compatibility) {
2715│         if (!(method.attributes() & QMetaMethod::Compatibility))
2716│             qWarning("QObject::connect: Connecting from COMPAT signal (%s::%s)",
2717│                      sender->className(), signal.methodSignature().constData());

Ah, missed that combination condition in the code. Though actually, I had tested all combinations before, disabling all or either of the QT_MOC_COMPAT (as you can see, blackbox testing without looking at the Qt code ;) ) , same with Q_DECL_DEPRECATED. And then read that configure --release sets QT_NO_DEBUG, at which point I stopped looking more.

For the record, I get

WARNING: QObject::connect|main QObject::connect: Connecting from COMPAT signal (Object::signalIt())

But indeed that's because I build my Qt in debug mode. The only mode that truly matters for developers :-)

Maybe Qt shouldn't use QT_NO_DEBUG for this. But oh well, as you noticed all of this only matters for the Qt4 macro. Yet another reason to use PMF connect instead....

@dfaure Any remaining issues from your side, or is your +1 available as well now? :)

dfaure accepted this revision.Thu, Oct 17, 2:17 PM

Yep all good from my point of view.

kossebau added inline comments.Thu, Oct 17, 3:08 PM
src/kactioncollection.h
308

Fixed to KXMLGUI_ENABLE_DEPRECATED_SINCE, as slotActionHighlighted is a virtual method, which the compiler needs to always know about.

308

Eh, fixed to KXMLGUI_BUILD_DEPRECATED_SINCE actually :)

This revision was automatically updated to reflect the committed changes.