How usable is Qt without its preprocessing step?
Asked Answered
B

12

66

I think it's unreasonable for a library to require preprocessing of my source code with a special tool. That said, several people have recommended the Qt library to me for cross platform GUI development.

How usable is Qt without the preprocessing step?

EDIT: Okay people, I'm not meaning this question as a rip on Qt -- too many Qt fanboys are treating it as if it is. I don't want to discuss the merits of the fact that Qt came up with this preprocessing tool. I understand why the tool is there, and I understand why there are large parts of Qt's design that are built upon the idea of preprocessing.

I've never used Qt, ergo I am in no position to rip on it. But I would much rather pay in writing a small amount of boilerplate myself and not depend on ripping apart my entire build process. I won't use Flex and Bison in my current project for the same reason; if I won't use those tools, I'm definitely not going to use another kind of preprocessing.

So, please don't take me as ripping on Qt. I cannot comment on how nice or not nice it is; I have not used it. I just want to know if it is possible to use it without moc.

Babi answered 27/8, 2010 at 21:12 Comment(12)
+1 Their moc tool is the main reason I haven't jumped onto the Qt bandwagon.Aver
moc is really only a problem until you actually use it. I used to balk at the idea of an extra preprocessing step, but once I started using Qt instead of just thinking about it, moc ceased to be a nuisance. Especially if you use QMake, moc is almost invisible in practice.Weeny
Qt isn't "just another library" for C++ users. Qt thinks it's a complete, all encompassing framework for all your app development needs (with a scope comparable to the Java SE SDK) and, once you have adopted it's ways (moc and all) you should you should be forever content within it's walled garden.Snag
Just a comment on your EDIT clarification. I suspect you riled up Qt fanboys (like myself) mostly with your opening sentence. "I think it's unreasonable for...". So you should hardly be surprised by responses telling you why it is reasonable.Nickel
@jkerian: See my comment on Steve S's answer. The long and short of it is that there are things that suck about any moderately complex software solution. One of those things for Qt is the requirement of separate preprocessing. I don't like that C++ has completely broken (IMHO) exception specifications. But C++ is still my favorite language. I do think that having preprocessing is unreasonable. That's a major mark against Qt for me, no lie. I think that sucks. That does not mean I am averse to using or liking the library as a whole.Babi
@Billy ONeal : Matias has answered your question, but why don't you ask yourself what it would cost to try and integrate Qt (with its precompilation tools) into your build system ? As suggested by others, i believe that cost would be acceptable.Enface
@Benoît: If I would have believed that was acceptable, I would not have asked this question in the first place. Perhaps for future projects; unfortunately that's not acceptable for what I'm currently working on.Babi
What kind of a build system do you use ?Enface
@Billy ONeal : can't this site help : linuxdummy.blogspot.com/2008/06/… ?Enface
@Benoit: It's not that MSBuild cannot do it. It's that it's not worth the time and effort for me to get it working, plus several hundred kb of Qt libraries, plus time spent learning the Qt library, for the current (simple) GUI I'm working on. I'd rather just build it manually.Babi
You may find this article help to explain why moc is a preprocessor instead of a template library: harmattan-dev.nokia.com/docs/library/html/qt4/templates.htmlCytolysin
This really ought to be closed as opinion-based. In fact, it should have been closed long ago. It's still attracting flies.Seraphine
R
27

Qt doesn't require the use of moc just to use it, it requires that usage if you create a subclass of QObject, and to declare signals and slots in your custom classes.

It's not unreasonable, moc provides features that C++ doesn't have, signals/slots, introspection, etc.

So, to do something minimally advanced, you WILL have to use the moc preprocessor. You either love it, or hate it.

