| 1 | // Copyright (C) 2016 The Qt Company Ltd. |
| 2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 |
| 3 | |
| 4 | #include "property.h" |
| 5 | |
| 6 | #include <qdir.h> |
| 7 | #include <qsettings.h> |
| 8 | #include <qtversion.h> |
| 9 | #include <qmakelibraryinfo.h> |
| 10 | #include <qstringlist.h> |
| 11 | #include <stdio.h> |
| 12 | |
| 13 | namespace { |
| 14 | constexpr int PropSuccessRetCode = 0; |
| 15 | constexpr int PropFailRetCode = 101; |
| 16 | } |
| 17 | |
| 18 | QT_BEGIN_NAMESPACE |
| 19 | |
| 20 | static const struct { |
| 21 | const char *name; |
| 22 | int loc; |
| 23 | bool raw; |
| 24 | bool singular; |
| 25 | } propList[] = { |
| 26 | { .name: "QT_SYSROOT" , .loc: QMakeLibraryInfo::SysrootPath, .raw: true, .singular: true }, |
| 27 | { .name: "QT_INSTALL_PREFIX" , .loc: QLibraryInfo::PrefixPath, .raw: false, .singular: false }, |
| 28 | { .name: "QT_INSTALL_ARCHDATA" , .loc: QLibraryInfo::ArchDataPath, .raw: false, .singular: false }, |
| 29 | { .name: "QT_INSTALL_DATA" , .loc: QLibraryInfo::DataPath, .raw: false, .singular: false }, |
| 30 | { .name: "QT_INSTALL_DOCS" , .loc: QLibraryInfo::DocumentationPath, .raw: false, .singular: false }, |
| 31 | { .name: "QT_INSTALL_HEADERS" , .loc: QLibraryInfo::HeadersPath, .raw: false, .singular: false }, |
| 32 | { .name: "QT_INSTALL_LIBS" , .loc: QLibraryInfo::LibrariesPath, .raw: false, .singular: false }, |
| 33 | { .name: "QT_INSTALL_LIBEXECS" , .loc: QLibraryInfo::LibraryExecutablesPath, .raw: false, .singular: false }, |
| 34 | { .name: "QT_INSTALL_BINS" , .loc: QLibraryInfo::BinariesPath, .raw: false, .singular: false }, |
| 35 | { .name: "QT_INSTALL_TESTS" , .loc: QLibraryInfo::TestsPath, .raw: false, .singular: false }, |
| 36 | { .name: "QT_INSTALL_PLUGINS" , .loc: QLibraryInfo::PluginsPath, .raw: false, .singular: false }, |
| 37 | { .name: "QT_INSTALL_QML" , .loc: QLibraryInfo::QmlImportsPath, .raw: false, .singular: false }, |
| 38 | { .name: "QT_INSTALL_TRANSLATIONS" , .loc: QLibraryInfo::TranslationsPath, .raw: false, .singular: false }, |
| 39 | { .name: "QT_INSTALL_CONFIGURATION" , .loc: QLibraryInfo::SettingsPath, .raw: false, .singular: false }, |
| 40 | { .name: "QT_INSTALL_EXAMPLES" , .loc: QLibraryInfo::ExamplesPath, .raw: false, .singular: false }, |
| 41 | { .name: "QT_INSTALL_DEMOS" , .loc: QLibraryInfo::ExamplesPath, .raw: false, .singular: false }, // Just backwards compat |
| 42 | { .name: "QT_HOST_PREFIX" , .loc: QMakeLibraryInfo::HostPrefixPath, .raw: true, .singular: false }, |
| 43 | { .name: "QT_HOST_DATA" , .loc: QMakeLibraryInfo::HostDataPath, .raw: true, .singular: false }, |
| 44 | { .name: "QT_HOST_BINS" , .loc: QMakeLibraryInfo::HostBinariesPath, .raw: true, .singular: false }, |
| 45 | { .name: "QT_HOST_LIBEXECS" , .loc: QMakeLibraryInfo::HostLibraryExecutablesPath, .raw: true, .singular: false }, |
| 46 | { .name: "QT_HOST_LIBS" , .loc: QMakeLibraryInfo::HostLibrariesPath, .raw: true, .singular: false }, |
| 47 | { .name: "QMAKE_SPEC" , .loc: QMakeLibraryInfo::HostSpecPath, .raw: true, .singular: true }, |
| 48 | { .name: "QMAKE_XSPEC" , .loc: QMakeLibraryInfo::TargetSpecPath, .raw: true, .singular: true }, |
| 49 | }; |
| 50 | |
| 51 | QMakeProperty::QMakeProperty() : settings(nullptr) |
| 52 | { |
| 53 | reload(); |
| 54 | } |
| 55 | |
| 56 | void QMakeProperty::reload() |
| 57 | { |
| 58 | QMakeLibraryInfo::reload(); |
| 59 | for (unsigned i = 0; i < sizeof(propList)/sizeof(propList[0]); i++) { |
| 60 | QString name = QString::fromLatin1(ba: propList[i].name); |
| 61 | if (!propList[i].singular) { |
| 62 | m_values[ProKey(name + "/src" )] = QMakeLibraryInfo::rawLocation( |
| 63 | loc: propList[i].loc, group: QMakeLibraryInfo::EffectiveSourcePaths); |
| 64 | m_values[ProKey(name + "/get" )] = QMakeLibraryInfo::rawLocation( |
| 65 | loc: propList[i].loc, group: QMakeLibraryInfo::EffectivePaths); |
| 66 | } |
| 67 | QString val = QMakeLibraryInfo::rawLocation(loc: propList[i].loc, group: QMakeLibraryInfo::FinalPaths); |
| 68 | if (!propList[i].raw) { |
| 69 | m_values[ProKey(name + "/dev" )] = |
| 70 | QMakeLibraryInfo::rawLocation(loc: propList[i].loc, group: QMakeLibraryInfo::DevicePaths); |
| 71 | m_values[ProKey(name)] = QMakeLibraryInfo::path(loc: propList[i].loc); |
| 72 | name += "/raw" ; |
| 73 | } |
| 74 | m_values[ProKey(name)] = val; |
| 75 | } |
| 76 | #ifdef QMAKE_VERSION_STR |
| 77 | m_values["QMAKE_VERSION" ] = ProString(QMAKE_VERSION_STR); |
| 78 | #endif |
| 79 | #ifdef QT_VERSION_STR |
| 80 | m_values["QT_VERSION" ] = ProString(QT_VERSION_STR); |
| 81 | #endif |
| 82 | } |
| 83 | |
| 84 | QMakeProperty::~QMakeProperty() |
| 85 | { |
| 86 | delete settings; |
| 87 | settings = nullptr; |
| 88 | } |
| 89 | |
| 90 | void QMakeProperty::initSettings() |
| 91 | { |
| 92 | if (!settings) { |
| 93 | settings = new QSettings(QSettings::UserScope, "QtProject" , "QMake" ); |
| 94 | settings->setFallbacksEnabled(false); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | ProString |
| 99 | QMakeProperty::value(const ProKey &vk) |
| 100 | { |
| 101 | ProString val = m_values.value(key: vk); |
| 102 | if (!val.isNull()) |
| 103 | return val; |
| 104 | |
| 105 | initSettings(); |
| 106 | return settings->value(key: vk.toQString()).toString(); |
| 107 | } |
| 108 | |
| 109 | bool |
| 110 | QMakeProperty::hasValue(const ProKey &v) |
| 111 | { |
| 112 | return !value(vk: v).isNull(); |
| 113 | } |
| 114 | |
| 115 | void |
| 116 | QMakeProperty::setValue(QString var, const QString &val) |
| 117 | { |
| 118 | initSettings(); |
| 119 | settings->setValue(key: var, value: val); |
| 120 | } |
| 121 | |
| 122 | void |
| 123 | QMakeProperty::remove(const QString &var) |
| 124 | { |
| 125 | initSettings(); |
| 126 | settings->remove(key: var); |
| 127 | } |
| 128 | |
| 129 | int QMakeProperty::queryProperty(const QStringList &optionProperties, |
| 130 | const PropertyPrinter &printer) |
| 131 | { |
| 132 | QList<QPair<QString, QString>> output; |
| 133 | int ret = PropSuccessRetCode; |
| 134 | if (optionProperties.isEmpty()) { |
| 135 | initSettings(); |
| 136 | const auto keys = settings->childKeys(); |
| 137 | for (const QString &key : keys) { |
| 138 | QString val = settings->value(key).toString(); |
| 139 | output.append(t: { key, val }); |
| 140 | } |
| 141 | QStringList specialProps; |
| 142 | for (unsigned i = 0; i < sizeof(propList) / sizeof(propList[0]); i++) |
| 143 | specialProps.append(t: QString::fromLatin1(ba: propList[i].name)); |
| 144 | #ifdef QMAKE_VERSION_STR |
| 145 | specialProps.append(t: "QMAKE_VERSION" ); |
| 146 | #endif |
| 147 | #ifdef QT_VERSION_STR |
| 148 | specialProps.append(t: "QT_VERSION" ); |
| 149 | #endif |
| 150 | for (const QString &prop : std::as_const(t&: specialProps)) { |
| 151 | ProString val = value(vk: ProKey(prop)); |
| 152 | ProString pval = value(vk: ProKey(prop + "/raw" )); |
| 153 | ProString gval = value(vk: ProKey(prop + "/get" )); |
| 154 | ProString sval = value(vk: ProKey(prop + "/src" )); |
| 155 | ProString dval = value(vk: ProKey(prop + "/dev" )); |
| 156 | output.append(t: { prop, val.toQString() }); |
| 157 | if (!pval.isEmpty() && pval != val) |
| 158 | output.append(t: { prop + "/raw" , pval.toQString() }); |
| 159 | if (!gval.isEmpty() && gval != (pval.isEmpty() ? val : pval)) |
| 160 | output.append(t: { prop + "/get" , gval.toQString() }); |
| 161 | if (!sval.isEmpty() && sval != gval) |
| 162 | output.append(t: { prop + "/src" , sval.toQString() }); |
| 163 | if (!dval.isEmpty() && dval != pval) |
| 164 | output.append(t: { prop + "/dev" , dval.toQString() }); |
| 165 | } |
| 166 | } else { |
| 167 | for (const auto &prop : optionProperties) { |
| 168 | const ProKey pkey(prop); |
| 169 | if (!hasValue(v: pkey)) { |
| 170 | ret = PropFailRetCode; |
| 171 | output.append(t: { prop, QString("**Unknown**" ) }); |
| 172 | } else { |
| 173 | output.append(t: { prop, value(vk: pkey).toQString() }); |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | printer(output); |
| 178 | return ret; |
| 179 | } |
| 180 | |
| 181 | int QMakeProperty::setProperty(const QStringList &optionProperties) |
| 182 | { |
| 183 | for (auto it = optionProperties.cbegin(); it != optionProperties.cend(); ++it) { |
| 184 | QString var = (*it); |
| 185 | ++it; |
| 186 | if (it == optionProperties.cend()) { |
| 187 | return PropFailRetCode; |
| 188 | } |
| 189 | if (!var.startsWith(s: "." )) |
| 190 | setValue(var, val: (*it)); |
| 191 | } |
| 192 | return PropSuccessRetCode; |
| 193 | } |
| 194 | |
| 195 | void QMakeProperty::unsetProperty(const QStringList &optionProperties) |
| 196 | { |
| 197 | for (auto it = optionProperties.cbegin(); it != optionProperties.cend(); ++it) { |
| 198 | QString var = (*it); |
| 199 | if (!var.startsWith(s: "." )) |
| 200 | remove(var); |
| 201 | } |
| 202 | } |
| 203 | |
| 204 | QT_END_NAMESPACE |
| 205 | |