2013-08-13 10:52:57 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2013-08-13 10:52:57 +02:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2013-08-13 10:52:57 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2013-08-13 10:52:57 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "qmakeprojectimporter.h"
|
|
|
|
|
|
|
|
|
|
#include "qmakebuildinfo.h"
|
|
|
|
|
#include "qmakekitinformation.h"
|
2013-10-16 12:10:22 +02:00
|
|
|
#include "qmakebuildconfiguration.h"
|
|
|
|
|
#include "qmakeproject.h"
|
2015-03-04 17:14:28 +01:00
|
|
|
#include "makefileparse.h"
|
|
|
|
|
#include "qmakestep.h"
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2019-01-29 16:51:17 +01:00
|
|
|
#include <projectexplorer/buildinfo.h>
|
2016-12-16 00:43:14 +01:00
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
2013-08-13 10:52:57 +02:00
|
|
|
#include <projectexplorer/kitmanager.h>
|
2014-08-04 15:17:28 +02:00
|
|
|
#include <projectexplorer/toolchain.h>
|
|
|
|
|
#include <projectexplorer/toolchainmanager.h>
|
2019-01-29 16:51:17 +01:00
|
|
|
|
2013-08-13 10:52:57 +02:00
|
|
|
#include <qtsupport/qtkitinformation.h>
|
|
|
|
|
#include <qtsupport/qtsupportconstants.h>
|
|
|
|
|
#include <qtsupport/qtversionfactory.h>
|
|
|
|
|
#include <qtsupport/qtversionmanager.h>
|
2016-08-24 15:53:50 +02:00
|
|
|
|
2014-08-04 15:17:28 +02:00
|
|
|
#include <utils/algorithm.h>
|
2016-08-24 15:53:50 +02:00
|
|
|
#include <utils/qtcassert.h>
|
|
|
|
|
#include <utils/qtcprocess.h>
|
2013-08-13 10:52:57 +02:00
|
|
|
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
2014-10-23 18:13:15 +02:00
|
|
|
#include <QStringList>
|
2015-03-04 17:14:28 +01:00
|
|
|
#include <QLoggingCategory>
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
#include <memory>
|
|
|
|
|
|
2014-10-23 18:13:15 +02:00
|
|
|
using namespace ProjectExplorer;
|
2016-08-25 14:32:48 +02:00
|
|
|
using namespace QmakeProjectManager;
|
2014-10-23 18:13:15 +02:00
|
|
|
using namespace QtSupport;
|
|
|
|
|
using namespace Utils;
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
struct DirectoryData
|
|
|
|
|
{
|
|
|
|
|
QString makefile;
|
|
|
|
|
Utils::FileName buildDirectory;
|
|
|
|
|
Utils::FileName canonicalQmakeBinary;
|
|
|
|
|
QtProjectImporter::QtVersionData qtVersionData;
|
|
|
|
|
FileName parsedSpec;
|
|
|
|
|
BaseQtVersion::QmakeBuildConfigs buildConfig;
|
|
|
|
|
QString additionalArguments;
|
|
|
|
|
QMakeStepConfig config;
|
|
|
|
|
QMakeStepConfig::TargetArchConfig archConfig;
|
|
|
|
|
QMakeStepConfig::OsType osType;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2013-10-16 11:02:37 +02:00
|
|
|
namespace QmakeProjectManager {
|
2013-08-13 10:52:57 +02:00
|
|
|
namespace Internal {
|
|
|
|
|
|
2014-10-23 18:13:15 +02:00
|
|
|
const Core::Id QT_IS_TEMPORARY("Qmake.TempQt");
|
2015-03-04 17:14:28 +01:00
|
|
|
const char IOSQT[] = "Qt4ProjectManager.QtVersion.Ios"; // ugly
|
2014-10-23 18:13:15 +02:00
|
|
|
|
2016-11-16 11:20:04 +01:00
|
|
|
QmakeProjectImporter::QmakeProjectImporter(const FileName &path) :
|
2016-08-24 15:53:50 +02:00
|
|
|
QtProjectImporter(path)
|
2013-08-13 10:52:57 +02:00
|
|
|
{ }
|
|
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
QStringList QmakeProjectImporter::importCandidates()
|
2013-08-13 10:52:57 +02:00
|
|
|
{
|
2016-08-25 14:32:48 +02:00
|
|
|
QStringList candidates;
|
2015-03-04 17:14:28 +01:00
|
|
|
|
2016-11-16 11:20:04 +01:00
|
|
|
QFileInfo pfi = projectFilePath().toFileInfo();
|
2016-08-25 14:32:48 +02:00
|
|
|
const QString prefix = pfi.baseName();
|
|
|
|
|
candidates << pfi.absolutePath();
|
|
|
|
|
|
|
|
|
|
foreach (Kit *k, KitManager::kits()) {
|
2016-11-16 11:20:04 +01:00
|
|
|
QFileInfo fi(QmakeBuildConfiguration::shadowBuildDirectory(projectFilePath().toString(), k,
|
2016-08-25 14:32:48 +02:00
|
|
|
QString(), BuildConfiguration::Unknown));
|
|
|
|
|
const QString baseDir = fi.absolutePath();
|
|
|
|
|
|
|
|
|
|
foreach (const QString &dir, QDir(baseDir).entryList()) {
|
|
|
|
|
const QString path = baseDir + QLatin1Char('/') + dir;
|
|
|
|
|
if (dir.startsWith(prefix) && !candidates.contains(path))
|
|
|
|
|
candidates << path;
|
|
|
|
|
}
|
2015-03-04 17:14:28 +01:00
|
|
|
}
|
2016-08-25 14:32:48 +02:00
|
|
|
return candidates;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<void *> QmakeProjectImporter::examineDirectory(const FileName &importPath) const
|
|
|
|
|
{
|
|
|
|
|
QList<void *> result;
|
|
|
|
|
const QLoggingCategory &logs = MakeFileParse::logging();
|
2013-08-13 10:52:57 +02:00
|
|
|
|
|
|
|
|
QStringList makefiles = QDir(importPath.toString()).entryList(QStringList(QLatin1String("Makefile*")));
|
2015-03-04 17:14:28 +01:00
|
|
|
qCDebug(logs) << " Makefiles:" << makefiles;
|
2013-08-13 10:52:57 +02:00
|
|
|
|
|
|
|
|
foreach (const QString &file, makefiles) {
|
2016-08-25 14:32:48 +02:00
|
|
|
std::unique_ptr<DirectoryData> data(new DirectoryData);
|
|
|
|
|
data->makefile = file;
|
|
|
|
|
data->buildDirectory = importPath;
|
|
|
|
|
|
2015-03-04 17:14:28 +01:00
|
|
|
qCDebug(logs) << " Parsing makefile" << file;
|
2013-08-13 10:52:57 +02:00
|
|
|
// find interesting makefiles
|
|
|
|
|
QString makefile = importPath.toString() + QLatin1Char('/') + file;
|
2015-03-04 17:14:28 +01:00
|
|
|
MakeFileParse parse(makefile);
|
2016-08-25 14:32:48 +02:00
|
|
|
if (parse.makeFileState() != MakeFileParse::Okay) {
|
|
|
|
|
qCDebug(logs) << " Parsing the makefile failed" << makefile;
|
2013-08-13 10:52:57 +02:00
|
|
|
continue;
|
2015-03-04 17:14:28 +01:00
|
|
|
}
|
2016-11-16 11:20:04 +01:00
|
|
|
if (parse.srcProFile() != projectFilePath().toString()) {
|
2015-03-04 17:14:28 +01:00
|
|
|
qCDebug(logs) << " pro files doesn't match" << parse.srcProFile() << projectFilePath();
|
2013-08-13 10:52:57 +02:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
QFileInfo qmakeFi = parse.qmakePath().toFileInfo();
|
|
|
|
|
data->canonicalQmakeBinary = FileName::fromString(qmakeFi.canonicalFilePath());
|
|
|
|
|
if (data->canonicalQmakeBinary.isEmpty()) {
|
|
|
|
|
qCDebug(logs) << " " << parse.qmakePath() << "doesn't exist anymore";
|
|
|
|
|
continue;
|
2015-03-04 17:14:28 +01:00
|
|
|
}
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
qCDebug(logs) << " QMake:" << data->canonicalQmakeBinary;
|
|
|
|
|
|
|
|
|
|
data->qtVersionData = QtProjectImporter::findOrCreateQtVersion(data->canonicalQmakeBinary);
|
|
|
|
|
BaseQtVersion *version = data->qtVersionData.qt;
|
|
|
|
|
bool isTemporaryVersion = data->qtVersionData.isTemporary;
|
|
|
|
|
|
|
|
|
|
QTC_ASSERT(version, continue);
|
|
|
|
|
|
|
|
|
|
qCDebug(logs) << " qt version:" << version->displayName() << " temporary:" << isTemporaryVersion;
|
|
|
|
|
|
|
|
|
|
data->archConfig = parse.config().archConfig;
|
|
|
|
|
data->osType = parse.config().osType;
|
|
|
|
|
|
|
|
|
|
qCDebug(logs) << " archConfig:" << data->archConfig;
|
|
|
|
|
qCDebug(logs) << " osType: " << data->osType;
|
|
|
|
|
if (version->type() == QLatin1String(IOSQT)
|
|
|
|
|
&& data->osType == QMakeStepConfig::NoOsType) {
|
|
|
|
|
data->osType = QMakeStepConfig::IphoneOS;
|
|
|
|
|
qCDebug(logs) << " IOS found without osType, adjusting osType" << data->osType;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-16 00:43:14 +01:00
|
|
|
if (version->type() == QtSupport::Constants::DESKTOPQT) {
|
2019-05-27 11:04:18 +02:00
|
|
|
const ProjectExplorer::Abis abis = version->qtAbis();
|
2015-03-04 17:14:28 +01:00
|
|
|
if (!abis.isEmpty()) {
|
|
|
|
|
ProjectExplorer::Abi abi = abis.first();
|
2016-07-25 18:39:16 -07:00
|
|
|
if (abi.os() == ProjectExplorer::Abi::DarwinOS) {
|
2015-03-04 17:14:28 +01:00
|
|
|
if (abi.wordWidth() == 64)
|
2016-08-25 14:32:48 +02:00
|
|
|
data->archConfig = QMakeStepConfig::X86_64;
|
2015-03-04 17:14:28 +01:00
|
|
|
else
|
2016-08-25 14:32:48 +02:00
|
|
|
data->archConfig = QMakeStepConfig::X86;
|
|
|
|
|
qCDebug(logs) << " OS X found without targetarch, adjusting archType" << data->archConfig;
|
2015-03-04 17:14:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// find qmake arguments and mkspec
|
2016-08-25 14:32:48 +02:00
|
|
|
data->additionalArguments = parse.unparsedArguments();
|
|
|
|
|
qCDebug(logs) << " Unparsed arguments:" << data->additionalArguments;
|
|
|
|
|
data->parsedSpec =
|
|
|
|
|
QmakeBuildConfiguration::extractSpecFromArguments(&(data->additionalArguments), importPath.toString(), version);
|
|
|
|
|
qCDebug(logs) << " Extracted spec:" << data->parsedSpec;
|
|
|
|
|
qCDebug(logs) << " Arguments now:" << data->additionalArguments;
|
|
|
|
|
|
|
|
|
|
FileName versionSpec = version->mkspec();
|
|
|
|
|
if (data->parsedSpec.isEmpty() || data->parsedSpec == FileName::fromLatin1("default")) {
|
|
|
|
|
data->parsedSpec = versionSpec;
|
|
|
|
|
qCDebug(logs) << " No parsed spec or default spec => parsed spec now:" << data->parsedSpec;
|
2015-03-04 17:14:28 +01:00
|
|
|
}
|
2016-08-25 14:32:48 +02:00
|
|
|
data->buildConfig = parse.effectiveBuildConfig(data->qtVersionData.qt->defaultBuildConfig());
|
|
|
|
|
data->config = parse.config();
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
result.append(data.release());
|
2013-08-13 10:52:57 +02:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
bool QmakeProjectImporter::matchKit(void *directoryData, const Kit *k) const
|
2013-08-13 10:52:57 +02:00
|
|
|
{
|
2018-07-12 23:59:51 +02:00
|
|
|
auto *data = static_cast<DirectoryData *>(directoryData);
|
2016-08-25 14:32:48 +02:00
|
|
|
const QLoggingCategory &logs = MakeFileParse::logging();
|
|
|
|
|
|
2019-02-06 12:50:51 +01:00
|
|
|
BaseQtVersion *kitVersion = QtKitAspect::qtVersion(k);
|
|
|
|
|
FileName kitSpec = QmakeKitAspect::mkspec(k);
|
|
|
|
|
ToolChain *tc = ToolChainKitAspect::toolChain(k, ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
2016-08-25 14:32:48 +02:00
|
|
|
if (kitSpec.isEmpty() && kitVersion)
|
|
|
|
|
kitSpec = kitVersion->mkspecFor(tc);
|
|
|
|
|
QMakeStepConfig::TargetArchConfig kitTargetArch = QMakeStepConfig::NoArch;
|
|
|
|
|
QMakeStepConfig::OsType kitOsType = QMakeStepConfig::NoOsType;
|
|
|
|
|
if (tc) {
|
|
|
|
|
kitTargetArch = QMakeStepConfig::targetArchFor(tc->targetAbi(), kitVersion);
|
|
|
|
|
kitOsType = QMakeStepConfig::osTypeFor(tc->targetAbi(), kitVersion);
|
|
|
|
|
}
|
|
|
|
|
qCDebug(logs) << k->displayName()
|
|
|
|
|
<< "version:" << (kitVersion == data->qtVersionData.qt)
|
|
|
|
|
<< "spec:" << (kitSpec == data->parsedSpec)
|
|
|
|
|
<< "targetarch:" << (kitTargetArch == data->archConfig)
|
|
|
|
|
<< "ostype:" << (kitOsType == data->osType);
|
|
|
|
|
return kitVersion == data->qtVersionData.qt
|
|
|
|
|
&& kitSpec == data->parsedSpec
|
|
|
|
|
&& kitTargetArch == data->archConfig
|
|
|
|
|
&& kitOsType == data->osType;
|
|
|
|
|
}
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
Kit *QmakeProjectImporter::createKit(void *directoryData) const
|
|
|
|
|
{
|
2018-07-12 23:59:51 +02:00
|
|
|
auto *data = static_cast<DirectoryData *>(directoryData);
|
2016-08-25 14:32:48 +02:00
|
|
|
return createTemporaryKit(data->qtVersionData, data->parsedSpec, data->archConfig, data->osType);
|
|
|
|
|
}
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2019-01-29 16:51:17 +01:00
|
|
|
const QList<BuildInfo> QmakeProjectImporter::buildInfoListForKit(const Kit *k, void *directoryData) const
|
2016-08-25 14:32:48 +02:00
|
|
|
{
|
2018-07-12 23:59:51 +02:00
|
|
|
auto *data = static_cast<DirectoryData *>(directoryData);
|
2016-08-25 14:32:48 +02:00
|
|
|
auto factory = qobject_cast<QmakeBuildConfigurationFactory *>(
|
2019-01-29 08:55:52 +01:00
|
|
|
BuildConfigurationFactory::find(k, projectFilePath().toString()));
|
2016-08-25 14:32:48 +02:00
|
|
|
if (!factory)
|
2019-01-30 12:10:24 +01:00
|
|
|
return {};
|
2013-08-13 10:52:57 +02:00
|
|
|
|
2016-08-25 14:32:48 +02:00
|
|
|
// create info:
|
2019-01-29 16:51:17 +01:00
|
|
|
BuildInfo info(factory);
|
2016-08-25 14:32:48 +02:00
|
|
|
if (data->buildConfig & BaseQtVersion::DebugBuild) {
|
2019-01-29 16:51:17 +01:00
|
|
|
info.buildType = BuildConfiguration::Debug;
|
|
|
|
|
info.displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Debug");
|
2016-08-25 14:32:48 +02:00
|
|
|
} else {
|
2019-01-29 16:51:17 +01:00
|
|
|
info.buildType = BuildConfiguration::Release;
|
|
|
|
|
info.displayName = QCoreApplication::translate("QmakeProjectManager::Internal::QmakeProjectImporter", "Release");
|
2016-08-25 14:32:48 +02:00
|
|
|
}
|
2019-01-29 16:51:17 +01:00
|
|
|
info.kitId = k->id();
|
|
|
|
|
info.buildDirectory = data->buildDirectory;
|
|
|
|
|
|
|
|
|
|
QmakeExtraBuildInfo extra;
|
|
|
|
|
extra.additionalArguments = data->additionalArguments;
|
|
|
|
|
extra.config = data->config;
|
|
|
|
|
extra.makefile = data->makefile;
|
|
|
|
|
info.extraInfo = QVariant::fromValue(extra);
|
2016-08-25 14:32:48 +02:00
|
|
|
|
2019-01-30 12:10:24 +01:00
|
|
|
return {info};
|
2013-08-13 10:52:57 +02:00
|
|
|
}
|
|
|
|
|
|
2016-09-16 14:13:02 +02:00
|
|
|
void QmakeProjectImporter::deleteDirectoryData(void *directoryData) const
|
|
|
|
|
{
|
|
|
|
|
delete static_cast<DirectoryData *>(directoryData);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-27 15:45:17 +01:00
|
|
|
static const QList<ToolChain *> preferredToolChains(BaseQtVersion *qtVersion, const FileName &ms,
|
|
|
|
|
const QMakeStepConfig::TargetArchConfig &archConfig)
|
2014-08-04 15:17:28 +02:00
|
|
|
{
|
2014-10-23 18:13:15 +02:00
|
|
|
const FileName spec = ms.isEmpty() ? qtVersion->mkspec() : ms;
|
2014-08-04 15:17:28 +02:00
|
|
|
|
2017-01-11 16:12:32 +01:00
|
|
|
const QList<ToolChain *> toolchains = ToolChainManager::toolChains();
|
2019-05-27 11:04:18 +02:00
|
|
|
const Abis qtAbis = qtVersion->qtAbis();
|
2019-02-27 15:45:17 +01:00
|
|
|
const auto matcher = [&](const ToolChain *tc) {
|
2017-01-11 16:12:32 +01:00
|
|
|
return qtAbis.contains(tc->targetAbi())
|
2019-02-27 15:45:17 +01:00
|
|
|
&& tc->suggestedMkspecList().contains(spec)
|
|
|
|
|
&& QMakeStepConfig::targetArchFor(tc->targetAbi(), qtVersion) == archConfig;
|
|
|
|
|
};
|
|
|
|
|
ToolChain * const cxxToolchain = findOrDefault(toolchains, [matcher](const ToolChain *tc) {
|
|
|
|
|
return tc->language() == ProjectExplorer::Constants::CXX_LANGUAGE_ID && matcher(tc);
|
2017-01-11 16:12:32 +01:00
|
|
|
});
|
2019-02-27 15:45:17 +01:00
|
|
|
ToolChain * const cToolchain = findOrDefault(toolchains, [matcher](const ToolChain *tc) {
|
|
|
|
|
return tc->language() == ProjectExplorer::Constants::C_LANGUAGE_ID && matcher(tc);
|
|
|
|
|
});
|
|
|
|
|
QList<ToolChain *> chosenToolchains;
|
|
|
|
|
for (ToolChain * const tc : {cxxToolchain, cToolchain}) {
|
|
|
|
|
if (tc)
|
|
|
|
|
chosenToolchains << tc;
|
|
|
|
|
};
|
|
|
|
|
return chosenToolchains;
|
2014-08-04 15:17:28 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-24 15:53:50 +02:00
|
|
|
Kit *QmakeProjectImporter::createTemporaryKit(const QtProjectImporter::QtVersionData &data,
|
2014-10-23 18:13:15 +02:00
|
|
|
const FileName &parsedSpec,
|
2015-03-04 17:14:28 +01:00
|
|
|
const QMakeStepConfig::TargetArchConfig &archConfig,
|
2016-08-25 14:32:48 +02:00
|
|
|
const QMakeStepConfig::OsType &osType) const
|
2013-08-13 10:52:57 +02:00
|
|
|
{
|
2015-03-04 17:14:28 +01:00
|
|
|
Q_UNUSED(osType); // TODO use this to select the right toolchain?
|
2016-08-24 15:53:50 +02:00
|
|
|
return QtProjectImporter::createTemporaryKit(data,
|
|
|
|
|
[&data, parsedSpec, archConfig](Kit *k) -> void {
|
2019-02-27 15:45:17 +01:00
|
|
|
for (ToolChain * const tc : preferredToolChains(data.qt, parsedSpec, archConfig))
|
2019-03-01 12:20:57 +02:00
|
|
|
ToolChainKitAspect::setToolChain(k, tc);
|
2016-08-25 14:32:48 +02:00
|
|
|
if (parsedSpec != data.qt->mkspec())
|
2019-05-02 09:58:21 +02:00
|
|
|
QmakeKitAspect::setMkspec(k, parsedSpec, QmakeKitAspect::MkspecSource::Code);
|
2016-08-24 15:20:28 +02:00
|
|
|
});
|
2013-08-13 10:52:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace Internal
|
2013-10-16 11:02:37 +02:00
|
|
|
} // namespace QmakeProjectManager
|