Ration answered 27/8, 2010 at 21:19 Comment(6)
Is doing something like creating a window with a tab control, a textbox, and a few buttons "minimally advanced"?Babi
Boost.Signals2 (boost.org/doc/libs/1_40_0/doc/html/signals2.html) implements the observer pattern without having to resort to special preprocessing like signals/slots. Also, MFC provides introspection if you derive from CObject using preprocessor macros. I'm not suggesting either implementation is superior to Qt's, just that people have managed it without generating additional source files.Aver
@Billy Depends, connecting a button click to a slot in your custom class requires the use of moc.Ration
@Matias: So, I could have a button, but I'd have no way of telling when someone clicked on it?Babi
@Billy Yeah, unless you connect it to a already defined slot (not much useful).Ration
@Praetorian: qts moc compiler has a lot more to offer than just signals/slots, and it was written in a time where you could not rely on templates, since templates were not supported too well on all compilersCalysta
R
10

It's completely usable now. The maintainer of moc has made an alternative with slightly more verbose syntax than ordinary Qt, but it uses standard C++14 so there's no extra step.

It's called 'Verdigris'

(as an aside, moc isn't really a preprocessing step so much as a code generator. The code you write is valid C++, and moc doesn't change any of it. It just generates extra C++ code for you.)

Renvoi answered 31/8, 2016 at 9:7 Comment(3)
RE: Aside: "public slots" is not valid C++. Qt isn't C++ any more than yacc.Babi
it is if you have #define slot somewhere so the preprocessor turns it into just plain public, which is exactly what Qt does. moc does not edit any of your source files, it just creates extra moc_myfile.cpp ones. The compilation uses the exact headers and cpp files you wrote, plus the moc_*.cpp ones.Renvoi
@BillyONeal qt and yacc are from different stables i think. one classical the other a hack.Asexual
A
4

I don't consider it unreasonable that Qt requires a special pre-processing tool, considering how large and comprehensive of a library it is.

Other similarly comprehensive libraries such as Boost and GLib don't require special pre-processing tools but do make extensive use of the standard C preprocessor. Qt could have been implemented using only the C preprocessor, but by using its own special preprocessing tool, it can provide a cleaner syntax and avoid many of the pitfalls associated with C preprocessor macros.

As has been answered already, though, you can use Qt without moc, just not anything that requires signals and slots. Yes, this does include all of the GUI stuff, but Qt is not by any means just a GUI library.

Arboreal answered 27/8, 2010 at 21:23 Comment(6)
-1: That does not answer the question I asked. I'm not asking about the merits/pitfalls of Qt. I'm asking if it's usable without the special preprocessing tool.Babi
(sorry for double comment) I know that to do something like reflection they would need to use preprocessing as C++ does not provide that feature out of the box. That said, there was really no reason to have to implement signals and slots that way -- there are plenty of pure C++ solutions to that problem. I understand though, that to fulfill the goals Qt started out with, that preprocessing would be needed. But given that I don't plan on using any kind of reflective features, I want to know if it's possible to use the library reasonably without preprocessing.Babi
I'm not sure what else you're looking for other than what's already been posted. The answer is simply that you can "effectively use" the parts of Qt that don't rely on moc to compile or to function properly. Whether that's enough for you depends on what you're doing with Qt. It sounds like you're making a GUI, so you will probably not be able to get away with avoiding moc.Arboreal
Somehow I missed that last paragraph in your answer... was it there when I commented? Anyway... I just don't want this question to turn into a Qt Fanboys versus Qt Haters flame war. (See edit to my question explaining where I'm coming from). I thought that's where this answer was coming from; I have changed my downvote into an upvote.Babi
You don't consider it unreasonable, but what about the end users of your library which is built on top of QT? Are they going to consider it reasonable that they can't simply use your code in their favourite compiler, without downloading and installing extra build tools? IMO this is much more important than any inconvenience the developer might face.Unforgettable
I would note that even though moc might allow for a "cleaner" and "avoids the pitfalls associated with the C preprocessor", that doesn't make it more familiar. I have been using Qt for a while and I still find it weird to write signals: in a class. What is the issue with just a boost::signals2::signal<...>? Just because it is clean doesn't make it standard and "normal" for C++ developers. I would personally feel more comfortable with a signal library because I could at least understand the implementation by looking at the source without digging very deep. (not that I don't like Qt.....)Leal
W
4

Using Qt while avoiding moc will be more difficult than just using them together as intended. You will also sacrifice most of the interesting features that motivated others to recommend Qt.

Without moc you can't

  • Use signals & slots (which are all but required for UI)
  • Use the dynamic property system (needed to write plugins, among other things)
  • Use the internationalization features
  • Expect to get help from anybody when nothing works

If you want to use Qt, use moc. In fact, don't even worry about moc -- just use QMake. You can write a QMake .pro file that looks like this:

TARGET = myApp

FORMS += MainWindow.ui

HEADERS += MainWindow.h

SOURCES += MainWindow.cpp
SOURCES += main.cpp

Everything will be taken care of automatically. Or you can spend all your time trying to figure out how to avoid moc.

See https://doc.qt.io/archives/qt-4.7/metaobjects.html and https://doc.qt.io/archives/qt-4.7/moc.html#moc

Weeny answered 27/8, 2010 at 21:52 Comment(5)
I don't want to have to revamp my entire build system (which is currently MSBuild) in order to use a single library.Babi
1) You didn't state that you're converting an existing project. 2) You can probably make MSBuild work with moc more easily than you can make Qt work without moc.Weeny
I assumed that if I said "I think using a preprocessing tool is unreasonable" -- which isn't all that invasive -- that it would be sort of implicit that I didn't want to spend a week completely replacing my current build system (which is much more invasive). Given that I was not asking how to get moc working in my project, I was asking if it was possible to avoid it, I did not think that piece of information was relevant to my question. Given that you answered my question in the first part of your answer without that information, I don't think I was wrong.Babi
Your question was indeed clear. But I think my answer (all of it) was appropriate given the amount of detail you provided. Even with the added information, my advice remains "Use moc, or don't bother with Qt at all."Weeny
And actually, using any build system with moc isn't that hard.Circus
H
4

