Use KConfigXT, but use with Care.

I stumbled a annoyance that made my hair gray today.

Imagine that you are a happy developer living a happy life sending patches for some random terminal emulator that you know and love. Imagine also that you see a strange pattern in code and you know that you can write in a better way, and you do. Code looks fine, code looks correct, code looks pretty and it also does a massive cleanup on the number of lines of code. Now also imagine that you are pretty confident that you are actually doing something good for mankind.

And nothing works.

That, my beloved friends, can destroy your afternoon. It’s just not as bad as hitting the table with your pinky or having to watch Neymar pretend to play soccer. The code in Question:

Main.cpp:
connect(KonsoleSettings::self(), &KonsoleSettings::settingsChanged, []{ qDebug() << "Sugar, oh, Honey Honey."; }

Some Other Random.cpp
connect(KonsoleSettings::self(), &KonsoleSettings::settingsChanged, []{ qDebug() << "You are my candy girl"; }

Same code, Same connect, KonsoleSettings is a singleton so I know that’s generated only once, but the problem always hit me: Only the first part of the song was appearing on the debug and for the love of bad 80’s music I could not understand what was going wrong. I mean, KconfigXT autogenerates code based on XML, so i went to take a look on how it generated.

Q_GLOBAL_STATIC(KonsoleSettingsHelper, s_globalKonsoleSettings)
KonsoleSettings *KonsoleSettings::self()
{
      if (!s_globalKonsoleSettings()->q) {
           new KonsoleSettings;
           s_globalKonsoleSettings()->q->read();
      }

      return s_globalKonsoleSettings()->q;
}

the Q_GLOBAL_STATIC gave me a hint. If it’s static it can only be in a single compilation unit and if not we have problems as the one I was having, I could not use KonsoleSettings from outside of the mainwindow.cpp as it would give me a *wrong pointer for the instance*, making the idea, well, silly.

The fix, after spending almost 4 hours trying to find the issue with the magically different pointers for the self() method was quite simple.

Add Visibility=Q_DECL_EXPORT on your kcfrc and add it in your CMakeFile onle one line containing kconfig_add_kcfg_files, with the configuration files that you need.

do not generate them on a per-target basis, use only *one* library for your KConfigXT settings.

I’v tested this in a few different KDE apps and many are using more than one instance of the KConfig singleton – that defeats the purpose and can add silent bugs, like the one I spend hours trying to fix today.

 

Leave a Reply

Your email address will not be published. Required fields are marked *