defaultpropertyprovider.cpp 10.8 KB
Newer Older
1 2
/****************************************************************************
**
3 4
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
5 6 7 8 9 10 11
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
12 13 14
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
15
**
16 17 18 19 20 21 22
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 24 25 26
**
****************************************************************************/

#include "defaultpropertyprovider.h"
27
#include "qbsconstants.h"
28

29
#include <projectexplorer/abi.h>
30
#include <projectexplorer/gcctoolchain.h>
31 32 33
#include <projectexplorer/kit.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/toolchain.h>
34
#include <projectexplorer/projectexplorerconstants.h>
35

36
#include <utils/hostosinfo.h>
37 38
#include <utils/qtcassert.h>

Christian Kandeler's avatar
Christian Kandeler committed
39
#include <qbs.h>
40

41 42 43 44
#include <ios/iosconstants.h>
#include <qnx/qnxconstants.h>
#include <winrt/winrtconstants.h>

45
#include <QDir>
46
#include <QFileInfo>
47
#include <QSettings>
48 49

namespace QbsProjectManager {
50
using namespace Constants;
51 52

namespace Internal {
53 54 55 56
using namespace ProjectExplorer::Constants;
using namespace Ios::Constants;
using namespace Qnx::Constants;
using namespace WinRt::Internal::Constants;
57

58 59 60
static QString extractToolchainPrefix(QString *compilerName)
{
    QString prefix;
61 62 63 64 65 66 67 68 69 70
    const QStringList candidates = { QLatin1String("g++"), QLatin1String("clang++"),
                                     QLatin1String("gcc"), QLatin1String("clang") };
    foreach (const QString &candidate, candidates) {
        const QString suffix = Utils::HostOsInfo::withExecutableSuffix(QLatin1Char('-')
                                                                       + candidate);
        if (compilerName->endsWith(suffix)) {
            const int idx = compilerName->lastIndexOf(QLatin1Char('-')) + 1;
            prefix = compilerName->left(idx);
            compilerName->remove(0, idx);
        }
71 72 73 74
    }
    return prefix;
}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
static QStringList targetOSList(const ProjectExplorer::Abi &abi, const ProjectExplorer::Kit *k)
{
    const Core::Id device = ProjectExplorer::DeviceTypeKitInformation::deviceTypeId(k);
    QStringList os;
    switch (abi.os()) {
    case ProjectExplorer::Abi::WindowsOS:
        if (device == WINRT_DEVICE_TYPE_LOCAL ||
                device == WINRT_DEVICE_TYPE_PHONE ||
                device == WINRT_DEVICE_TYPE_EMULATOR) {
            os << QLatin1String("winrt");
        } else if (abi.osFlavor() == ProjectExplorer::Abi::WindowsCEFlavor) {
            os << QLatin1String("windowsce");
        }
        os << QLatin1String("windows");
        break;
    case ProjectExplorer::Abi::MacOS:
        if (device == DESKTOP_DEVICE_TYPE)
            os << QLatin1String("osx");
        else if (device == IOS_DEVICE_TYPE)
            os << QLatin1String("ios");
        else if (device == IOS_SIMULATOR_TYPE)
            os << QLatin1String("ios-simulator") << QLatin1String("ios");
        os << QLatin1String("darwin") << QLatin1String("bsd") << QLatin1String("unix");
        break;
    case ProjectExplorer::Abi::LinuxOS:
        if (abi.osFlavor() == ProjectExplorer::Abi::AndroidLinuxFlavor)
            os << QLatin1String("android");
        os << QLatin1String("linux") << QLatin1String("unix");
        break;
    case ProjectExplorer::Abi::BsdOS:
        switch (abi.osFlavor()) {
        case ProjectExplorer::Abi::FreeBsdFlavor:
            os << QLatin1String("freebsd");
            break;
        case ProjectExplorer::Abi::NetBsdFlavor:
            os << QLatin1String("netbsd");
            break;
        case ProjectExplorer::Abi::OpenBsdFlavor:
            os << QLatin1String("openbsd");
            break;
        default:
            break;
        }
        os << QLatin1String("bsd") << QLatin1String("unix");
        break;
    case ProjectExplorer::Abi::UnixOS:
121
        if (device == QNX_QNX_OS_TYPE)
122 123 124 125 126 127 128 129 130 131 132 133 134 135
            os << QLatin1String("qnx");
        else if (abi.osFlavor() == ProjectExplorer::Abi::SolarisUnixFlavor)
            os << QLatin1String("solaris");
        os << QLatin1String("unix");
        break;
    default:
        break;
    }
    return os;
}

static QStringList toolchainList(const ProjectExplorer::ToolChain *tc)
{
    QStringList list;
136
    if (tc->typeId() == ProjectExplorer::Constants::CLANG_TOOLCHAIN_TYPEID)
137
        list << QLatin1String("clang") << QLatin1String("llvm") << QLatin1String("gcc");
138
    else if (tc->typeId() == ProjectExplorer::Constants::GCC_TOOLCHAIN_TYPEID)
139
        list << QLatin1String("gcc"); // TODO: Detect llvm-gcc
140
    else if (tc->typeId() == ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID)
141
        list << QLatin1String("mingw") << QLatin1String("gcc");
142
    else if (tc->typeId() == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID)
143 144 145 146
        list << QLatin1String("msvc");
    return list;
}

147 148
QVariantMap DefaultPropertyProvider::properties(const ProjectExplorer::Kit *k,
                                                const QVariantMap &defaultData) const
149 150
{
    QTC_ASSERT(k, return defaultData);
151 152 153 154 155 156 157 158 159
    QVariantMap data = autoGeneratedProperties(k, defaultData);
    const QVariantMap customProperties = k->value(Core::Id(QBS_PROPERTIES_KEY_FOR_KITS)).toMap();
    for (QVariantMap::ConstIterator it = customProperties.constBegin();
         it != customProperties.constEnd(); ++it) {
        data.insert(it.key(), it.value());
    }
    return data;
}

160 161 162 163 164 165 166 167 168 169 170 171 172
struct MSVCVersion
{
    int major = 0;
    int minor = 0;
};

static MSVCVersion msvcCompilerVersion(const ProjectExplorer::Abi &abi)
{
    MSVCVersion v;
    v.major = abi.osFlavor() - ProjectExplorer::Abi::WindowsMsvc2005Flavor + 14;
    return v;
}

173 174 175
QVariantMap DefaultPropertyProvider::autoGeneratedProperties(const ProjectExplorer::Kit *k,
                                                             const QVariantMap &defaultData) const
{
176
    QVariantMap data = defaultData;
177 178

    const QString sysroot = ProjectExplorer::SysRootKitInformation::sysRoot(k).toUserOutput();
179
    if (ProjectExplorer::SysRootKitInformation::hasSysRoot(k))
180
        data.insert(QLatin1String(QBS_SYSROOT), sysroot);
181 182

    ProjectExplorer::ToolChain *tc = ProjectExplorer::ToolChainKitInformation::toolChain(k);
183 184 185 186 187 188 189 190 191 192 193 194
    if (!tc)
        return data;

    ProjectExplorer::Abi targetAbi = tc->targetAbi();
    if (targetAbi.architecture() != ProjectExplorer::Abi::UnknownArchitecture) {
        QString architecture = ProjectExplorer::Abi::toString(targetAbi.architecture());

        // We have to be conservative tacking on suffixes to arch names because an arch that is
        // already 64-bit may get an incorrect name as a result (i.e. Itanium)
        if (targetAbi.wordWidth() == 64) {
            switch (targetAbi.architecture()) {
            case ProjectExplorer::Abi::X86Architecture:
195
                architecture.append(QLatin1Char('_'));
196 197 198 199 200 201 202 203
                // fall through
            case ProjectExplorer::Abi::ArmArchitecture:
            case ProjectExplorer::Abi::MipsArchitecture:
            case ProjectExplorer::Abi::PowerPCArchitecture:
                architecture.append(QString::number(targetAbi.wordWidth()));
                break;
            default:
                break;
204
            }
205 206 207
        } else if (targetAbi.architecture() == ProjectExplorer::Abi::ArmArchitecture &&
                   targetAbi.os() == ProjectExplorer::Abi::MacOS) {
            architecture.append(QLatin1String("v7"));
208 209
        }

210
        data.insert(QLatin1String(QBS_ARCHITECTURE), qbs::canonicalArchitecture(architecture));
211
    }
212

213 214
    QStringList targetOS = targetOSList(targetAbi, k);
    if (!targetOS.isEmpty())
215
        data.insert(QLatin1String(QBS_TARGETOS), targetOS);
216

217 218 219
    QStringList toolchain = toolchainList(tc);
    if (!toolchain.isEmpty())
        data.insert(QLatin1String(QBS_TOOLCHAIN), toolchain);
220

221
    if (targetAbi.os() == ProjectExplorer::Abi::MacOS) {
222 223
        // Set Xcode SDK name and version - required by Qbs if a sysroot is present
        // Ideally this would be done in a better way...
224 225 226 227 228 229 230 231 232 233 234 235
        const QRegExp sdkNameRe(QLatin1String("(macosx|iphoneos|iphonesimulator)([0-9]+\\.[0-9]+)"));
        const QRegExp sdkVersionRe(QLatin1String("([0-9]+\\.[0-9]+)"));
        QDir sysrootdir(sysroot);
        const QSettings sdkSettings(sysrootdir.absoluteFilePath(QLatin1String("SDKSettings.plist")), QSettings::NativeFormat);
        const QString sdkName(sdkSettings.value(QLatin1String("CanonicalName")).toString());
        const QString sdkVersion(sdkSettings.value(QLatin1String("Version")).toString());
        if (sdkNameRe.exactMatch(sdkName) && sdkVersionRe.exactMatch(sdkVersion)) {
            for (int i = 3; i > 0; --i)
                sysrootdir.cdUp();
            data.insert(QLatin1String(CPP_PLATFORMPATH), sysrootdir.absolutePath());
            data.insert(QLatin1String(CPP_XCODESDKNAME), sdkName);
            data.insert(QLatin1String(CPP_XCODESDKVERSION), sdkVersion);
236 237
        }
    }
238 239 240 241 242 243 244

    Utils::FileName cxx = tc->compilerCommand();
    const QFileInfo cxxFileInfo = cxx.toFileInfo();
    QString compilerName = cxxFileInfo.fileName();
    const QString toolchainPrefix = extractToolchainPrefix(&compilerName);
    if (!toolchainPrefix.isEmpty())
        data.insert(QLatin1String(CPP_TOOLCHAINPREFIX), toolchainPrefix);
245
    if (toolchain.contains(QLatin1String("msvc"))) {
246
        data.insert(QLatin1String(CPP_COMPILERNAME), compilerName);
247 248 249 250
        const MSVCVersion v = msvcCompilerVersion(targetAbi);
        data.insert(QLatin1String(CPP_COMPILERVERSIONMAJOR), v.major);
        data.insert(QLatin1String(CPP_COMPILERVERSIONMINOR), v.minor);
    } else {
251
        data.insert(QLatin1String(CPP_CXXCOMPILERNAME), compilerName);
252
    }
253 254 255 256 257
    if (targetAbi.os() != ProjectExplorer::Abi::WindowsOS
            || targetAbi.osFlavor() == ProjectExplorer::Abi::WindowsMSysFlavor) {
        data.insert(QLatin1String(CPP_LINKERNAME), compilerName);
    }
    data.insert(QLatin1String(CPP_TOOLCHAINPATH), cxxFileInfo.absolutePath());
258

259 260 261 262 263
    if (ProjectExplorer::GccToolChain *gcc = dynamic_cast<ProjectExplorer::GccToolChain *>(tc)) {
        data.insert(QLatin1String(CPP_PLATFORMCOMMONCOMPILERFLAGS), gcc->platformCodeGenFlags());
        data.insert(QLatin1String(CPP_PLATFORMLINKERFLAGS), gcc->platformLinkerFlags());
    }

264 265 266
    return data;
}

267
} // namespace Internal
268
} // namespace QbsProjectManager