I don't have a full answer, but as I understand it, moc mainly (or perhaps only) generates additional C++ code. So potentially there's nothing it does that you couldn't also do yourself manually. However, I have no idea how tedious that might be nor how much study it might take to understand all the necessary concepts and details that go into that code.


Also, as I side note: In my opinion, the reason you're getting as much defense of Qt and moc is because you started your question with the strongly worded "I think it's unreasonable" which is easily interpreted to mean that you don't think moc should ever have existed. This distracts from your actual question. I think it would have been better just to say "moc doesn't fit into my build system" or simply "I have my own reasons for not wanting to use it".

Hogback answered 27/8, 2010 at 22:35 Comment(1)
I do think it's unreasonable. That does not mean I dislike Qt as a whole. It does mean that I do strongly dislike that I would have to use a separate preprocessor. I strongly dislike plenty of things about the C++ spec too (i.e. exception specifications) -- that does not mean that C++ is not my favorite language. Any sufficiently complex piece of technology is going to have annoying pieces. That's in no way unique to Qt. I assumed that the people reading my question would understand that. Perhaps I assumed too much.Babi
Z
4

I have a solution, that is not super-clean and not 100% satisfactory, but that allows to connect Qt signals to your own code without having to use the MOC compiler (I had exactly the same constraint as in the question, i.e. not able to run the MOC compiler in the building process of my application).

To be able to capture Qt signals without using MOC, I am using the following tricks:

(1) get the definition of QMetaCallEvent (copy it from ): In Qt 5.x, you will have something like:

class QMetaCallEvent : public QEvent {
public:
    inline int id() const {
        return method_offset_ + method_relative_;
    }

    virtual void placeMetaCall(QObject *object);

private:
    QMetaCallEvent();
    void* slotObj_;
    const QObject *sender_;
    int signalId_;
    int nargs_;
    int *types_;
    void **args_;
    void *semaphore_;
    void *callFunction_;
    ushort method_offset_;
    ushort method_relative_;
};

(2) In your widget class that needs to capture Qt signals, you will inherit from a Qt widget (say QButton), and define the following function:

