fyngyrz
fyngyrz

Reputation: 2658

Retrieving OS X version using Qt, c, c++

Build Environment: QT 4.7, OS X 10.6
Run Environment: OS X 10.6 through OS X 10.13, Windows XP and later

I'm working in a very large, highly graphics-intensive QT app. I need to find out what version of OS X / MacOS I am running on - 10.6... 10.10... 10.12 etc.

I am looking for a c or c++ function in OS X I can call live; this is a runtime issue. It needs to work from 10.6 onwards. I am writing in c++ so I can use a c solution as conveniently as c++.

I have this:

#ifdef Q_OS_WIN
    QApplication::setGraphicsSystem("raster");
#else
    QApplication::setGraphicsSystem("native");
#endif

The above works to determine if it's windows or OS X I am building for. Inside the else in the above fragment I need to do some further checking; I don't need the "native" graphics system except in OS X 10.12, where the QT "raster" system has problems. I prefer the "raster" system because it is much faster, but later machines are faster too and so if I can only call for the "native" system on a modern machine running recent OS's, that should work out.

I have users - large numbers of them - running under earlier versions of OS X, consequently whatever is used here has to be general enough to work on all versions of the OS 10.6 and up. QT 4.7 itself seems to be clueless about OS versions it doesn't explicitly know about; using QSysInfo::MacVersion, it just reports "Unknown OS version."

Ideally, I imagine something of the following form:

int v = majorOSRevision();
int r = minorOSRevision();
int s = stepOSRevision();

Are there such direct, simple calls within the OS X API?

Upvotes: 1

Views: 1315

Answers (2)

TheDarkKnight
TheDarkKnight

Reputation: 27621

OS X / macOS has always stored its product info in one definitive plist file, which is located at /System/Library/CoreServices/SystemVersion.plist

If we view this file on High Sierra, we can see the following

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>ProductBuildVersion</key>
    <string>17C205</string>
    <key>ProductCopyright</key>
    <string>1983-2018 Apple Inc.</string>
    <key>ProductName</key>
    <string>Mac OS X</string>
    <key>ProductUserVisibleVersion</key>
    <string>10.13.2</string>
    <key>ProductVersion</key>
    <string>10.13.2</string>
</dict>
</plist>

As it's a plist, use Qt's QSettings to read any value, according to the given key

#include <QSettings>
QString getSysVersion()
{
    QSettings settings("/System/Library/CoreServices/SystemVersion.plist", QSettings::NativeFormat);
    return settings.value("ProductUserVisibleVersion").toString();
}

Now we have the version in a QString, we can obtain major, minor and build components

QString version = getSysVersion();
QStringList components = version.split(".");
int maj = components[0].toInt();
int min = components[1].toInt();
int build = components[2].toInt();

Upvotes: 1

p-a-o-l-o
p-a-o-l-o

Reputation: 10057

You could execute a command like sw_vers and read its output.

Example code, using QProcess:

osxversion.h

#ifndef OSXVERSION_H
#define OSXVERSION_H

#include <QProcess>

class OSXVersion : public QProcess
{
    Q_OBJECT

    int majr;
    int minr;
    int step;

    OSXVersion();

public:

    int majorOSRevision() const { return majr; }
    int minorOSRevision() const { return minr; }
    int stepOSRevision() const { return step; }

    static OSXVersion * getVersion();

private slots:
    void dataReady();
};

#endif // OSXVERSION_H

osxversion.cpp

#include "osxversion.h"

OSXVersion::OSXVersion() : QProcess(0)
{
    majr = 0;
    minr = 0;
    step = 0;
    connect(this, SIGNAL(readyRead()), this, SLOT(dataReady()));
}

OSXVersion * OSXVersion::getVersion()
{
    OSXVersion * v = new OSXVersion();
    v->start("sw_vers -productName");
    v->waitForFinished();
    return v;
}

void OSXVersion::dataReady()
{
    int * v[3] = {&majr, &minr, &step};

    QByteArray data = readAll();
    QList<QByteArray> tokens =  data.split(':');
    tokens = tokens[tokens.size() - 1].split('.');
    for(int i=0; i<tokens.size(); i++)
    {
        *(v[i]) = QString(tokens[i]).toInt();
    }
}

main.cpp

#include <QCoreApplication>
#include <QDebug>

#include "osxversion.h"

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

    OSXVersion * version = OSXVersion::getVersion();

    qDebug() << "OSX Version: "
             << version->majorOSRevision()
             << "."
             << version->minorOSRevision()
             << "."
             << version->stepOSRevision();

    delete version;

    return a.exec();
}

Upvotes: 3

Related Questions