QT GUI Fixed!

So, if you've seen gr-qtgui in the source code or maybe heard about it from your friends, I'm writing this to say that it's finally fixed! It was working at first, but through a Makefile hack. Then it was broken because I tried to clean it up. This "fix" went unnoticed because previously built files were preventing me from seeing the error. But now, I finally put in the real fix. It's working and the code is much cleaner than before.

This fix, actually, is stupidly simple and I'm embarrassed for not having seen it before. The problem comes from the use of QT, which in turn uses two pre-processor programs: moc and uic. The moc program build meta object information to support QT classes and uic builds a C++ class file from the QT user interface (.ui) files. From the point of view of programming up nice-looking QT GUIs, these programs are pretty nice, but when working them into an Autotool project, they're not so pleasant. QT actually comes with its own qmake compile that takes care of a lot of the preprocessing and Makefile setup through project (.pro) files. Well, in the Autotools world, we'd like to be able to handle this ourselves as usual.

So the trick is the add the moc and uic build steps to the script. So we of course need to know where to find these programs. Then we need to know how to apply the and to what files. Then, we need to use the output files from these steps as source file inputs to the library project we are actually trying to compile (let's not forget that we're trying to do something bigger than just build an interface; we're building a tool to build GNU Radio interfaces). All of this comes to a head when we realize that we don't necessarily want to build gr-qtgui due to dependency issues but the VPATH build of make distcheck should still be satisfied. When you skip the moc and uic bits, you're now missing source files, which causes make to be unhappy (yes, even if you've told it not to build gr-qtgui; its still making sure everything is available).

So then, how do we do all of this? This section is for the record and posterity. If you have no desire to learn more about the GNU Radio build system, stop reading now. Instead, I will direct you to the examples pages where I will be posting an example of how to actually use QTGUI.

Now for the inside-baseball section. First, we need to know where moc and uic are if we are going to build QTGUI. This part is done in the M4 scripts that we use to check dependencies and set variables during configure time. In the file "config/grc_gr_qtgui.m4", we make checks for all of the QT and QWT library dependencies, including the Python QT modules. That's pretty standard M4 stuff. Now, luckily, we have pkg-config on our side for the program discovery. As part of the QT library, the QtCore package config file contains a couple of important variables: "moc_location" and "uic_location." You can probably guess what they mean. So we can set some variables to keep track of this information:



    QT_MOC_EXEC=`pkg-config --variable=moc_location QtCore`

    QT_UIC_EXEC=`pkg-config --variable=uic_location QtCore`


<end file excerpt>


Those four lines will allow us to use the variables "QT_MOC_EXEC" and "QT_UIC_EXEC" as the moc and uic programs, respectively.

So now we need to have some knowledge of which files are to be built and how. We are now working in "gr-qtgui/src/lib". The how is pretty easy. Using Makefile rules, we tell make to build anything with a "" with moc and ".ui.h" with uic using these lines:




        $(QT_MOC_EXEC) $(QT_MOC_FLAGS) -p $(srcdir) $< -o $@

    %.ui.h : %.ui

        $(QT_UIC_EXEC) $< -o $@

<end file excerpt>


But this produces the "" and "ui.h" files. We get this from telling Automake that these particular sources are "to be built" by adding them to the "BUILD_SOURCES" list. I split it up a bit to keep track of what is a QT-made file and any others (there aren't right now, but I like to keep things in their proper place). So I make a "QMAKE_SOURCES" and add it to "BUILD_SOURCS" with the following few lines:










    EXTRA_DIST = spectrumdisplayform.ui


<end file excerpt>


I also snuck in the "EXTRA_DIST" call here, too. This is a special variable that tells the distribution mechanisms of make to make sure to include these files in the distribution package. It defaults to taking any file used to in the build, but it knows nothing about .ui files, even though this is part of the package. Adding "spectrumdisplayform.ui" make sure it gets included in the distribution.

So now we know that we are going to build all of these "moc" and "ui" files and how. The next part is to include these source files as part of the source file like for building the library. The Autotools rules about this follow the convention:



    lib_LTLIBRARIES = lib<your name here>.la

    lib<your name here>_la_SOURCES = <all sources required to build this library>

    lib<your name here>_la_HEADERS = <all headers required to build this library>

<end file excerpt>


In our case, we are building "", which becomes "libgnuradio_qtgui_la_SOURCES."

My mistake was to just add "QMAKE_SOURCES" to the "libgnuradio_qtgui_la_SOURCES" thinking that I needed to in order to build the library. Well, I was right that I have to tell make to includes these files in the build. What I was wrong about was to include them this way. See, when distributing the project, it now thinks that all files in this "SOURCES" variable need to be distributed, too. But if we aren't building QTGUI, which many systems won't be, these files won't exist and will crash the build. This shows up pretty quickly during make distcheck as it tries to set up the VPATH build.

So anyone who really knows Automake will probably already know the answer to this problem. At one point, I did, too, but was enamored with the rest of the QT build system that I had set up that I didn't think about it. The easy solution is the use of the "nodist_" prefix. See, we can exclude "QMAKE_SOURCES" from "libgnuradio_qtgui_la_SOURCES" and instead have the line:




<end file excerpt>


This tells the make system that we need these files to compile the library, but we don't need them distributed, so don't. Really simple.

An infuriatingly simple solution that I wanted to record here for anyone else having any issues properly building a project like this. Of course, you probably don't need it as you already knew this answer and have only read this far to continue to moc <sic> me.