// Inspired by QObject::connect() in src/corelib/kernel/qobject.cpp
bool connect_sender(
    const QObject* sender, const char* signal, int method_index
) {

        // We need to generate MetaCall events (since QObject::event()
        //   is the only virtual function we can overload)
        // (note that the other connection types do not generate events).
        Qt::ConnectionType type = Qt::QueuedConnection ;

        if(sender == 0 || signal == 0) {
            std::cerr << "null sender or signal" << std::endl ;
            return false ;
        }

        QByteArray tmp_signal_name;
        const QMetaObject *smeta = sender->metaObject();
        ++signal; //skip code
        int signal_index = smeta->indexOfSignal(signal);
        if (signal_index < 0) {
            // check for normalized signatures
            tmp_signal_name = 
                QMetaObject::normalizedSignature(signal).prepend(*(signal - 1));
            signal = tmp_signal_name.constData() + 1;
            signal_index = smeta->indexOfSignal(signal);
            if (signal_index < 0) {
                std::cerr << "Signal \'" << signal << "\' not found" 
                          << std::endl ;
                return false;
            }
        }

        int *types = 0;

        QMetaObject::connect(
            sender, signal_index, this, method_index, type, types
        ) ;

        return true ;
    }

(3) overload the event() function:

bool event(QEvent* e) {
    if(e->type() == QEvent::MetaCall) {
        QMetaCallEvent* ev = static_cast<QMetaCallEvent*>(e);
        switch(ev->id()) {
            // insert your handling code here
        }  
        return true;
    }
    return QObject::event(e) ;
}

Now, if you call connect_sender(qobject, signal_name, method_index), this will call event() each time the signal is fired, with the specified method_index retrieved in ev->id().

Important note: I have been using this trick in my application for several years, it works quite well, but it is not very clean. One of the consequences is that whenever the definition of QMetaCallEvent changes, you need to edit your declaration accordingly (unfortunately it is not exposed in the header files of Qt).

Zing answered 21/11, 2015 at 17:28 Comment(1)
I know it is an old question, but I think that this technical answer may be of interest for folks who have the same problem....Zing
P
3

I really can't think of anything so unique and useful with Qt without using QObjects. I wish they worked their way around that pre-compilation step.

Plaided answered 27/8, 2010 at 21:26 Comment(0)
N
2

Is it possible? As long as you're not doing any gui programming, probably. Personally I mostly run with PyQt these days, so it's not a big concern for me.

Why you shouldn't care: Given the nature of the "precompilation" if you're using cmake or qmake, it's not really a big deal in terms of inconvenience. If you're doing anything with a GUI these days, you should be using a graphical designer for most of the work anyway, so you're already adding some "pre-compilation" steps.

Regarding why they did it: You might be interested to read Qt's explanation: http://doc.qt.io/qt-4.8/templates.html

It boils down to:

  • The template solution lacks properties and overloading
  • The moc solution prevents signals from breaking binary compatability
  • Runtime analysis and modification are possible with the non-templated signals/slots mechanism

On a side note, multithreading signals/slots are also an advantage of their system.

Nickel answered 27/8, 2010 at 21:36 Comment(6)
It's a big deal in that I have to tear down my existing build system and replace it with Qt's. I don't fancy having to spend hours converting from MSBuild.Babi
If it's even a half-decent build system in the first place, it'll accomodate it. linuxdummy.blogspot.com/2008/06/…Nickel
Given that objection though, I'm suspicious that Qt may not be appropriate for your problem. Qt is a pretty massive library, and I'm not sure how well it would work as an "addon" to a presumably large project already.Nickel
@jkerian: It will accommodate it just fine. I'm just saying the response of "Well just throw out your current build system" isn't really realistic.Babi
Basically any build system can be taught how to deal with moc and the precompilation step, it's just easier with cmake or qmake. I've done it a few times now with custom makefiles. Not necessarily pleasant, but workable.Nickel
In case others get to this page from Google (like I did), I'll just note that I was able to add Qt to an existing MFC-based application using MSBuild with about 40 hours of effort. Our MSBuild setup handles about 1.5 million lines of C++ across ~150 VS projects, but it was still pretty easy to get Qt working with it. Qt has an add-on for Visual Studio which makes managing the moc mostly automatic.Sosa
D
2

You can use Qt without the moc, but then you lose certain functions, especially those that make Qt interesting in the first place (such as most of the GUI stuff, signals and slots, and string translation). But it's still a nice general purpose library, even without moc.

Deferent answered 8/10, 2010 at 1:59 Comment(0)
L
2

I'm currently in the position of needing to find alternatives to MOC. So far I use GLib for text translation and I'm in the middle of reengineering a signals/slots library I found on the web (sigslot) using C++ templates and C macros combined. The boring and exhausting part is redoing the GUI for my app and replacing normal Qt widgets with my own widgets (i.e. QPushButton -> MyPushButton) through widget promotion (a feature of Qt Designer). This way I can have my widgets emit templated signals instead of Qt's. There's a catch, tho. My "modified" widget classes MUST be run through the preprocessor, but that's a once-in-a-lifetime step. After that, I can move on.

I can afford to do all of this only because I have already written an Application Framework library with its own event loop (well, it's a wrapper that piggybacks on Qt's event loop code), multithreading and string classes, etc. My project will only need Qt to display the nice and nifty widgets.

But if you don't have these tools at your disposal - which I'm sure you don't - trust me, trying to get rid of Qt's preprocessor is going to be a royal pain in the arse.

Here's my message to you: If you can use QMake or moc, just use them.

Lysippus answered 29/11, 2010 at 22:29 Comment(1)
I had not written any Qt code as of yet and didn't want to depend on external tools, hence the question. (You could do signals/slots with something like boost::signals ;) )Babi
M
1

If you just need to connect to signals coming from Qt objects, a hack solution is to utilize existing QT objects that have public or protected virtual slots that match the signature of the signal you want to connect to. You can subclass the QT object and re-implement the virtual slot as a proxy to perform whatever action you need to when the QT signal is emitted. E.g.,

class SignalProxy : public QWidget
{
public:
  SignalProxy() {}

  void setVisible( bool isVisible )
  {
     // Do whatever you want to do when the signal is emitted.
  }
};


// code to connect the signal, e.g., to a QWebView object
SignalProxy proxy;
QWebView webview;
QObject::connect( &webview, SIGNAL(loadFinished(bool)),
        &proxy, SLOT(setVisible(bool)) );

It's not pretty but it gets the job done. If you were really intent on doing without the MOC you could probably locate existing Qt objects to use as proxies for just about any signal signature you need, e.g., the QAbstract... classes have lots of virtual slots, and you could hide all that nastiness in a library that provides a boost signals or tr1::function<> style API for connecting to QT signals.

Calling slots on QT objects is less of a concern than receiving signals, since you can generally invoke the slot method directly.

Manisa answered 4/9, 2013 at 22:46 Comment(0)
R
0

(sorry for reviving such an old post)

I was required to do a C/W assignment for my MSc unit in 3D Software Development.

Unfortunately a requirement was to use Qt to provide an OpenGL context rather than use Glut, native X11, Gtk etc...

I did not want to use MOC and with a lot of fiddling I was able to get just enough callbacks (such as keyboard, mouse, paint, timer etc...) to make a usable submission. So for using Qt with a primary reason for OpenGL software, it actually works fine without MOC.

However, I can't see how a full application could be developed without using MOC. Which is a shame.

This Qt MOC thing is a pain. I don't understand why so many C++ developers seem to find it acceptable frankly. It is extremely unportable and will get crusty fast! (Just try to get some Borland Kylix C++ code to compile. You will soon realize what a bad idea this is).

If I wanted to use non-standard C++, I would just use Microsoft C++/CLI.

Rectilinear answered 20/9, 2012 at 16:56 Comment(1)
I'm not going to downvote you, but the second half of your answer is incredibly subjective and unnecessarily critical. You could have left off after the "However," sentence and it would have been a good, helpful, answer.Sosa

© 2022 - 2024 — McMap. All rights reserved.