2017-02-09 11:40:25 +01:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
|
**
|
|
|
|
|
** 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
|
|
|
|
|
** 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.
|
|
|
|
|
**
|
|
|
|
|
** 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.
|
|
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "qmakeparsernodes.h"
|
2017-02-09 23:28:02 +01:00
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
#include "qmakeproject.h"
|
|
|
|
|
#include "qmakeprojectmanagerconstants.h"
|
|
|
|
|
#include "qmakebuildconfiguration.h"
|
|
|
|
|
|
2017-02-09 23:28:02 +01:00
|
|
|
#include <coreplugin/documentmanager.h>
|
2017-02-09 11:40:25 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <coreplugin/iversioncontrol.h>
|
|
|
|
|
#include <coreplugin/vcsmanager.h>
|
2017-02-09 23:28:02 +01:00
|
|
|
#include <cpptools/cpptoolsconstants.h>
|
2019-02-01 16:50:29 +01:00
|
|
|
#include <projectexplorer/editorconfiguration.h>
|
2017-02-09 11:40:25 +01:00
|
|
|
#include <projectexplorer/projectexplorer.h>
|
2017-02-15 12:53:30 +01:00
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
2017-02-09 11:40:25 +01:00
|
|
|
#include <projectexplorer/target.h>
|
|
|
|
|
#include <qtsupport/profilereader.h>
|
2019-02-01 16:50:29 +01:00
|
|
|
#include <texteditor/icodestylepreferences.h>
|
|
|
|
|
#include <texteditor/tabsettings.h>
|
|
|
|
|
#include <texteditor/texteditorsettings.h>
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
#include <utils/algorithm.h>
|
2018-11-30 10:31:56 +02:00
|
|
|
#include <utils/filesystemwatcher.h>
|
2017-02-09 11:40:25 +01:00
|
|
|
#include <utils/qtcprocess.h>
|
|
|
|
|
#include <utils/mimetypes/mimedatabase.h>
|
|
|
|
|
#include <utils/stringutils.h>
|
2018-07-04 12:47:21 +02:00
|
|
|
#include <utils/temporarydirectory.h>
|
2017-02-09 23:28:02 +01:00
|
|
|
#include <utils/QtConcurrentTools>
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-09 15:41:05 +01:00
|
|
|
#include <QLoggingCategory>
|
|
|
|
|
#include <QMessageBox>
|
2017-02-09 11:40:25 +01:00
|
|
|
#include <QTextCodec>
|
|
|
|
|
|
|
|
|
|
using namespace Core;
|
|
|
|
|
using namespace ProjectExplorer;
|
2017-02-09 16:07:21 +01:00
|
|
|
using namespace QmakeProjectManager;
|
|
|
|
|
using namespace QmakeProjectManager::Internal;
|
2017-02-09 11:40:25 +01:00
|
|
|
using namespace QMakeInternal;
|
2017-02-09 16:07:21 +01:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
|
|
|
|
namespace {
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-09 16:07:21 +01:00
|
|
|
class QmakePriFileDocument : public Core::IDocument
|
|
|
|
|
{
|
|
|
|
|
public:
|
2019-05-28 13:49:26 +02:00
|
|
|
QmakePriFileDocument(QmakePriFile *qmakePriFile, const Utils::FilePath &filePath) :
|
2017-02-09 16:07:21 +01:00
|
|
|
IDocument(nullptr), m_priFile(qmakePriFile)
|
|
|
|
|
{
|
|
|
|
|
setId("Qmake.PriFile");
|
|
|
|
|
setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
|
|
|
|
|
setFilePath(filePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(state)
|
|
|
|
|
Q_UNUSED(type)
|
|
|
|
|
return BehaviorSilent;
|
|
|
|
|
}
|
|
|
|
|
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override
|
|
|
|
|
{
|
|
|
|
|
Q_UNUSED(errorString)
|
|
|
|
|
Q_UNUSED(flag)
|
|
|
|
|
if (type == TypePermissions)
|
|
|
|
|
return true;
|
|
|
|
|
m_priFile->scheduleUpdate();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
2017-02-09 16:45:36 +01:00
|
|
|
QmakePriFile *m_priFile;
|
2017-02-09 16:07:21 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
namespace QmakeProjectManager {
|
|
|
|
|
|
2020-01-15 14:39:23 +01:00
|
|
|
static Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg);
|
2017-02-09 15:41:05 +01:00
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
uint qHash(Variable key, uint seed) { return ::qHash(static_cast<int>(key), seed); }
|
2019-08-20 14:48:48 +02:00
|
|
|
uint qHash(FileOrigin fo) { return ::qHash(int(fo)); }
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
namespace Internal {
|
2017-02-09 17:02:47 +01:00
|
|
|
|
2020-03-11 14:01:35 +01:00
|
|
|
Q_LOGGING_CATEGORY(qmakeNodesLog, "qtc.qmake.nodes", QtWarningMsg)
|
|
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
class QmakeEvalInput
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
QString projectDir;
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath projectFilePath;
|
|
|
|
|
FilePath buildDirectory;
|
|
|
|
|
FilePath sysroot;
|
2017-02-09 11:40:25 +01:00
|
|
|
QtSupport::ProFileReader *readerExact;
|
|
|
|
|
QtSupport::ProFileReader *readerCumulative;
|
|
|
|
|
QMakeGlobals *qmakeGlobals;
|
|
|
|
|
QMakeVfs *qmakeVfs;
|
2020-01-31 15:52:20 +01:00
|
|
|
QSet<FilePath> parentFilePaths;
|
|
|
|
|
bool includedInExcactParse;
|
2017-02-09 11:40:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class QmakePriFileEvalResult
|
|
|
|
|
{
|
|
|
|
|
public:
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> folders;
|
|
|
|
|
QSet<FilePath> recursiveEnumerateFiles;
|
2019-08-20 14:48:48 +02:00
|
|
|
QMap<FileType, QSet<FilePath>> foundFilesExact;
|
|
|
|
|
QMap<FileType, QSet<FilePath>> foundFilesCumulative;
|
2017-02-09 11:40:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class QmakeIncludedPriFile
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
ProFile *proFile;
|
2019-05-28 13:49:26 +02:00
|
|
|
Utils::FilePath name;
|
2017-02-09 11:40:25 +01:00
|
|
|
QmakePriFileEvalResult result;
|
2019-05-28 13:49:26 +02:00
|
|
|
QMap<Utils::FilePath, QmakeIncludedPriFile *> children;
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
~QmakeIncludedPriFile()
|
|
|
|
|
{
|
|
|
|
|
qDeleteAll(children);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class QmakeEvalResult
|
|
|
|
|
{
|
|
|
|
|
public:
|
2020-01-31 15:52:20 +01:00
|
|
|
~QmakeEvalResult() { qDeleteAll(directChildren); }
|
|
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
enum EvalResultState { EvalAbort, EvalFail, EvalPartial, EvalOk };
|
|
|
|
|
EvalResultState state;
|
|
|
|
|
ProjectType projectType;
|
|
|
|
|
|
|
|
|
|
QStringList subProjectsNotToDeploy;
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> exactSubdirs;
|
2017-02-09 11:40:25 +01:00
|
|
|
QmakeIncludedPriFile includedFiles;
|
2017-02-15 13:44:13 +01:00
|
|
|
TargetInformation targetInformation;
|
|
|
|
|
InstallsList installsList;
|
2017-02-09 11:40:25 +01:00
|
|
|
QHash<Variable, QStringList> newVarValues;
|
|
|
|
|
QStringList errors;
|
2018-11-30 10:31:56 +02:00
|
|
|
QSet<QString> directoriesWithWildcards;
|
2020-01-31 15:52:20 +01:00
|
|
|
QList<QmakePriFile *> directChildren;
|
|
|
|
|
QList<QPair<QmakePriFile *, QmakePriFileEvalResult>> priFiles;
|
|
|
|
|
QList<QmakeProFile *> proFiles;
|
2017-02-09 11:40:25 +01:00
|
|
|
};
|
|
|
|
|
|
2017-02-09 16:07:21 +01:00
|
|
|
} // namespace Internal
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
QmakePriFile::QmakePriFile(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile,
|
2020-01-31 15:52:20 +01:00
|
|
|
const FilePath &filePath) : m_filePath(filePath)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2020-01-31 15:52:20 +01:00
|
|
|
finishInitialization(buildSystem, qmakeProFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QmakePriFile::QmakePriFile(const FilePath &filePath) : m_filePath(filePath) { }
|
|
|
|
|
|
|
|
|
|
void QmakePriFile::finishInitialization(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(buildSystem, return);
|
|
|
|
|
m_buildSystem = buildSystem;
|
|
|
|
|
m_qmakeProFile = qmakeProFile;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath QmakePriFile::filePath() const
|
2017-02-09 15:35:19 +01:00
|
|
|
{
|
2020-01-31 15:52:20 +01:00
|
|
|
return m_filePath;
|
2017-02-09 15:35:19 +01:00
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath QmakePriFile::directoryPath() const
|
2017-02-09 15:35:19 +01:00
|
|
|
{
|
|
|
|
|
return filePath().parentDir();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 10:24:32 +01:00
|
|
|
QString QmakePriFile::displayName() const
|
|
|
|
|
{
|
|
|
|
|
return filePath().toFileInfo().completeBaseName();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 17:02:47 +01:00
|
|
|
QmakePriFile *QmakePriFile::parent() const
|
|
|
|
|
{
|
|
|
|
|
return m_parent;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 10:24:32 +01:00
|
|
|
QmakeProject *QmakePriFile::project() const
|
|
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
return static_cast<QmakeProject *>(m_buildSystem->project());
|
2017-02-15 10:24:32 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 17:02:47 +01:00
|
|
|
QVector<QmakePriFile *> QmakePriFile::children() const
|
|
|
|
|
{
|
|
|
|
|
return m_children;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QmakePriFile *QmakePriFile::findPriFile(const FilePath &fileName)
|
2017-02-15 12:24:57 +01:00
|
|
|
{
|
|
|
|
|
if (fileName == filePath())
|
|
|
|
|
return this;
|
2018-04-08 23:40:00 +03:00
|
|
|
for (QmakePriFile *n : qAsConst(m_children)) {
|
2017-02-15 12:24:57 +01:00
|
|
|
if (QmakePriFile *result = n->findPriFile(fileName))
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
2017-11-02 15:23:37 +01:00
|
|
|
}
|
2017-02-15 12:24:57 +01:00
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
const QmakePriFile *QmakePriFile::findPriFile(const FilePath &fileName) const
|
2017-11-02 15:23:37 +01:00
|
|
|
{
|
|
|
|
|
if (fileName == filePath())
|
|
|
|
|
return this;
|
2018-04-08 23:40:00 +03:00
|
|
|
for (const QmakePriFile *n : qAsConst(m_children)) {
|
2017-11-02 15:23:37 +01:00
|
|
|
if (const QmakePriFile *result = n->findPriFile(fileName))
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
2017-02-15 12:24:57 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-10 09:56:33 +01:00
|
|
|
void QmakePriFile::makeEmpty()
|
|
|
|
|
{
|
|
|
|
|
qDeleteAll(m_children);
|
|
|
|
|
m_children.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-20 14:48:48 +02:00
|
|
|
SourceFiles QmakePriFile::files(const FileType &type) const
|
2017-02-15 12:52:36 +01:00
|
|
|
{
|
|
|
|
|
return m_files.value(type);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
const QSet<FilePath> QmakePriFile::collectFiles(const FileType &type) const
|
2019-05-06 16:46:03 +02:00
|
|
|
{
|
2019-08-20 14:48:48 +02:00
|
|
|
QSet<FilePath> allFiles = transform(files(type),
|
|
|
|
|
[](const SourceFile &sf) { return sf.first; });
|
2019-05-06 16:46:03 +02:00
|
|
|
for (const QmakePriFile * const priFile : qAsConst(m_children)) {
|
|
|
|
|
if (!dynamic_cast<const QmakeProFile *>(priFile))
|
|
|
|
|
allFiles.unite(priFile->collectFiles(type));
|
|
|
|
|
}
|
|
|
|
|
return allFiles;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QmakePriFile::~QmakePriFile()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-17 16:04:02 +01:00
|
|
|
watchFolders( {} );
|
2017-02-09 17:02:47 +01:00
|
|
|
qDeleteAll(m_children);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::scheduleUpdate()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-08-14 18:30:29 +02:00
|
|
|
QtSupport::ProFileCacheManager::instance()->discardFile(
|
2019-10-25 09:55:32 +02:00
|
|
|
filePath().toString(), m_buildSystem->qmakeVfs());
|
2017-02-09 16:45:36 +01:00
|
|
|
m_qmakeProFile->scheduleUpdate(QmakeProFile::ParseLater);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QStringList QmakePriFile::baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
if (!reader)
|
|
|
|
|
return result;
|
|
|
|
|
result += reader->absolutePathValues(QLatin1String("VPATH"), projectDir);
|
|
|
|
|
result << projectDir; // QMAKE_ABSOLUTE_SOURCE_PATH
|
|
|
|
|
result << buildDir;
|
|
|
|
|
result.removeDuplicates();
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QStringList QmakePriFile::fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader,
|
2017-02-09 11:40:25 +01:00
|
|
|
const QString &qmakeVariable, const QString &projectDir)
|
|
|
|
|
{
|
|
|
|
|
QStringList vPaths;
|
|
|
|
|
if (!reader)
|
|
|
|
|
return vPaths;
|
|
|
|
|
vPaths = reader->absolutePathValues(QLatin1String("VPATH_") + qmakeVariable, projectDir);
|
|
|
|
|
vPaths += baseVPaths;
|
|
|
|
|
vPaths.removeDuplicates();
|
|
|
|
|
return vPaths;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> QmakePriFile::recursiveEnumerate(const QString &folder)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> result;
|
2017-02-09 11:40:25 +01:00
|
|
|
QDir dir(folder);
|
|
|
|
|
dir.setFilter(dir.filter() | QDir::NoDotAndDotDot);
|
|
|
|
|
foreach (const QFileInfo &file, dir.entryInfoList()) {
|
|
|
|
|
if (file.isDir() && !file.isSymLink())
|
|
|
|
|
result += recursiveEnumerate(file.absoluteFilePath());
|
|
|
|
|
else if (!Core::EditorManager::isAutoSaveFile(file.fileName()))
|
2019-05-28 13:49:26 +02:00
|
|
|
result += FilePath::fromFileInfo(file);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QStringList fileListForVar(
|
2017-02-09 16:25:23 +01:00
|
|
|
const QHash<QString, QVector<ProFileEvaluator::SourceFile>> &sourceFiles,
|
2017-02-09 11:40:25 +01:00
|
|
|
const QString &varName)
|
|
|
|
|
{
|
|
|
|
|
const QVector<ProFileEvaluator::SourceFile> &sources = sourceFiles[varName];
|
|
|
|
|
QStringList result;
|
|
|
|
|
result.reserve(sources.size());
|
|
|
|
|
foreach (const ProFileEvaluator::SourceFile &sf, sources)
|
|
|
|
|
result << sf.fileName;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::extractSources(
|
2017-08-14 18:30:29 +02:00
|
|
|
QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback,
|
2019-08-20 14:48:48 +02:00
|
|
|
QVector<ProFileEvaluator::SourceFile> sourceFiles, FileType type, bool cumulative)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
foreach (const ProFileEvaluator::SourceFile &source, sourceFiles) {
|
2017-08-14 18:30:29 +02:00
|
|
|
auto *result = proToResult.value(source.proFileId);
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!result)
|
|
|
|
|
result = fallback;
|
2019-08-20 14:48:48 +02:00
|
|
|
auto &foundFiles = cumulative ? result->foundFilesCumulative : result->foundFilesExact;
|
|
|
|
|
foundFiles[type].insert(FilePath::fromString(source.fileName));
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::extractInstalls(
|
2017-08-14 18:30:29 +02:00
|
|
|
QHash<int, QmakePriFileEvalResult *> proToResult, QmakePriFileEvalResult *fallback,
|
2017-02-15 13:44:13 +01:00
|
|
|
const InstallsList &installList)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-15 13:44:13 +01:00
|
|
|
for (const InstallsItem &item : installList.items) {
|
2017-02-09 11:40:25 +01:00
|
|
|
for (const ProFileEvaluator::SourceFile &source : item.files) {
|
2017-08-14 18:30:29 +02:00
|
|
|
auto *result = proToResult.value(source.proFileId);
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!result)
|
|
|
|
|
result = fallback;
|
2019-05-28 13:49:26 +02:00
|
|
|
result->folders.insert(FilePath::fromString(source.fileName));
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::processValues(QmakePriFileEvalResult &result)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
// Remove non existing items and non folders
|
2017-02-17 16:04:02 +01:00
|
|
|
auto it = result.folders.begin();
|
2017-02-09 11:40:25 +01:00
|
|
|
while (it != result.folders.end()) {
|
2017-02-17 16:04:02 +01:00
|
|
|
QFileInfo fi((*it).toFileInfo());
|
2017-02-09 11:40:25 +01:00
|
|
|
if (fi.exists()) {
|
|
|
|
|
if (fi.isDir()) {
|
2017-02-17 16:04:02 +01:00
|
|
|
result.recursiveEnumerateFiles += recursiveEnumerate((*it).toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
// keep directories
|
|
|
|
|
++it;
|
|
|
|
|
} else {
|
|
|
|
|
// move files directly to recursiveEnumerateFiles
|
2017-02-17 16:04:02 +01:00
|
|
|
result.recursiveEnumerateFiles += (*it);
|
2017-02-09 11:40:25 +01:00
|
|
|
it = result.folders.erase(it);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// do remove non exsting stuff
|
|
|
|
|
it = result.folders.erase(it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 10:15:34 +01:00
|
|
|
for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
|
2018-07-12 23:59:51 +02:00
|
|
|
auto type = static_cast<FileType>(i);
|
2019-08-20 14:48:48 +02:00
|
|
|
for (QSet<FilePath> * const foundFiles
|
|
|
|
|
: {&result.foundFilesExact[type], &result.foundFilesCumulative[type]}) {
|
|
|
|
|
result.recursiveEnumerateFiles.subtract(*foundFiles);
|
|
|
|
|
QSet<FilePath> newFilePaths = filterFilesProVariables(type, *foundFiles);
|
|
|
|
|
newFilePaths += filterFilesRecursiveEnumerata(type, result.recursiveEnumerateFiles);
|
|
|
|
|
*foundFiles = newFilePaths;
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::update(const Internal::QmakePriFileEvalResult &result)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
m_recursiveEnumerateFiles = result.recursiveEnumerateFiles;
|
2017-02-17 16:04:02 +01:00
|
|
|
watchFolders(result.folders);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-15 10:15:34 +01:00
|
|
|
for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
|
2018-07-12 23:59:51 +02:00
|
|
|
const auto type = static_cast<FileType>(i);
|
2019-08-20 14:48:48 +02:00
|
|
|
SourceFiles &files = m_files[type];
|
|
|
|
|
files.clear();
|
|
|
|
|
const QSet<FilePath> exactFps = result.foundFilesExact.value(type);
|
|
|
|
|
for (const FilePath &exactFp : exactFps)
|
|
|
|
|
files << qMakePair(exactFp, FileOrigin::ExactParse);
|
|
|
|
|
for (const FilePath &cumulativeFp : result.foundFilesCumulative.value(type)) {
|
|
|
|
|
if (!exactFps.contains(cumulativeFp))
|
|
|
|
|
files << qMakePair(cumulativeFp, FileOrigin::CumulativeParse);
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
void QmakePriFile::watchFolders(const QSet<FilePath> &folders)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-17 16:04:02 +01:00
|
|
|
const QSet<QString> folderStrings =
|
2019-05-28 13:49:26 +02:00
|
|
|
Utils::transform(folders, &FilePath::toString);
|
2017-02-09 11:40:25 +01:00
|
|
|
QSet<QString> toUnwatch = m_watchedFolders;
|
2017-02-17 16:04:02 +01:00
|
|
|
toUnwatch.subtract(folderStrings);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-17 16:04:02 +01:00
|
|
|
QSet<QString> toWatch = folderStrings;
|
2017-02-09 11:40:25 +01:00
|
|
|
toWatch.subtract(m_watchedFolders);
|
|
|
|
|
|
2020-02-04 11:58:23 +01:00
|
|
|
if (m_buildSystem) {
|
|
|
|
|
// Check needed on early exit of QmakeProFile::applyEvaluate?
|
|
|
|
|
m_buildSystem->unwatchFolders(Utils::toList(toUnwatch), this);
|
|
|
|
|
m_buildSystem->watchFolders(Utils::toList(toWatch), this);
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-17 16:04:02 +01:00
|
|
|
m_watchedFolders = folderStrings;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-02-01 16:50:29 +01:00
|
|
|
QString QmakePriFile::continuationIndent() const
|
|
|
|
|
{
|
|
|
|
|
const EditorConfiguration *editorConf = project()->editorConfiguration();
|
|
|
|
|
const TextEditor::TabSettings &tabSettings = editorConf->useGlobalSettings()
|
|
|
|
|
? TextEditor::TextEditorSettings::codeStyle()->tabSettings()
|
|
|
|
|
: editorConf->codeStyle()->tabSettings();
|
|
|
|
|
if (tabSettings.m_continuationAlignBehavior == TextEditor::TabSettings::ContinuationAlignWithIndent
|
|
|
|
|
&& tabSettings.m_tabPolicy == TextEditor::TabSettings::TabsOnlyTabPolicy) {
|
|
|
|
|
return QString("\t");
|
|
|
|
|
}
|
|
|
|
|
return QString(tabSettings.m_indentSize, ' ');
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
QmakeBuildSystem *QmakePriFile::buildSystem() const
|
|
|
|
|
{
|
|
|
|
|
return m_buildSystem;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
bool QmakePriFile::knowsFile(const FilePath &filePath) const
|
2017-02-15 14:47:30 +01:00
|
|
|
{
|
|
|
|
|
return m_recursiveEnumerateFiles.contains(filePath);
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
bool QmakePriFile::folderChanged(const QString &changedFolder, const QSet<FilePath> &newFiles)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-09 16:45:36 +01:00
|
|
|
qCDebug(qmakeParse()) << "QmakePriFile::folderChanged";
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> addedFiles = newFiles;
|
2017-02-09 11:40:25 +01:00
|
|
|
addedFiles.subtract(m_recursiveEnumerateFiles);
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> removedFiles = m_recursiveEnumerateFiles;
|
2017-02-09 11:40:25 +01:00
|
|
|
removedFiles.subtract(newFiles);
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
foreach (const FilePath &file, removedFiles) {
|
|
|
|
|
if (!file.isChildOf(FilePath::fromString(changedFolder)))
|
2017-02-09 11:40:25 +01:00
|
|
|
removedFiles.remove(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (addedFiles.isEmpty() && removedFiles.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
m_recursiveEnumerateFiles = newFiles;
|
|
|
|
|
|
2017-02-09 15:41:05 +01:00
|
|
|
// Apply the differences per file type
|
2017-02-15 10:15:34 +01:00
|
|
|
for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
|
2018-07-12 23:59:51 +02:00
|
|
|
auto type = static_cast<FileType>(i);
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> add = filterFilesRecursiveEnumerata(type, addedFiles);
|
|
|
|
|
QSet<FilePath> remove = filterFilesRecursiveEnumerata(type, removedFiles);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
if (!add.isEmpty() || !remove.isEmpty()) {
|
2017-02-15 10:15:34 +01:00
|
|
|
qCDebug(qmakeParse()) << "For type" << static_cast<int>(type) <<"\n"
|
2017-02-09 15:41:05 +01:00
|
|
|
<< "added files" << add << "\n"
|
|
|
|
|
<< "removed files" << remove;
|
2019-08-20 14:48:48 +02:00
|
|
|
SourceFiles ¤tFiles = m_files[type];
|
|
|
|
|
for (const FilePath &fp : add) {
|
|
|
|
|
if (!contains(currentFiles, [&fp](const SourceFile &sf) { return sf.first == fp; }))
|
|
|
|
|
currentFiles.insert(qMakePair(fp, FileOrigin::ExactParse));
|
|
|
|
|
}
|
|
|
|
|
for (const FilePath &fp : remove) {
|
|
|
|
|
const auto it = std::find_if(currentFiles.begin(), currentFiles.end(),
|
|
|
|
|
[&fp](const SourceFile &sf) {
|
|
|
|
|
return sf.first == fp; });
|
|
|
|
|
if (it != currentFiles.end())
|
|
|
|
|
currentFiles.erase(it);
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::deploysFolder(const QString &folder) const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QString f = folder;
|
|
|
|
|
const QChar slash = QLatin1Char('/');
|
|
|
|
|
if (!f.endsWith(slash))
|
|
|
|
|
f.append(slash);
|
|
|
|
|
|
|
|
|
|
foreach (const QString &wf, m_watchedFolders) {
|
|
|
|
|
if (f.startsWith(wf)
|
|
|
|
|
&& (wf.endsWith(slash)
|
|
|
|
|
|| (wf.length() < f.length() && f.at(wf.length()) == slash)))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-10 11:21:58 +01:00
|
|
|
QVector<QmakePriFile *> QmakePriFile::subPriFilesExact() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-10 11:21:58 +01:00
|
|
|
return Utils::filtered(m_children, &QmakePriFile::includedInExactParse);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QmakeProFile *QmakePriFile::proFile() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-09 16:45:36 +01:00
|
|
|
return m_qmakeProFile;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::includedInExactParse() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_includedInExactParse;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::setIncludedInExactParse(bool b)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
m_includedInExactParse = b;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::canAddSubProject(const QString &proFilePath) const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QFileInfo fi(proFilePath);
|
|
|
|
|
if (fi.suffix() == QLatin1String("pro")
|
|
|
|
|
|| fi.suffix() == QLatin1String("pri"))
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static QString simplifyProFilePath(const QString &proFilePath)
|
|
|
|
|
{
|
|
|
|
|
// if proFilePath is like: _path_/projectName/projectName.pro
|
|
|
|
|
// we simplify it to: _path_/projectName
|
|
|
|
|
QFileInfo fi(proFilePath);
|
|
|
|
|
const QString parentPath = fi.absolutePath();
|
|
|
|
|
QFileInfo parentFi(parentPath);
|
|
|
|
|
if (parentFi.fileName() == fi.completeBaseName())
|
|
|
|
|
return parentPath;
|
|
|
|
|
return proFilePath;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-15 14:45:54 +01:00
|
|
|
bool QmakePriFile::addSubProject(const QString &proFile)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList uniqueProFilePaths;
|
2019-05-28 13:49:26 +02:00
|
|
|
if (!m_recursiveEnumerateFiles.contains(FilePath::fromString(proFile)))
|
2017-03-15 14:45:54 +01:00
|
|
|
uniqueProFilePaths.append(simplifyProFilePath(proFile));
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
QStringList failedFiles;
|
|
|
|
|
changeFiles(QLatin1String(Constants::PROFILE_MIMETYPE), uniqueProFilePaths, &failedFiles, AddToProFile);
|
|
|
|
|
|
|
|
|
|
return failedFiles.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-15 14:45:54 +01:00
|
|
|
bool QmakePriFile::removeSubProjects(const QString &proFilePath)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList failedOriginalFiles;
|
2017-03-15 14:45:54 +01:00
|
|
|
changeFiles(QLatin1String(Constants::PROFILE_MIMETYPE), QStringList(proFilePath), &failedOriginalFiles, RemoveFromProFile);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
QStringList simplifiedProFiles = Utils::transform(failedOriginalFiles, &simplifyProFilePath);
|
|
|
|
|
|
|
|
|
|
QStringList failedSimplifiedFiles;
|
|
|
|
|
changeFiles(QLatin1String(Constants::PROFILE_MIMETYPE), simplifiedProFiles, &failedSimplifiedFiles, RemoveFromProFile);
|
|
|
|
|
|
|
|
|
|
return failedSimplifiedFiles.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::addFiles(const QStringList &filePaths, QStringList *notAdded)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
// If a file is already referenced in the .pro file then we don't add them.
|
|
|
|
|
// That ignores scopes and which variable was used to reference the file
|
|
|
|
|
// So it's obviously a bit limited, but in those cases you need to edit the
|
|
|
|
|
// project files manually anyway.
|
|
|
|
|
|
2018-07-12 23:59:51 +02:00
|
|
|
using TypeFileMap = QMap<QString, QStringList>;
|
2017-02-09 11:40:25 +01:00
|
|
|
// Split into lists by file type and bulk-add them.
|
|
|
|
|
TypeFileMap typeFileMap;
|
|
|
|
|
foreach (const QString &file, filePaths) {
|
2017-03-02 12:07:11 +01:00
|
|
|
const Utils::MimeType mt = Utils::mimeTypeForFile(file);
|
2017-02-09 11:40:25 +01:00
|
|
|
typeFileMap[mt.name()] << file;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList failedFiles;
|
|
|
|
|
foreach (const QString &type, typeFileMap.keys()) {
|
|
|
|
|
const QStringList typeFiles = typeFileMap.value(type);
|
|
|
|
|
QStringList qrcFiles; // the list of qrc files referenced from ui files
|
|
|
|
|
if (type == QLatin1String(ProjectExplorer::Constants::RESOURCE_MIMETYPE)) {
|
|
|
|
|
foreach (const QString &formFile, typeFiles) {
|
|
|
|
|
QStringList resourceFiles = formResources(formFile);
|
|
|
|
|
foreach (const QString &resourceFile, resourceFiles)
|
|
|
|
|
if (!qrcFiles.contains(resourceFile))
|
|
|
|
|
qrcFiles.append(resourceFile);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList uniqueQrcFiles;
|
|
|
|
|
foreach (const QString &file, qrcFiles) {
|
2019-05-28 13:49:26 +02:00
|
|
|
if (!m_recursiveEnumerateFiles.contains(FilePath::fromString(file)))
|
2017-02-09 11:40:25 +01:00
|
|
|
uniqueQrcFiles.append(file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList uniqueFilePaths;
|
|
|
|
|
foreach (const QString &file, typeFiles) {
|
2019-05-28 13:49:26 +02:00
|
|
|
if (!m_recursiveEnumerateFiles.contains(FilePath::fromString(file)))
|
2017-02-09 11:40:25 +01:00
|
|
|
uniqueFilePaths.append(file);
|
|
|
|
|
}
|
2019-01-23 17:30:52 +01:00
|
|
|
uniqueFilePaths.sort();
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
changeFiles(type, uniqueFilePaths, &failedFiles, AddToProFile);
|
|
|
|
|
if (notAdded)
|
|
|
|
|
*notAdded += failedFiles;
|
|
|
|
|
changeFiles(QLatin1String(ProjectExplorer::Constants::RESOURCE_MIMETYPE), uniqueQrcFiles, &failedFiles, AddToProFile);
|
|
|
|
|
if (notAdded)
|
|
|
|
|
*notAdded += failedFiles;
|
|
|
|
|
}
|
|
|
|
|
return failedFiles.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::removeFiles(const QStringList &filePaths,
|
2017-02-09 11:40:25 +01:00
|
|
|
QStringList *notRemoved)
|
|
|
|
|
{
|
|
|
|
|
QStringList failedFiles;
|
2018-07-12 23:59:51 +02:00
|
|
|
using TypeFileMap = QMap<QString, QStringList>;
|
2017-02-09 11:40:25 +01:00
|
|
|
// Split into lists by file type and bulk-add them.
|
|
|
|
|
TypeFileMap typeFileMap;
|
|
|
|
|
foreach (const QString &file, filePaths) {
|
2017-03-02 12:07:11 +01:00
|
|
|
const Utils::MimeType mt = Utils::mimeTypeForFile(file);
|
2017-02-09 11:40:25 +01:00
|
|
|
typeFileMap[mt.name()] << file;
|
|
|
|
|
}
|
|
|
|
|
foreach (const QString &type, typeFileMap.keys()) {
|
|
|
|
|
const QStringList typeFiles = typeFileMap.value(type);
|
|
|
|
|
changeFiles(type, typeFiles, &failedFiles, RemoveFromProFile);
|
|
|
|
|
if (notRemoved)
|
|
|
|
|
*notRemoved = failedFiles;
|
|
|
|
|
}
|
|
|
|
|
return failedFiles.isEmpty();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::deleteFiles(const QStringList &filePaths)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
removeFiles(filePaths);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::canRenameFile(const QString &filePath, const QString &newFilePath)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
if (newFilePath.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bool changeProFileOptional = deploysFolder(QFileInfo(filePath).absolutePath());
|
|
|
|
|
if (changeProFileOptional)
|
|
|
|
|
return true;
|
|
|
|
|
|
2019-10-29 17:11:00 +01:00
|
|
|
return renameFile(filePath, newFilePath, Change::TestOnly);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::renameFile(const QString &filePath, const QString &newFilePath)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
if (newFilePath.isEmpty())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
bool changeProFileOptional = deploysFolder(QFileInfo(filePath).absolutePath());
|
2019-10-29 17:11:00 +01:00
|
|
|
if (renameFile(filePath, newFilePath, Change::Save))
|
2017-02-09 11:40:25 +01:00
|
|
|
return true;
|
|
|
|
|
return changeProFileOptional;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-18 15:41:27 +02:00
|
|
|
bool QmakePriFile::addDependencies(const QStringList &dependencies)
|
|
|
|
|
{
|
|
|
|
|
if (dependencies.isEmpty())
|
|
|
|
|
return true;
|
|
|
|
|
if (!prepareForChange())
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
QStringList qtDependencies = filtered(dependencies, [](const QString &dep) {
|
|
|
|
|
return dep.length() > 3 && dep.startsWith("Qt.");
|
|
|
|
|
});
|
|
|
|
|
qtDependencies = transform(qtDependencies, [](const QString &dep) {
|
|
|
|
|
return dep.mid(3);
|
|
|
|
|
});
|
|
|
|
|
qtDependencies.removeOne("core");
|
|
|
|
|
if (qtDependencies.isEmpty())
|
|
|
|
|
return true;
|
|
|
|
|
|
2019-07-24 16:04:09 +02:00
|
|
|
const QPair<ProFile *, QStringList> pair = readProFile();
|
2019-06-18 15:41:27 +02:00
|
|
|
ProFile * const includeFile = pair.first;
|
|
|
|
|
if (!includeFile)
|
|
|
|
|
return false;
|
|
|
|
|
QStringList lines = pair.second;
|
|
|
|
|
|
|
|
|
|
const QString indent = continuationIndent();
|
|
|
|
|
const ProWriter::PutFlags appendFlags(ProWriter::AppendValues | ProWriter::AppendOperator);
|
|
|
|
|
if (!proFile()->variableValue(Variable::Config).contains("qt")) {
|
|
|
|
|
if (lines.removeAll("CONFIG -= qt") == 0) {
|
|
|
|
|
ProWriter::putVarValues(includeFile, &lines, {"qt"}, "CONFIG", appendFlags,
|
|
|
|
|
QString(), indent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QStringList currentQtDependencies = proFile()->variableValue(Variable::Qt);
|
|
|
|
|
qtDependencies = filtered(qtDependencies, [currentQtDependencies](const QString &dep) {
|
|
|
|
|
return !currentQtDependencies.contains(dep);
|
|
|
|
|
});
|
|
|
|
|
if (!qtDependencies.isEmpty()) {
|
|
|
|
|
ProWriter::putVarValues(includeFile, &lines, qtDependencies, "QT", appendFlags,
|
|
|
|
|
QString(), indent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
save(lines);
|
|
|
|
|
includeFile->deref();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::saveModifiedEditors()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
Core::IDocument *document
|
2017-02-09 15:35:19 +01:00
|
|
|
= Core::DocumentModel::documentForFilePath(filePath().toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!document || !document->isModified())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (!Core::DocumentManager::saveDocument(document))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// force instant reload of ourselves
|
2017-08-14 18:30:29 +02:00
|
|
|
QtSupport::ProFileCacheManager::instance()->discardFile(
|
2019-10-25 09:55:32 +02:00
|
|
|
filePath().toString(), m_buildSystem->qmakeVfs());
|
|
|
|
|
|
|
|
|
|
m_buildSystem->notifyChanged(filePath());
|
2017-02-09 11:40:25 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QStringList QmakePriFile::formResources(const QString &formFile) const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList resourceFiles;
|
|
|
|
|
QFile file(formFile);
|
|
|
|
|
if (!file.open(QIODevice::ReadOnly))
|
|
|
|
|
return resourceFiles;
|
|
|
|
|
|
|
|
|
|
QXmlStreamReader reader(&file);
|
|
|
|
|
|
|
|
|
|
QFileInfo fi(formFile);
|
|
|
|
|
QDir formDir = fi.absoluteDir();
|
|
|
|
|
while (!reader.atEnd()) {
|
|
|
|
|
reader.readNext();
|
|
|
|
|
if (reader.isStartElement()) {
|
|
|
|
|
if (reader.name() == QLatin1String("iconset")) {
|
|
|
|
|
const QXmlStreamAttributes attributes = reader.attributes();
|
|
|
|
|
if (attributes.hasAttribute(QLatin1String("resource")))
|
|
|
|
|
resourceFiles.append(QDir::cleanPath(formDir.absoluteFilePath(
|
|
|
|
|
attributes.value(QLatin1String("resource")).toString())));
|
|
|
|
|
} else if (reader.name() == QLatin1String("include")) {
|
|
|
|
|
const QXmlStreamAttributes attributes = reader.attributes();
|
|
|
|
|
if (attributes.hasAttribute(QLatin1String("location")))
|
|
|
|
|
resourceFiles.append(QDir::cleanPath(formDir.absoluteFilePath(
|
|
|
|
|
attributes.value(QLatin1String("location")).toString())));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (reader.hasError())
|
|
|
|
|
qWarning() << "Could not read form file:" << formFile;
|
|
|
|
|
|
|
|
|
|
return resourceFiles;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::ensureWriteableProFile(const QString &file)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
// Ensure that the file is not read only
|
|
|
|
|
QFileInfo fi(file);
|
|
|
|
|
if (!fi.isWritable()) {
|
|
|
|
|
// Try via vcs manager
|
|
|
|
|
Core::IVersionControl *versionControl = Core::VcsManager::findVersionControlForDirectory(fi.absolutePath());
|
|
|
|
|
if (!versionControl || !versionControl->vcsOpen(file)) {
|
|
|
|
|
bool makeWritable = QFile::setPermissions(file, fi.permissions() | QFile::WriteUser);
|
|
|
|
|
if (!makeWritable) {
|
|
|
|
|
QMessageBox::warning(Core::ICore::mainWindow(),
|
2017-02-09 16:45:36 +01:00
|
|
|
QCoreApplication::translate("QmakePriFile", "Failed"),
|
|
|
|
|
QCoreApplication::translate("QmakePriFile", "Could not write project file %1.").arg(file));
|
2017-02-09 11:40:25 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-24 16:04:09 +02:00
|
|
|
QPair<ProFile *, QStringList> QmakePriFile::readProFile()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList lines;
|
2017-02-09 23:45:58 +01:00
|
|
|
ProFile *includeFile = nullptr;
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QString contents;
|
|
|
|
|
{
|
2019-07-24 16:04:09 +02:00
|
|
|
QString errorMsg;
|
|
|
|
|
if (TextFileFormat::readFile(
|
|
|
|
|
filePath().toString(),
|
|
|
|
|
Core::EditorManager::defaultTextCodec(),
|
|
|
|
|
&contents,
|
|
|
|
|
&m_textFormat,
|
|
|
|
|
&errorMsg) != TextFileFormat::ReadSuccess) {
|
2019-10-25 09:55:32 +02:00
|
|
|
QmakeBuildSystem::proFileParseError(errorMsg);
|
2017-02-09 11:40:25 +01:00
|
|
|
return qMakePair(includeFile, lines);
|
|
|
|
|
}
|
2019-07-24 16:04:09 +02:00
|
|
|
lines = contents.split('\n');
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QMakeVfs vfs;
|
|
|
|
|
QtSupport::ProMessageHandler handler;
|
2017-02-09 23:45:58 +01:00
|
|
|
QMakeParser parser(nullptr, &vfs, &handler);
|
2019-07-24 16:04:09 +02:00
|
|
|
includeFile = parser.parsedProBlock(QStringRef(&contents), 0, filePath().toString(), 1);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
return qMakePair(includeFile, lines);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::prepareForChange()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-09 15:35:19 +01:00
|
|
|
return saveModifiedEditors() && ensureWriteableProFile(filePath().toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-10-29 17:11:00 +01:00
|
|
|
bool QmakePriFile::renameFile(const QString &oldName, const QString &newName, Change mode)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
if (!prepareForChange())
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-07-24 16:04:09 +02:00
|
|
|
QPair<ProFile *, QStringList> pair = readProFile();
|
2017-02-09 11:40:25 +01:00
|
|
|
ProFile *includeFile = pair.first;
|
|
|
|
|
QStringList lines = pair.second;
|
|
|
|
|
|
|
|
|
|
if (!includeFile)
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString());
|
2019-10-29 17:11:00 +01:00
|
|
|
ProWriter::VarLocations removedLocations;
|
|
|
|
|
const QStringList notChanged = ProWriter::removeFiles(
|
|
|
|
|
includeFile,
|
|
|
|
|
&lines,
|
|
|
|
|
priFileDir,
|
|
|
|
|
QStringList(oldName),
|
|
|
|
|
varNamesForRemoving(),
|
|
|
|
|
&removedLocations
|
|
|
|
|
);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
includeFile->deref();
|
|
|
|
|
if (!notChanged.isEmpty())
|
|
|
|
|
return false;
|
2019-10-29 17:11:00 +01:00
|
|
|
QTC_ASSERT(!removedLocations.isEmpty(), return false);
|
|
|
|
|
|
|
|
|
|
int endLine = lines.count();
|
|
|
|
|
reverseForeach(removedLocations,
|
|
|
|
|
[this, &newName, &lines, &endLine](const ProWriter::VarLocation &loc) {
|
|
|
|
|
QStringList currentLines = lines.mid(loc.second, endLine - loc.second);
|
|
|
|
|
const QString currentContents = currentLines.join('\n');
|
|
|
|
|
|
|
|
|
|
// Reparse necessary due to changed contents.
|
|
|
|
|
QMakeParser parser(nullptr, nullptr, nullptr);
|
|
|
|
|
ProFile * const proFile = parser.parsedProBlock(
|
|
|
|
|
QStringRef(¤tContents),
|
|
|
|
|
0,
|
|
|
|
|
filePath().toString(),
|
|
|
|
|
1,
|
|
|
|
|
QMakeParser::FullGrammar
|
|
|
|
|
);
|
|
|
|
|
QTC_ASSERT(proFile, return); // The file should still be valid after what we did.
|
|
|
|
|
|
|
|
|
|
ProWriter::addFiles(proFile, ¤tLines, {newName}, loc.first, continuationIndent());
|
|
|
|
|
lines = lines.mid(0, loc.second) + currentLines + lines.mid(endLine);
|
|
|
|
|
endLine = loc.second;
|
|
|
|
|
proFile->deref();
|
|
|
|
|
});
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
if (mode == Change::Save)
|
|
|
|
|
save(lines);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::changeFiles(const QString &mimeType,
|
2017-02-09 11:40:25 +01:00
|
|
|
const QStringList &filePaths,
|
|
|
|
|
QStringList *notChanged,
|
|
|
|
|
ChangeType change, Change mode)
|
|
|
|
|
{
|
|
|
|
|
if (filePaths.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
*notChanged = filePaths;
|
|
|
|
|
|
|
|
|
|
// Check for modified editors
|
|
|
|
|
if (!prepareForChange())
|
|
|
|
|
return;
|
|
|
|
|
|
2019-07-24 16:04:09 +02:00
|
|
|
QPair<ProFile *, QStringList> pair = readProFile();
|
2017-02-09 11:40:25 +01:00
|
|
|
ProFile *includeFile = pair.first;
|
|
|
|
|
QStringList lines = pair.second;
|
|
|
|
|
|
|
|
|
|
if (!includeFile)
|
|
|
|
|
return;
|
|
|
|
|
|
2020-03-11 14:01:35 +01:00
|
|
|
qCDebug(qmakeNodesLog) << Q_FUNC_INFO << "mime type:" << mimeType << "file paths:"
|
|
|
|
|
<< filePaths << "change type:" << int(change) << "mode:" << int(mode);
|
2017-02-09 11:40:25 +01:00
|
|
|
if (change == AddToProFile) {
|
|
|
|
|
// Use the first variable for adding.
|
2019-02-01 16:50:29 +01:00
|
|
|
ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType),
|
|
|
|
|
continuationIndent());
|
2017-02-09 11:40:25 +01:00
|
|
|
notChanged->clear();
|
|
|
|
|
} else { // RemoveFromProFile
|
2017-02-09 16:45:36 +01:00
|
|
|
QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
*notChanged = ProWriter::removeFiles(includeFile, &lines, priFileDir, filePaths, varNamesForRemoving());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// save file
|
|
|
|
|
if (mode == Change::Save)
|
|
|
|
|
save(lines);
|
|
|
|
|
includeFile->deref();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 17:02:47 +01:00
|
|
|
void QmakePriFile::addChild(QmakePriFile *pf)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(!m_children.contains(pf), return);
|
|
|
|
|
QTC_ASSERT(!pf->parent(), return);
|
|
|
|
|
m_children.append(pf);
|
|
|
|
|
pf->setParent(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void QmakePriFile::setParent(QmakePriFile *p)
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(!m_parent, return);
|
|
|
|
|
m_parent = p;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakePriFile::setProVariable(const QString &var, const QStringList &values, const QString &scope, int flags)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
if (!prepareForChange())
|
|
|
|
|
return false;
|
|
|
|
|
|
2019-07-24 16:04:09 +02:00
|
|
|
QPair<ProFile *, QStringList> pair = readProFile();
|
2017-02-09 11:40:25 +01:00
|
|
|
ProFile *includeFile = pair.first;
|
|
|
|
|
QStringList lines = pair.second;
|
|
|
|
|
|
|
|
|
|
if (!includeFile)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
ProWriter::putVarValues(includeFile, &lines, values, var,
|
|
|
|
|
ProWriter::PutFlags(flags),
|
2019-02-01 16:50:29 +01:00
|
|
|
scope, continuationIndent());
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
save(lines);
|
|
|
|
|
includeFile->deref();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakePriFile::save(const QStringList &lines)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
{
|
2019-07-24 16:04:09 +02:00
|
|
|
QTC_ASSERT(m_textFormat.codec, return);
|
2017-02-09 15:35:19 +01:00
|
|
|
FileChangeBlocker changeGuard(filePath().toString());
|
2019-07-24 16:04:09 +02:00
|
|
|
QString errorMsg;
|
|
|
|
|
if (!m_textFormat.writeFile(filePath().toString(), lines.join('\n'), &errorMsg)) {
|
|
|
|
|
QMessageBox::critical(Core::ICore::mainWindow(), QCoreApplication::translate(
|
|
|
|
|
"QmakePriFile", "File Error"), errorMsg);
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is a hack.
|
|
|
|
|
// We are saving twice in a very short timeframe, once the editor and once the ProFile.
|
|
|
|
|
// So the modification time might not change between those two saves.
|
|
|
|
|
// We manually tell each editor to reload it's file.
|
|
|
|
|
// (The .pro files are notified by the file system watcher.)
|
|
|
|
|
QStringList errorStrings;
|
2017-02-09 15:35:19 +01:00
|
|
|
Core::IDocument *document = Core::DocumentModel::documentForFilePath(filePath().toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
if (document) {
|
|
|
|
|
QString errorString;
|
|
|
|
|
if (!document->reload(&errorString, Core::IDocument::FlagReload, Core::IDocument::TypeContents))
|
|
|
|
|
errorStrings << errorString;
|
|
|
|
|
}
|
|
|
|
|
if (!errorStrings.isEmpty())
|
2017-02-09 16:45:36 +01:00
|
|
|
QMessageBox::warning(Core::ICore::mainWindow(), QCoreApplication::translate("QmakePriFile", "File Error"),
|
2017-02-09 11:40:25 +01:00
|
|
|
errorStrings.join(QLatin1Char('\n')));
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QStringList QmakePriFile::varNames(FileType type, QtSupport::ProFileReader *readerExact)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList vars;
|
|
|
|
|
switch (type) {
|
|
|
|
|
case FileType::Header:
|
2019-06-12 15:03:23 +02:00
|
|
|
vars << "HEADERS" << "OBJECTIVE_HEADERS" << "PRECOMPILED_HEADER";
|
2017-02-09 11:40:25 +01:00
|
|
|
break;
|
|
|
|
|
case FileType::Source: {
|
|
|
|
|
vars << QLatin1String("SOURCES");
|
|
|
|
|
QStringList listOfExtraCompilers = readerExact->values(QLatin1String("QMAKE_EXTRA_COMPILERS"));
|
|
|
|
|
foreach (const QString &var, listOfExtraCompilers) {
|
|
|
|
|
QStringList inputs = readerExact->values(var + QLatin1String(".input"));
|
|
|
|
|
foreach (const QString &input, inputs)
|
|
|
|
|
// FORMS, RESOURCES, and STATECHARTS are handled below, HEADERS and SOURCES above
|
2019-06-12 15:03:23 +02:00
|
|
|
if (input != "FORMS"
|
|
|
|
|
&& input != "STATECHARTS"
|
|
|
|
|
&& input != "RESOURCES"
|
|
|
|
|
&& input != "SOURCES"
|
|
|
|
|
&& input != "HEADERS"
|
|
|
|
|
&& input != "OBJECTIVE_HEADERS"
|
|
|
|
|
&& input != "PRECOMPILED_HEADER") {
|
2017-02-09 11:40:25 +01:00
|
|
|
vars << input;
|
2019-06-12 15:03:23 +02:00
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case FileType::Resource:
|
|
|
|
|
vars << QLatin1String("RESOURCES");
|
|
|
|
|
break;
|
|
|
|
|
case FileType::Form:
|
|
|
|
|
vars << QLatin1String("FORMS");
|
|
|
|
|
break;
|
|
|
|
|
case FileType::StateChart:
|
|
|
|
|
vars << QLatin1String("STATECHARTS");
|
|
|
|
|
break;
|
|
|
|
|
case FileType::Project:
|
|
|
|
|
vars << QLatin1String("SUBDIRS");
|
|
|
|
|
break;
|
|
|
|
|
case FileType::QML:
|
|
|
|
|
vars << QLatin1String("OTHER_FILES");
|
|
|
|
|
vars << QLatin1String("DISTFILES");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2019-07-31 15:49:41 +02:00
|
|
|
vars << "DISTFILES" << "ICON" << "OTHER_FILES" << "QMAKE_INFO_PLIST" << "TRANSLATIONS";
|
2017-02-09 11:40:25 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return vars;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//!
|
2017-02-09 16:45:36 +01:00
|
|
|
//! \brief QmakePriFile::varNames
|
2017-02-09 11:40:25 +01:00
|
|
|
//! \param mimeType
|
|
|
|
|
//! \return the qmake variable name for the mime type
|
|
|
|
|
//! Note: Only used for adding.
|
|
|
|
|
//!
|
2017-02-09 16:45:36 +01:00
|
|
|
QString QmakePriFile::varNameForAdding(const QString &mimeType)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
if (mimeType == QLatin1String(ProjectExplorer::Constants::CPP_HEADER_MIMETYPE)
|
|
|
|
|
|| mimeType == QLatin1String(ProjectExplorer::Constants::C_HEADER_MIMETYPE)) {
|
|
|
|
|
return QLatin1String("HEADERS");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mimeType == QLatin1String(ProjectExplorer::Constants::CPP_SOURCE_MIMETYPE)
|
|
|
|
|
|| mimeType == QLatin1String(CppTools::Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)
|
|
|
|
|
|| mimeType == QLatin1String(ProjectExplorer::Constants::C_SOURCE_MIMETYPE)) {
|
|
|
|
|
return QLatin1String("SOURCES");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mimeType == QLatin1String(ProjectExplorer::Constants::RESOURCE_MIMETYPE))
|
|
|
|
|
return QLatin1String("RESOURCES");
|
|
|
|
|
|
|
|
|
|
if (mimeType == QLatin1String(ProjectExplorer::Constants::FORM_MIMETYPE))
|
|
|
|
|
return QLatin1String("FORMS");
|
|
|
|
|
|
2017-10-17 18:53:28 +02:00
|
|
|
if (mimeType == QLatin1String(ProjectExplorer::Constants::QML_MIMETYPE)
|
|
|
|
|
|| mimeType == QLatin1String(ProjectExplorer::Constants::QMLUI_MIMETYPE)) {
|
2017-02-09 11:40:25 +01:00
|
|
|
return QLatin1String("DISTFILES");
|
2017-10-17 18:53:28 +02:00
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
if (mimeType == QLatin1String(ProjectExplorer::Constants::SCXML_MIMETYPE))
|
|
|
|
|
return QLatin1String("STATECHARTS");
|
|
|
|
|
|
|
|
|
|
if (mimeType == QLatin1String(Constants::PROFILE_MIMETYPE))
|
|
|
|
|
return QLatin1String("SUBDIRS");
|
|
|
|
|
|
|
|
|
|
return QLatin1String("DISTFILES");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//!
|
2017-02-09 16:45:36 +01:00
|
|
|
//! \brief QmakePriFile::varNamesForRemoving
|
2017-02-09 11:40:25 +01:00
|
|
|
//! \return all qmake variables which are displayed in the project tree
|
|
|
|
|
//! Note: Only used for removing.
|
|
|
|
|
//!
|
2017-02-09 16:45:36 +01:00
|
|
|
QStringList QmakePriFile::varNamesForRemoving()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList vars;
|
|
|
|
|
vars << QLatin1String("HEADERS");
|
|
|
|
|
vars << QLatin1String("OBJECTIVE_HEADERS");
|
|
|
|
|
vars << QLatin1String("PRECOMPILED_HEADER");
|
|
|
|
|
vars << QLatin1String("SOURCES");
|
|
|
|
|
vars << QLatin1String("OBJECTIVE_SOURCES");
|
|
|
|
|
vars << QLatin1String("RESOURCES");
|
|
|
|
|
vars << QLatin1String("FORMS");
|
|
|
|
|
vars << QLatin1String("OTHER_FILES");
|
|
|
|
|
vars << QLatin1String("SUBDIRS");
|
|
|
|
|
vars << QLatin1String("DISTFILES");
|
|
|
|
|
vars << QLatin1String("ICON");
|
|
|
|
|
vars << QLatin1String("QMAKE_INFO_PLIST");
|
|
|
|
|
vars << QLatin1String("STATECHARTS");
|
|
|
|
|
return vars;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> QmakePriFile::filterFilesProVariables(FileType fileType, const QSet<FilePath> &files)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
if (fileType != FileType::QML && fileType != FileType::Unknown)
|
|
|
|
|
return files;
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> result;
|
2017-02-09 11:40:25 +01:00
|
|
|
if (fileType == FileType::QML) {
|
2019-05-28 13:49:26 +02:00
|
|
|
foreach (const FilePath &file, files)
|
2017-02-09 11:40:25 +01:00
|
|
|
if (file.toString().endsWith(QLatin1String(".qml")))
|
|
|
|
|
result << file;
|
|
|
|
|
} else {
|
2019-05-28 13:49:26 +02:00
|
|
|
foreach (const FilePath &file, files)
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!file.toString().endsWith(QLatin1String(".qml")))
|
|
|
|
|
result << file;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> QmakePriFile::filterFilesRecursiveEnumerata(FileType fileType, const QSet<FilePath> &files)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2019-05-28 13:49:26 +02:00
|
|
|
QSet<FilePath> result;
|
2017-02-09 11:40:25 +01:00
|
|
|
if (fileType != FileType::QML && fileType != FileType::Unknown)
|
|
|
|
|
return result;
|
|
|
|
|
if (fileType == FileType::QML) {
|
2019-05-28 13:49:26 +02:00
|
|
|
foreach (const FilePath &file, files)
|
2017-02-09 11:40:25 +01:00
|
|
|
if (file.toString().endsWith(QLatin1String(".qml")))
|
|
|
|
|
result << file;
|
|
|
|
|
} else {
|
2019-05-28 13:49:26 +02:00
|
|
|
foreach (const FilePath &file, files)
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!file.toString().endsWith(QLatin1String(".qml")))
|
|
|
|
|
result << file;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace QmakeProjectManager
|
|
|
|
|
|
2017-02-09 13:56:22 +01:00
|
|
|
static ProjectType proFileTemplateTypeToProjectType(ProFileEvaluator::TemplateType type)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
switch (type) {
|
|
|
|
|
case ProFileEvaluator::TT_Unknown:
|
|
|
|
|
case ProFileEvaluator::TT_Application:
|
2017-02-09 13:56:22 +01:00
|
|
|
return ProjectType::ApplicationTemplate;
|
2017-02-09 11:40:25 +01:00
|
|
|
case ProFileEvaluator::TT_StaticLibrary:
|
2017-02-09 13:56:22 +01:00
|
|
|
return ProjectType::StaticLibraryTemplate;
|
2017-02-09 11:40:25 +01:00
|
|
|
case ProFileEvaluator::TT_SharedLibrary:
|
2017-02-09 13:56:22 +01:00
|
|
|
return ProjectType::SharedLibraryTemplate;
|
2017-02-09 11:40:25 +01:00
|
|
|
case ProFileEvaluator::TT_Script:
|
2017-02-09 13:56:22 +01:00
|
|
|
return ProjectType::ScriptTemplate;
|
2017-02-09 11:40:25 +01:00
|
|
|
case ProFileEvaluator::TT_Aux:
|
2017-02-09 13:56:22 +01:00
|
|
|
return ProjectType::AuxTemplate;
|
2017-02-09 11:40:25 +01:00
|
|
|
case ProFileEvaluator::TT_Subdirs:
|
2017-02-09 13:56:22 +01:00
|
|
|
return ProjectType::SubDirsTemplate;
|
2017-02-09 11:40:25 +01:00
|
|
|
default:
|
2017-02-09 13:56:22 +01:00
|
|
|
return ProjectType::Invalid;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QmakeProFile *QmakeProFile::findProFile(const FilePath &fileName)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-11-02 15:23:37 +01:00
|
|
|
return static_cast<QmakeProFile *>(findPriFile(fileName));
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
const QmakeProFile *QmakeProFile::findProFile(const FilePath &fileName) const
|
2017-11-02 15:23:37 +01:00
|
|
|
{
|
|
|
|
|
return static_cast<const QmakeProFile *>(findPriFile(fileName));
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QByteArray QmakeProFile::cxxDefines() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QByteArray result;
|
|
|
|
|
foreach (const QString &def, variableValue(Variable::Defines)) {
|
|
|
|
|
// 'def' is shell input, so interpret it.
|
|
|
|
|
QtcProcess::SplitError error = QtcProcess::SplitOk;
|
|
|
|
|
const QStringList args = QtcProcess::splitArgs(def, HostOsInfo::hostOs(), false, &error);
|
|
|
|
|
if (error != QtcProcess::SplitOk || args.size() == 0)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
result += "#define ";
|
|
|
|
|
const QString defInterpreted = args.first();
|
|
|
|
|
const int index = defInterpreted.indexOf(QLatin1Char('='));
|
|
|
|
|
if (index == -1) {
|
|
|
|
|
result += defInterpreted.toLatin1();
|
|
|
|
|
result += " 1\n";
|
|
|
|
|
} else {
|
|
|
|
|
const QString name = defInterpreted.left(index);
|
|
|
|
|
const QString value = defInterpreted.mid(index + 1);
|
|
|
|
|
result += name.toLatin1();
|
|
|
|
|
result += ' ';
|
|
|
|
|
result += value.toLocal8Bit();
|
|
|
|
|
result += '\n';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*!
|
2017-02-09 16:45:36 +01:00
|
|
|
\class QmakeProFile
|
2017-02-09 11:40:25 +01:00
|
|
|
Implements abstract ProjectNode class
|
|
|
|
|
*/
|
2019-10-25 09:55:32 +02:00
|
|
|
QmakeProFile::QmakeProFile(QmakeBuildSystem *buildSystem, const FilePath &filePath) :
|
|
|
|
|
QmakePriFile(buildSystem, this, filePath)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2020-01-31 15:52:20 +01:00
|
|
|
setupFutureWatcher();
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-31 15:52:20 +01:00
|
|
|
QmakeProFile::QmakeProFile(const FilePath &filePath) : QmakePriFile(filePath) { }
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QmakeProFile::~QmakeProFile()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
qDeleteAll(m_extraCompilers);
|
2020-02-12 15:32:52 +01:00
|
|
|
if (m_parseFutureWatcher) {
|
|
|
|
|
m_parseFutureWatcher->cancel();
|
|
|
|
|
m_parseFutureWatcher->waitForFinished();
|
|
|
|
|
if (m_readerExact)
|
|
|
|
|
applyAsyncEvaluate();
|
|
|
|
|
delete m_parseFutureWatcher;
|
|
|
|
|
}
|
2017-11-24 13:32:20 +01:00
|
|
|
cleanupProFileReaders();
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-31 15:52:20 +01:00
|
|
|
void QmakeProFile::setupFutureWatcher()
|
|
|
|
|
{
|
|
|
|
|
m_parseFutureWatcher = new QFutureWatcher<Internal::QmakeEvalResult *>;
|
|
|
|
|
QObject::connect(m_parseFutureWatcher, &QFutureWatcherBase::finished,
|
|
|
|
|
[this](){ applyAsyncEvaluate(); });
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakeProFile::isParent(QmakeProFile *node)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-10 09:56:33 +01:00
|
|
|
while ((node = dynamic_cast<QmakeProFile *>(node->parent()))) {
|
2017-02-09 11:40:25 +01:00
|
|
|
if (node == this)
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-10 09:56:33 +01:00
|
|
|
QString QmakeProFile::displayName() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-15 10:24:32 +01:00
|
|
|
if (!m_displayName.isEmpty())
|
|
|
|
|
return m_displayName;
|
|
|
|
|
return QmakePriFile::displayName();
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-15 12:40:09 +01:00
|
|
|
QList<QmakeProFile *> QmakeProFile::allProFiles()
|
|
|
|
|
{
|
|
|
|
|
QList<QmakeProFile *> result = { this };
|
|
|
|
|
for (QmakePriFile *c : m_children) {
|
|
|
|
|
auto proC = dynamic_cast<QmakeProFile *>(c);
|
|
|
|
|
if (proC)
|
|
|
|
|
result.append(proC->allProFiles());
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
ProjectType QmakeProFile::projectType() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_projectType;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QStringList QmakeProFile::variableValue(const Variable var) const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_varValues.value(var);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QString QmakeProFile::singleVariableValue(const Variable var) const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
const QStringList &values = variableValue(var);
|
|
|
|
|
return values.isEmpty() ? QString() : values.first();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::setParseInProgressRecursive(bool b)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
setParseInProgress(b);
|
2017-02-10 09:56:33 +01:00
|
|
|
foreach (QmakePriFile *c, children()) {
|
|
|
|
|
if (auto node = dynamic_cast<QmakeProFile *>(c))
|
2017-02-09 11:40:25 +01:00
|
|
|
node->setParseInProgressRecursive(b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::setParseInProgress(bool b)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
m_parseInProgress = b;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Do note the absence of signal emission, always set validParse
|
|
|
|
|
// before setParseInProgress, as that will emit the signals
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::setValidParseRecursive(bool b)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
m_validParse = b;
|
2017-02-10 09:56:33 +01:00
|
|
|
foreach (QmakePriFile *c, children()) {
|
2018-07-12 23:59:51 +02:00
|
|
|
if (auto *node = dynamic_cast<QmakeProFile *>(c))
|
2017-02-09 11:40:25 +01:00
|
|
|
node->setValidParseRecursive(b);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakeProFile::validParse() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_validParse;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
bool QmakeProFile::parseInProgress() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_parseInProgress;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::scheduleUpdate(QmakeProFile::AsyncUpdateDelay delay)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
setParseInProgressRecursive(true);
|
2019-10-25 09:55:32 +02:00
|
|
|
m_buildSystem->scheduleAsyncUpdateFile(this, delay);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::asyncUpdate()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2019-10-25 09:55:32 +02:00
|
|
|
m_buildSystem->incrementPendingEvaluateFutures();
|
2017-02-09 11:40:25 +01:00
|
|
|
setupReader();
|
|
|
|
|
if (!includedInExactParse())
|
|
|
|
|
m_readerExact->setExact(false);
|
2020-01-31 15:52:20 +01:00
|
|
|
m_parseFutureWatcher->waitForFinished();
|
2017-02-09 11:40:25 +01:00
|
|
|
QmakeEvalInput input = evalInput();
|
|
|
|
|
QFuture<QmakeEvalResult *> future = Utils::runAsync(ProjectExplorerPlugin::sharedThreadPool(),
|
2017-07-13 16:29:15 +02:00
|
|
|
QThread::LowestPriority,
|
|
|
|
|
&QmakeProFile::asyncEvaluate,
|
|
|
|
|
this, input);
|
2020-01-31 15:52:20 +01:00
|
|
|
m_parseFutureWatcher->setFuture(future);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-06-18 14:39:38 +03:00
|
|
|
bool QmakeProFile::isFileFromWildcard(const QString &filePath) const
|
|
|
|
|
{
|
|
|
|
|
const QFileInfo fileInfo(filePath);
|
|
|
|
|
const auto directoryIterator = m_wildcardDirectoryContents.constFind(fileInfo.path());
|
|
|
|
|
return (directoryIterator != m_wildcardDirectoryContents.end()
|
|
|
|
|
&& directoryIterator.value().contains(fileInfo.fileName()));
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QmakeEvalInput QmakeProFile::evalInput() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QmakeEvalInput input;
|
2017-02-09 15:35:19 +01:00
|
|
|
input.projectDir = directoryPath().toString();
|
|
|
|
|
input.projectFilePath = filePath();
|
2020-03-20 14:55:49 +01:00
|
|
|
input.buildDirectory = m_buildSystem->buildDir(m_filePath);
|
2019-10-25 09:55:32 +02:00
|
|
|
input.sysroot = FilePath::fromString(m_buildSystem->qmakeSysroot());
|
2017-02-09 11:40:25 +01:00
|
|
|
input.readerExact = m_readerExact;
|
|
|
|
|
input.readerCumulative = m_readerCumulative;
|
2019-10-25 09:55:32 +02:00
|
|
|
input.qmakeGlobals = m_buildSystem->qmakeGlobals();
|
|
|
|
|
input.qmakeVfs = m_buildSystem->qmakeVfs();
|
2020-01-31 15:52:20 +01:00
|
|
|
input.includedInExcactParse = includedInExactParse();
|
|
|
|
|
for (const QmakePriFile *pri = this; pri; pri = pri->parent())
|
|
|
|
|
input.parentFilePaths.insert(pri->filePath());
|
2017-02-09 11:40:25 +01:00
|
|
|
return input;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::setupReader()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
Q_ASSERT(!m_readerExact);
|
|
|
|
|
Q_ASSERT(!m_readerCumulative);
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
m_readerExact = m_buildSystem->createProFileReader(this);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
m_readerCumulative = m_buildSystem->createProFileReader(this);
|
2017-02-09 11:40:25 +01:00
|
|
|
m_readerCumulative->setCumulative(true);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 23:39:57 +01:00
|
|
|
static bool evaluateOne(const QmakeEvalInput &input, ProFile *pro,
|
|
|
|
|
QtSupport::ProFileReader *reader, bool cumulative,
|
|
|
|
|
QtSupport::ProFileReader **buildPassReader)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
if (!reader->accept(pro, QMakeEvaluator::LoadAll))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
QStringList builds = reader->values(QLatin1String("BUILDS"));
|
|
|
|
|
if (builds.isEmpty()) {
|
|
|
|
|
*buildPassReader = reader;
|
|
|
|
|
} else {
|
|
|
|
|
QString build = builds.first();
|
|
|
|
|
QHash<QString, QStringList> basevars;
|
|
|
|
|
QStringList basecfgs = reader->values(build + QLatin1String(".CONFIG"));
|
|
|
|
|
basecfgs += build;
|
|
|
|
|
basecfgs += QLatin1String("build_pass");
|
2019-02-27 09:32:09 +01:00
|
|
|
basecfgs += "qtc_run";
|
2017-02-09 11:40:25 +01:00
|
|
|
basevars[QLatin1String("BUILD_PASS")] = QStringList(build);
|
|
|
|
|
QStringList buildname = reader->values(build + QLatin1String(".name"));
|
|
|
|
|
basevars[QLatin1String("BUILD_NAME")] = (buildname.isEmpty() ? QStringList(build) : buildname);
|
|
|
|
|
|
|
|
|
|
// We don't increase/decrease m_qmakeGlobalsRefCnt here, because the outer profilereaders keep m_qmakeGlobals alive anyway
|
|
|
|
|
auto bpReader = new QtSupport::ProFileReader(input.qmakeGlobals, input.qmakeVfs); // needs to access m_qmakeGlobals, m_qmakeVfs
|
2017-02-15 12:53:30 +01:00
|
|
|
bpReader->setOutputDir(input.buildDirectory.toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
bpReader->setCumulative(cumulative);
|
|
|
|
|
bpReader->setExtraVars(basevars);
|
|
|
|
|
bpReader->setExtraConfigs(basecfgs);
|
|
|
|
|
|
|
|
|
|
if (bpReader->accept(pro, QMakeEvaluator::LoadAll))
|
|
|
|
|
*buildPassReader = bpReader;
|
|
|
|
|
else
|
|
|
|
|
delete bpReader;
|
|
|
|
|
}
|
2017-02-09 23:39:57 +01:00
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QmakeEvalResult *QmakeProFile::evaluate(const QmakeEvalInput &input)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2018-07-12 23:59:51 +02:00
|
|
|
auto *result = new QmakeEvalResult;
|
2017-02-09 11:40:25 +01:00
|
|
|
QtSupport::ProFileReader *exactBuildPassReader = nullptr;
|
|
|
|
|
QtSupport::ProFileReader *cumulativeBuildPassReader = nullptr;
|
|
|
|
|
ProFile *pro;
|
|
|
|
|
if ((pro = input.readerExact->parsedProFile(input.projectFilePath.toString()))) {
|
|
|
|
|
bool exactOk = evaluateOne(input, pro, input.readerExact, false, &exactBuildPassReader);
|
|
|
|
|
bool cumulOk = evaluateOne(input, pro, input.readerCumulative, true, &cumulativeBuildPassReader);
|
|
|
|
|
pro->deref();
|
2017-02-09 23:39:57 +01:00
|
|
|
result->state = exactOk ? QmakeEvalResult::EvalOk
|
|
|
|
|
: cumulOk ? QmakeEvalResult::EvalPartial : QmakeEvalResult::EvalFail;
|
2017-02-09 11:40:25 +01:00
|
|
|
} else {
|
2017-02-09 23:39:57 +01:00
|
|
|
result->state = QmakeEvalResult::EvalFail;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 23:39:57 +01:00
|
|
|
if (result->state == QmakeEvalResult::EvalFail)
|
2017-02-09 11:40:25 +01:00
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
result->includedFiles.proFile = pro;
|
|
|
|
|
result->includedFiles.name = input.projectFilePath;
|
|
|
|
|
|
2017-08-14 18:30:29 +02:00
|
|
|
QHash<int, QmakePriFileEvalResult *> proToResult;
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-09 23:39:57 +01:00
|
|
|
result->projectType
|
|
|
|
|
= proFileTemplateTypeToProjectType(
|
|
|
|
|
(result->state == QmakeEvalResult::EvalOk ? input.readerExact
|
|
|
|
|
: input.readerCumulative)->templateType());
|
|
|
|
|
if (result->state == QmakeEvalResult::EvalOk) {
|
|
|
|
|
if (result->projectType == ProjectType::SubDirsTemplate) {
|
2017-02-09 11:40:25 +01:00
|
|
|
QStringList errors;
|
2019-12-17 14:07:53 +01:00
|
|
|
FilePaths subDirs = subDirsPaths(input.readerExact, input.projectDir, &result->subProjectsNotToDeploy, &errors);
|
2017-02-09 11:40:25 +01:00
|
|
|
result->errors.append(errors);
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
foreach (const Utils::FilePath &subDirName, subDirs) {
|
2017-02-09 23:39:57 +01:00
|
|
|
auto subDir = new QmakeIncludedPriFile;
|
2017-02-09 11:40:25 +01:00
|
|
|
subDir->proFile = nullptr;
|
|
|
|
|
subDir->name = subDirName;
|
|
|
|
|
result->includedFiles.children.insert(subDirName, subDir);
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-05 13:43:54 +02:00
|
|
|
result->exactSubdirs = Utils::toSet(subDirs);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert ProFileReader::includeFiles to IncludedPriFile structure
|
2017-02-09 16:25:23 +01:00
|
|
|
QHash<ProFile *, QVector<ProFile *>> includeFiles = input.readerExact->includeFiles();
|
2017-02-22 15:09:35 +01:00
|
|
|
QList<QmakeIncludedPriFile *> toBuild = {&result->includedFiles};
|
2017-02-09 11:40:25 +01:00
|
|
|
while (!toBuild.isEmpty()) {
|
2017-02-09 23:39:57 +01:00
|
|
|
QmakeIncludedPriFile *current = toBuild.takeFirst();
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!current->proFile)
|
|
|
|
|
continue; // Don't attempt to map subdirs here
|
|
|
|
|
QVector<ProFile *> children = includeFiles.value(current->proFile);
|
|
|
|
|
foreach (ProFile *child, children) {
|
2019-05-28 13:49:26 +02:00
|
|
|
const Utils::FilePath childName = Utils::FilePath::fromString(child->fileName());
|
2017-02-09 11:40:25 +01:00
|
|
|
auto it = current->children.find(childName);
|
|
|
|
|
if (it == current->children.end()) {
|
2017-02-09 23:39:57 +01:00
|
|
|
auto childTree = new QmakeIncludedPriFile;
|
2017-02-09 11:40:25 +01:00
|
|
|
childTree->proFile = child;
|
|
|
|
|
childTree->name = childName;
|
|
|
|
|
current->children.insert(childName, childTree);
|
2017-08-14 18:30:29 +02:00
|
|
|
proToResult[child->id()] = &childTree->result;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
toBuild.append(current->children.values());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 23:39:57 +01:00
|
|
|
if (result->projectType == ProjectType::SubDirsTemplate) {
|
2019-12-17 14:07:53 +01:00
|
|
|
FilePaths subDirs = subDirsPaths(input.readerCumulative, input.projectDir, nullptr, nullptr);
|
2019-05-28 13:49:26 +02:00
|
|
|
foreach (const Utils::FilePath &subDirName, subDirs) {
|
2017-02-09 11:40:25 +01:00
|
|
|
auto it = result->includedFiles.children.find(subDirName);
|
|
|
|
|
if (it == result->includedFiles.children.end()) {
|
2017-02-09 23:39:57 +01:00
|
|
|
auto subDir = new QmakeIncludedPriFile;
|
2017-02-09 11:40:25 +01:00
|
|
|
subDir->proFile = nullptr;
|
|
|
|
|
subDir->name = subDirName;
|
|
|
|
|
result->includedFiles.children.insert(subDirName, subDir);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add ProFileReader::includeFiles information from cumulative parse to IncludedPriFile structure
|
2017-02-09 16:25:23 +01:00
|
|
|
QHash<ProFile *, QVector<ProFile *>> includeFiles = input.readerCumulative->includeFiles();
|
2017-02-22 15:09:35 +01:00
|
|
|
QList<QmakeIncludedPriFile *> toBuild = {&result->includedFiles};
|
2017-02-09 11:40:25 +01:00
|
|
|
while (!toBuild.isEmpty()) {
|
2017-02-09 23:39:57 +01:00
|
|
|
QmakeIncludedPriFile *current = toBuild.takeFirst();
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!current->proFile)
|
|
|
|
|
continue; // Don't attempt to map subdirs here
|
|
|
|
|
QVector<ProFile *> children = includeFiles.value(current->proFile);
|
|
|
|
|
foreach (ProFile *child, children) {
|
2019-05-28 13:49:26 +02:00
|
|
|
const Utils::FilePath childName = Utils::FilePath::fromString(child->fileName());
|
2017-02-09 11:40:25 +01:00
|
|
|
auto it = current->children.find(childName);
|
|
|
|
|
if (it == current->children.end()) {
|
2017-02-09 23:39:57 +01:00
|
|
|
auto childTree = new QmakeIncludedPriFile;
|
2017-02-09 11:40:25 +01:00
|
|
|
childTree->proFile = child;
|
|
|
|
|
childTree->name = childName;
|
|
|
|
|
current->children.insert(childName, childTree);
|
2017-08-14 18:30:29 +02:00
|
|
|
proToResult[child->id()] = &childTree->result;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
toBuild.append(current->children.values());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto exactReader = exactBuildPassReader ? exactBuildPassReader : input.readerExact;
|
|
|
|
|
auto cumulativeReader = cumulativeBuildPassReader ? cumulativeBuildPassReader : input.readerCumulative;
|
|
|
|
|
|
2017-02-09 16:25:23 +01:00
|
|
|
QHash<QString, QVector<ProFileEvaluator::SourceFile>> exactSourceFiles;
|
|
|
|
|
QHash<QString, QVector<ProFileEvaluator::SourceFile>> cumulativeSourceFiles;
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-17 16:45:11 +01:00
|
|
|
const QStringList baseVPathsExact
|
2017-02-15 12:53:30 +01:00
|
|
|
= baseVPaths(exactReader, input.projectDir, input.buildDirectory.toString());
|
2017-02-17 16:45:11 +01:00
|
|
|
const QStringList baseVPathsCumulative
|
2017-02-15 12:53:30 +01:00
|
|
|
= baseVPaths(cumulativeReader, input.projectDir, input.buildDirectory.toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-15 10:15:34 +01:00
|
|
|
for (int i = 0; i < static_cast<int>(FileType::FileTypeSize); ++i) {
|
2018-07-12 23:59:51 +02:00
|
|
|
const auto type = static_cast<FileType>(i);
|
2017-02-17 16:45:11 +01:00
|
|
|
const QStringList qmakeVariables = varNames(type, exactReader);
|
2017-02-09 11:40:25 +01:00
|
|
|
foreach (const QString &qmakeVariable, qmakeVariables) {
|
|
|
|
|
QHash<ProString, bool> handled;
|
2017-02-09 23:39:57 +01:00
|
|
|
if (result->state == QmakeEvalResult::EvalOk) {
|
2017-02-17 16:45:11 +01:00
|
|
|
const QStringList vPathsExact = fullVPaths(
|
2017-02-09 11:40:25 +01:00
|
|
|
baseVPathsExact, exactReader, qmakeVariable, input.projectDir);
|
|
|
|
|
auto sourceFiles = exactReader->absoluteFileValues(
|
2018-11-30 10:31:56 +02:00
|
|
|
qmakeVariable, input.projectDir, vPathsExact, &handled, result->directoriesWithWildcards);
|
2017-02-09 11:40:25 +01:00
|
|
|
exactSourceFiles[qmakeVariable] = sourceFiles;
|
2019-08-20 14:48:48 +02:00
|
|
|
extractSources(proToResult, &result->includedFiles.result, sourceFiles, type, false);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
2017-02-17 16:45:11 +01:00
|
|
|
const QStringList vPathsCumulative = fullVPaths(
|
2017-02-09 11:40:25 +01:00
|
|
|
baseVPathsCumulative, cumulativeReader, qmakeVariable, input.projectDir);
|
|
|
|
|
auto sourceFiles = cumulativeReader->absoluteFileValues(
|
2018-11-30 10:31:56 +02:00
|
|
|
qmakeVariable, input.projectDir, vPathsCumulative, &handled, result->directoriesWithWildcards);
|
2017-02-09 11:40:25 +01:00
|
|
|
cumulativeSourceFiles[qmakeVariable] = sourceFiles;
|
2019-08-20 14:48:48 +02:00
|
|
|
extractSources(proToResult, &result->includedFiles.result, sourceFiles, type, true);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This is used for two things:
|
|
|
|
|
// - Actual deployment, in which case we need exact values.
|
|
|
|
|
// - The project tree, in which case we also want exact values to avoid recursively
|
|
|
|
|
// watching bogus paths. However, we accept the values even if the evaluation
|
|
|
|
|
// failed, to at least have a best-effort result.
|
|
|
|
|
result->installsList = installsList(exactBuildPassReader, input.projectFilePath.toString(),
|
2017-02-15 12:53:30 +01:00
|
|
|
input.projectDir, input.buildDirectory.toString());
|
2017-02-09 11:40:25 +01:00
|
|
|
extractInstalls(proToResult, &result->includedFiles.result, result->installsList);
|
|
|
|
|
|
2017-02-09 23:39:57 +01:00
|
|
|
if (result->state == QmakeEvalResult::EvalOk) {
|
2017-02-09 11:40:25 +01:00
|
|
|
result->targetInformation = targetInformation(input.readerExact, exactBuildPassReader,
|
2017-02-15 12:53:30 +01:00
|
|
|
input.buildDirectory, input.projectFilePath);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
// update other variables
|
|
|
|
|
result->newVarValues[Variable::Defines] = exactReader->values(QLatin1String("DEFINES"));
|
|
|
|
|
result->newVarValues[Variable::IncludePath] = includePaths(exactReader, input.sysroot,
|
|
|
|
|
input.buildDirectory, input.projectDir);
|
|
|
|
|
result->newVarValues[Variable::CppFlags] = exactReader->values(QLatin1String("QMAKE_CXXFLAGS"));
|
2017-11-03 12:26:21 +01:00
|
|
|
result->newVarValues[Variable::CFlags] = exactReader->values(QLatin1String("QMAKE_CFLAGS"));
|
2019-01-04 09:07:55 +01:00
|
|
|
result->newVarValues[Variable::ExactSource] =
|
2017-02-09 11:40:25 +01:00
|
|
|
fileListForVar(exactSourceFiles, QLatin1String("SOURCES")) +
|
|
|
|
|
fileListForVar(exactSourceFiles, QLatin1String("HEADERS")) +
|
2019-01-04 09:07:55 +01:00
|
|
|
fileListForVar(exactSourceFiles, QLatin1String("OBJECTIVE_HEADERS"));
|
|
|
|
|
result->newVarValues[Variable::CumulativeSource] =
|
|
|
|
|
fileListForVar(cumulativeSourceFiles, QLatin1String("SOURCES")) +
|
2017-02-09 11:40:25 +01:00
|
|
|
fileListForVar(cumulativeSourceFiles, QLatin1String("HEADERS")) +
|
|
|
|
|
fileListForVar(cumulativeSourceFiles, QLatin1String("OBJECTIVE_HEADERS"));
|
|
|
|
|
result->newVarValues[Variable::UiDir] = QStringList() << uiDirPath(exactReader, input.buildDirectory);
|
|
|
|
|
result->newVarValues[Variable::HeaderExtension] = QStringList() << exactReader->value(QLatin1String("QMAKE_EXT_H"));
|
|
|
|
|
result->newVarValues[Variable::CppExtension] = QStringList() << exactReader->value(QLatin1String("QMAKE_EXT_CPP"));
|
|
|
|
|
result->newVarValues[Variable::MocDir] = QStringList() << mocDirPath(exactReader, input.buildDirectory);
|
|
|
|
|
result->newVarValues[Variable::ExactResource] = fileListForVar(exactSourceFiles, QLatin1String("RESOURCES"));
|
|
|
|
|
result->newVarValues[Variable::CumulativeResource] = fileListForVar(cumulativeSourceFiles, QLatin1String("RESOURCES"));
|
|
|
|
|
result->newVarValues[Variable::PkgConfig] = exactReader->values(QLatin1String("PKGCONFIG"));
|
|
|
|
|
result->newVarValues[Variable::PrecompiledHeader] = ProFileEvaluator::sourcesToFiles(exactReader->fixifiedValues(
|
2017-10-26 14:29:43 +02:00
|
|
|
QLatin1String("PRECOMPILED_HEADER"), input.projectDir, input.buildDirectory.toString(), false));
|
2017-02-09 11:40:25 +01:00
|
|
|
result->newVarValues[Variable::LibDirectories] = libDirectories(exactReader);
|
|
|
|
|
result->newVarValues[Variable::Config] = exactReader->values(QLatin1String("CONFIG"));
|
|
|
|
|
result->newVarValues[Variable::QmlImportPath] = exactReader->absolutePathValues(
|
|
|
|
|
QLatin1String("QML_IMPORT_PATH"), input.projectDir);
|
|
|
|
|
result->newVarValues[Variable::QmlDesignerImportPath] = exactReader->absolutePathValues(
|
|
|
|
|
QLatin1String("QML_DESIGNER_IMPORT_PATH"), input.projectDir);
|
|
|
|
|
result->newVarValues[Variable::Makefile] = exactReader->values(QLatin1String("MAKEFILE"));
|
|
|
|
|
result->newVarValues[Variable::Qt] = exactReader->values(QLatin1String("QT"));
|
|
|
|
|
result->newVarValues[Variable::ObjectExt] = exactReader->values(QLatin1String("QMAKE_EXT_OBJ"));
|
|
|
|
|
result->newVarValues[Variable::ObjectsDir] = exactReader->values(QLatin1String("OBJECTS_DIR"));
|
|
|
|
|
result->newVarValues[Variable::Version] = exactReader->values(QLatin1String("VERSION"));
|
|
|
|
|
result->newVarValues[Variable::TargetExt] = exactReader->values(QLatin1String("TARGET_EXT"));
|
|
|
|
|
result->newVarValues[Variable::TargetVersionExt]
|
|
|
|
|
= exactReader->values(QLatin1String("TARGET_VERSION_EXT"));
|
|
|
|
|
result->newVarValues[Variable::StaticLibExtension] = exactReader->values(QLatin1String("QMAKE_EXTENSION_STATICLIB"));
|
|
|
|
|
result->newVarValues[Variable::ShLibExtension] = exactReader->values(QLatin1String("QMAKE_EXTENSION_SHLIB"));
|
|
|
|
|
result->newVarValues[Variable::AndroidArch] = exactReader->values(QLatin1String("ANDROID_TARGET_ARCH"));
|
|
|
|
|
result->newVarValues[Variable::AndroidDeploySettingsFile] = exactReader->values(QLatin1String("ANDROID_DEPLOYMENT_SETTINGS_FILE"));
|
|
|
|
|
result->newVarValues[Variable::AndroidPackageSourceDir] = exactReader->values(QLatin1String("ANDROID_PACKAGE_SOURCE_DIR"));
|
|
|
|
|
result->newVarValues[Variable::AndroidExtraLibs] = exactReader->values(QLatin1String("ANDROID_EXTRA_LIBS"));
|
2019-11-14 15:02:47 +01:00
|
|
|
result->newVarValues[Variable::AppmanPackageDir] = exactReader->values(QLatin1String("AM_PACKAGE_DIR"));
|
|
|
|
|
result->newVarValues[Variable::AppmanManifest] = exactReader->values(QLatin1String("AM_MANIFEST"));
|
2017-02-09 11:40:25 +01:00
|
|
|
result->newVarValues[Variable::IsoIcons] = exactReader->values(QLatin1String("ISO_ICONS"));
|
|
|
|
|
result->newVarValues[Variable::QmakeProjectName] = exactReader->values(QLatin1String("QMAKE_PROJECT_NAME"));
|
|
|
|
|
result->newVarValues[Variable::QmakeCc] = exactReader->values("QMAKE_CC");
|
|
|
|
|
result->newVarValues[Variable::QmakeCxx] = exactReader->values("QMAKE_CXX");
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 23:39:57 +01:00
|
|
|
if (result->state == QmakeEvalResult::EvalOk || result->state == QmakeEvalResult::EvalPartial) {
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2017-02-22 15:09:35 +01:00
|
|
|
QList<QmakeIncludedPriFile *> toExtract = {&result->includedFiles};
|
2017-02-09 11:40:25 +01:00
|
|
|
while (!toExtract.isEmpty()) {
|
2017-02-09 23:39:57 +01:00
|
|
|
QmakeIncludedPriFile *current = toExtract.takeFirst();
|
2017-02-09 11:40:25 +01:00
|
|
|
processValues(current->result);
|
|
|
|
|
toExtract.append(current->children.values());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (exactBuildPassReader && exactBuildPassReader != input.readerExact)
|
|
|
|
|
delete exactBuildPassReader;
|
|
|
|
|
if (cumulativeBuildPassReader && cumulativeBuildPassReader != input.readerCumulative)
|
|
|
|
|
delete cumulativeBuildPassReader;
|
2017-02-09 23:39:57 +01:00
|
|
|
|
2020-01-31 15:52:20 +01:00
|
|
|
QList<QPair<QmakePriFile *, QmakeIncludedPriFile *>> toCompare;
|
|
|
|
|
toCompare.append(qMakePair(nullptr, &result->includedFiles));
|
|
|
|
|
while (!toCompare.isEmpty()) {
|
|
|
|
|
QmakePriFile *pn = toCompare.first().first;
|
|
|
|
|
QmakeIncludedPriFile *tree = toCompare.first().second;
|
|
|
|
|
toCompare.pop_front();
|
|
|
|
|
|
|
|
|
|
// Loop prevention: Make sure that exact same node is not in our parent chain
|
|
|
|
|
for (QmakeIncludedPriFile *priFile : tree->children) {
|
|
|
|
|
bool loop = input.parentFilePaths.contains(priFile->name);
|
|
|
|
|
for (const QmakePriFile *n = pn; n && !loop; n = n->parent()) {
|
|
|
|
|
if (n->filePath() == priFile->name)
|
|
|
|
|
loop = true;
|
|
|
|
|
}
|
|
|
|
|
if (loop)
|
|
|
|
|
continue; // Do nothing
|
|
|
|
|
|
|
|
|
|
if (priFile->proFile) {
|
|
|
|
|
auto *qmakePriFileNode = new QmakePriFile(priFile->name);
|
|
|
|
|
if (pn)
|
|
|
|
|
pn->addChild(qmakePriFileNode);
|
|
|
|
|
else
|
|
|
|
|
result->directChildren << qmakePriFileNode;
|
|
|
|
|
qmakePriFileNode->setIncludedInExactParse(input.includedInExcactParse
|
|
|
|
|
&& result->state == QmakeEvalResult::EvalOk);
|
|
|
|
|
result->priFiles.append(qMakePair(qmakePriFileNode, priFile->result));
|
|
|
|
|
toCompare.append(qMakePair(qmakePriFileNode, priFile));
|
|
|
|
|
} else {
|
|
|
|
|
auto *qmakeProFileNode = new QmakeProFile(priFile->name);
|
|
|
|
|
if (pn)
|
|
|
|
|
pn->addChild(qmakeProFileNode);
|
|
|
|
|
else
|
|
|
|
|
result->directChildren << qmakeProFileNode;
|
|
|
|
|
qmakeProFileNode->setIncludedInExactParse(input.includedInExcactParse
|
|
|
|
|
&& result->exactSubdirs.contains(qmakeProFileNode->filePath()));
|
|
|
|
|
qmakeProFileNode->setParseInProgress(true);
|
|
|
|
|
result->proFiles << qmakeProFileNode;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::asyncEvaluate(QFutureInterface<QmakeEvalResult *> &fi, QmakeEvalInput input)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QmakeEvalResult *evalResult = evaluate(input);
|
|
|
|
|
fi.reportResult(evalResult);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::applyAsyncEvaluate()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2020-01-31 15:52:20 +01:00
|
|
|
if (m_parseFutureWatcher->isFinished())
|
|
|
|
|
applyEvaluate(m_parseFutureWatcher->result());
|
2019-10-25 09:55:32 +02:00
|
|
|
m_buildSystem->decrementPendingEvaluateFutures();
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool sortByParserNodes(Node *a, Node *b)
|
|
|
|
|
{
|
|
|
|
|
return a->filePath() < b->filePath();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::applyEvaluate(QmakeEvalResult *evalResult)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QScopedPointer<QmakeEvalResult> result(evalResult);
|
|
|
|
|
if (!m_readerExact)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-10-25 09:55:32 +02:00
|
|
|
if (m_buildSystem->asyncUpdateState() == QmakeBuildSystem::ShuttingDown) {
|
2017-02-09 11:40:25 +01:00
|
|
|
cleanupProFileReaders();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (const QString &error, evalResult->errors)
|
2019-10-25 09:55:32 +02:00
|
|
|
QmakeBuildSystem::proFileParseError(error);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
// we are changing what is executed in that case
|
2019-10-25 09:55:32 +02:00
|
|
|
if (result->state == QmakeEvalResult::EvalFail || m_buildSystem->wasEvaluateCanceled()) {
|
2017-02-09 11:40:25 +01:00
|
|
|
m_validParse = false;
|
|
|
|
|
cleanupProFileReaders();
|
|
|
|
|
setValidParseRecursive(false);
|
|
|
|
|
setParseInProgressRecursive(false);
|
|
|
|
|
|
|
|
|
|
if (result->state == QmakeEvalResult::EvalFail) {
|
2019-10-25 09:55:32 +02:00
|
|
|
QmakeBuildSystem::proFileParseError(
|
|
|
|
|
QCoreApplication::translate("QmakeProFile", "Error while parsing file %1. Giving up.")
|
2017-02-09 15:35:19 +01:00
|
|
|
.arg(filePath().toUserOutput()));
|
2017-02-09 11:40:25 +01:00
|
|
|
if (m_projectType == ProjectType::Invalid)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
makeEmpty();
|
2017-02-10 09:56:33 +01:00
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
m_projectType = ProjectType::Invalid;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
qCDebug(qmakeParse()) << "QmakeProFile - updating files for file " << filePath();
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
if (result->projectType != m_projectType) {
|
|
|
|
|
// probably all subfiles/projects have changed anyway
|
|
|
|
|
// delete files && folders && projects
|
2017-02-10 09:56:33 +01:00
|
|
|
foreach (QmakePriFile *c, children()) {
|
|
|
|
|
if (auto qmakeProFile = dynamic_cast<QmakeProFile *>(c)) {
|
|
|
|
|
qmakeProFile->setValidParseRecursive(false);
|
|
|
|
|
qmakeProFile->setParseInProgressRecursive(false);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
makeEmpty();
|
|
|
|
|
m_projectType = result->projectType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// Add/Remove pri files, sub projects
|
|
|
|
|
//
|
2020-03-20 14:55:49 +01:00
|
|
|
FilePath buildDirectory = m_buildSystem->buildDir(m_filePath);
|
2017-02-09 11:40:25 +01:00
|
|
|
makeEmpty();
|
2020-01-31 15:52:20 +01:00
|
|
|
for (QmakePriFile * const toAdd : qAsConst(result->directChildren))
|
|
|
|
|
addChild(toAdd);
|
|
|
|
|
result->directChildren.clear();
|
2017-02-09 11:40:25 +01:00
|
|
|
|
2020-05-12 13:01:44 +02:00
|
|
|
for (const auto &priFiles : qAsConst(result->priFiles)) {
|
2020-01-31 15:52:20 +01:00
|
|
|
priFiles.first->finishInitialization(m_buildSystem, this);
|
|
|
|
|
priFiles.first->update(priFiles.second);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2020-01-31 15:52:20 +01:00
|
|
|
for (QmakeProFile * const proFile : qAsConst(result->proFiles)) {
|
|
|
|
|
proFile->finishInitialization(m_buildSystem, proFile);
|
|
|
|
|
proFile->setupFutureWatcher();
|
|
|
|
|
proFile->asyncUpdate();
|
|
|
|
|
}
|
2017-02-09 16:45:36 +01:00
|
|
|
QmakePriFile::update(result->includedFiles.result);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
m_validParse = (result->state == QmakeEvalResult::EvalOk);
|
|
|
|
|
if (m_validParse) {
|
|
|
|
|
// update TargetInformation
|
|
|
|
|
m_qmakeTargetInformation = result->targetInformation;
|
|
|
|
|
|
2017-02-14 14:54:00 +01:00
|
|
|
m_subProjectsNotToDeploy
|
|
|
|
|
= Utils::transform(result->subProjectsNotToDeploy,
|
2019-05-28 13:49:26 +02:00
|
|
|
[](const QString &s) { return FilePath::fromString(s); });
|
2017-02-09 11:40:25 +01:00
|
|
|
m_installsList = result->installsList;
|
|
|
|
|
|
|
|
|
|
if (m_varValues != result->newVarValues)
|
|
|
|
|
m_varValues = result->newVarValues;
|
|
|
|
|
|
2017-02-15 10:24:32 +01:00
|
|
|
m_displayName = singleVariableValue(Variable::QmakeProjectName);
|
2019-03-19 16:03:36 +01:00
|
|
|
m_featureRoots = m_readerExact->featureRoots();
|
2017-02-09 11:40:25 +01:00
|
|
|
} // result == EvalOk
|
|
|
|
|
|
2018-11-30 10:31:56 +02:00
|
|
|
if (!result->directoriesWithWildcards.isEmpty()) {
|
|
|
|
|
if (!m_wildcardWatcher) {
|
|
|
|
|
m_wildcardWatcher = std::make_unique<Utils::FileSystemWatcher>();
|
|
|
|
|
QObject::connect(
|
|
|
|
|
m_wildcardWatcher.get(), &Utils::FileSystemWatcher::directoryChanged,
|
2019-04-25 11:06:58 +03:00
|
|
|
[this](QString path) {
|
|
|
|
|
QStringList directoryContents = QDir(path).entryList();
|
|
|
|
|
if (m_wildcardDirectoryContents.value(path) != directoryContents) {
|
|
|
|
|
m_wildcardDirectoryContents.insert(path, directoryContents);
|
|
|
|
|
scheduleUpdate();
|
|
|
|
|
}
|
2018-11-30 10:31:56 +02:00
|
|
|
});
|
|
|
|
|
}
|
2019-04-25 11:06:58 +03:00
|
|
|
const QStringList directoriesToAdd = Utils::filtered<QStringList>(
|
2019-07-04 19:00:20 +02:00
|
|
|
Utils::toList(result->directoriesWithWildcards),
|
2019-04-25 11:06:58 +03:00
|
|
|
[this](const QString &path) {
|
|
|
|
|
return !m_wildcardWatcher->watchesDirectory(path);
|
|
|
|
|
});
|
|
|
|
|
for (QString path : directoriesToAdd)
|
|
|
|
|
m_wildcardDirectoryContents.insert(path, QDir(path).entryList());
|
|
|
|
|
m_wildcardWatcher->addDirectories(directoriesToAdd,
|
|
|
|
|
Utils::FileSystemWatcher::WatchModifiedDate);
|
2018-11-30 10:31:56 +02:00
|
|
|
}
|
|
|
|
|
if (m_wildcardWatcher) {
|
|
|
|
|
if (result->directoriesWithWildcards.isEmpty()) {
|
|
|
|
|
m_wildcardWatcher.reset();
|
2019-04-25 11:06:58 +03:00
|
|
|
m_wildcardDirectoryContents.clear();
|
2018-11-30 10:31:56 +02:00
|
|
|
} else {
|
2019-04-25 11:06:58 +03:00
|
|
|
const QStringList directoriesToRemove =
|
|
|
|
|
Utils::filtered<QStringList>(
|
|
|
|
|
m_wildcardWatcher->directories(),
|
2018-11-30 10:31:56 +02:00
|
|
|
[&result](const QString &path) {
|
|
|
|
|
return !result->directoriesWithWildcards.contains(path);
|
2019-04-25 11:06:58 +03:00
|
|
|
});
|
|
|
|
|
m_wildcardWatcher->removeDirectories(directoriesToRemove);
|
|
|
|
|
for (QString path : directoriesToRemove)
|
|
|
|
|
m_wildcardDirectoryContents.remove(path);
|
2018-11-30 10:31:56 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
setParseInProgress(false);
|
|
|
|
|
|
|
|
|
|
updateGeneratedFiles(buildDirectory);
|
|
|
|
|
|
|
|
|
|
cleanupProFileReaders();
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
void QmakeProFile::cleanupProFileReaders()
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-11-24 13:32:20 +01:00
|
|
|
if (m_readerExact)
|
2019-10-25 09:55:32 +02:00
|
|
|
m_buildSystem->destroyProFileReader(m_readerExact);
|
2017-11-24 13:32:20 +01:00
|
|
|
if (m_readerCumulative)
|
2019-10-25 09:55:32 +02:00
|
|
|
m_buildSystem->destroyProFileReader(m_readerCumulative);
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
m_readerExact = nullptr;
|
|
|
|
|
m_readerCumulative = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QString QmakeProFile::uiDirPath(QtSupport::ProFileReader *reader, const FilePath &buildDir)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QString path = reader->value(QLatin1String("UI_DIR"));
|
|
|
|
|
if (QFileInfo(path).isRelative())
|
2017-02-15 12:53:30 +01:00
|
|
|
path = QDir::cleanPath(buildDir.toString() + QLatin1Char('/') + path);
|
2017-02-09 11:40:25 +01:00
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QString QmakeProFile::mocDirPath(QtSupport::ProFileReader *reader, const FilePath &buildDir)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QString path = reader->value(QLatin1String("MOC_DIR"));
|
|
|
|
|
if (QFileInfo(path).isRelative())
|
2017-02-15 12:53:30 +01:00
|
|
|
path = QDir::cleanPath(buildDir.toString() + QLatin1Char('/') + path);
|
2017-02-09 11:40:25 +01:00
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QString QmakeProFile::sysrootify(const QString &path, const QString &sysroot,
|
2017-02-09 11:40:25 +01:00
|
|
|
const QString &baseDir, const QString &outputDir)
|
|
|
|
|
{
|
|
|
|
|
#ifdef Q_OS_WIN
|
|
|
|
|
Qt::CaseSensitivity cs = Qt::CaseInsensitive;
|
|
|
|
|
#else
|
|
|
|
|
Qt::CaseSensitivity cs = Qt::CaseSensitive;
|
|
|
|
|
#endif
|
|
|
|
|
if (sysroot.isEmpty() || path.startsWith(sysroot, cs)
|
|
|
|
|
|| path.startsWith(baseDir, cs) || path.startsWith(outputDir, cs)) {
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
QString sysrooted = QDir::cleanPath(sysroot + path);
|
|
|
|
|
return !IoUtils::exists(sysrooted) ? path : sysrooted;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
QStringList QmakeProFile::includePaths(QtSupport::ProFileReader *reader, const FilePath &sysroot,
|
|
|
|
|
const FilePath &buildDir, const QString &projectDir)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList paths;
|
2018-04-06 10:23:59 +02:00
|
|
|
bool nextIsAnIncludePath = false;
|
2017-02-09 11:40:25 +01:00
|
|
|
foreach (const QString &cxxflags, reader->values(QLatin1String("QMAKE_CXXFLAGS"))) {
|
2018-04-06 10:23:59 +02:00
|
|
|
if (nextIsAnIncludePath) {
|
|
|
|
|
nextIsAnIncludePath = false;
|
|
|
|
|
paths.append(cxxflags);
|
2018-04-10 21:00:49 +02:00
|
|
|
} else if (cxxflags.startsWith(QLatin1String("-I"))) {
|
|
|
|
|
paths.append(cxxflags.mid(2));
|
|
|
|
|
} else if (cxxflags.startsWith(QLatin1String("-isystem"))) {
|
|
|
|
|
nextIsAnIncludePath = true;
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-08-12 15:29:33 +02:00
|
|
|
bool tryUnfixified = false;
|
2017-02-09 11:40:25 +01:00
|
|
|
foreach (const ProFileEvaluator::SourceFile &el,
|
2017-10-26 14:29:43 +02:00
|
|
|
reader->fixifiedValues(QLatin1String("INCLUDEPATH"), projectDir, buildDir.toString(),
|
|
|
|
|
false)) {
|
2019-08-12 15:29:33 +02:00
|
|
|
const QString sysrootifiedPath = sysrootify(el.fileName, sysroot.toString(), projectDir,
|
|
|
|
|
buildDir.toString());
|
2019-08-14 12:56:57 +02:00
|
|
|
if (IoUtils::isAbsolutePath(sysrootifiedPath) && IoUtils::exists(sysrootifiedPath))
|
2019-08-12 15:29:33 +02:00
|
|
|
paths << sysrootifiedPath;
|
|
|
|
|
else
|
|
|
|
|
tryUnfixified = true;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
2019-08-12 15:29:33 +02:00
|
|
|
|
|
|
|
|
// If sysrootifying a fixified path does not yield a valid path, try again with the
|
|
|
|
|
// unfixified value. This can be necessary for cross-building; see QTCREATORBUG-21164.
|
|
|
|
|
if (tryUnfixified) {
|
|
|
|
|
const QStringList rawValues = reader->values("INCLUDEPATH");
|
|
|
|
|
for (const QString &p : rawValues) {
|
|
|
|
|
const QString sysrootifiedPath = sysrootify(QDir::cleanPath(p), sysroot.toString(),
|
|
|
|
|
projectDir, buildDir.toString());
|
2019-08-14 12:56:57 +02:00
|
|
|
if (IoUtils::isAbsolutePath(sysrootifiedPath) && IoUtils::exists(sysrootifiedPath))
|
2019-08-12 15:29:33 +02:00
|
|
|
paths << sysrootifiedPath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 11:40:25 +01:00
|
|
|
// paths already contains moc dir and ui dir, due to corrrectly parsing uic.prf and moc.prf
|
|
|
|
|
// except if those directories don't exist at the time of parsing
|
|
|
|
|
// thus we add those directories manually (without checking for existence)
|
|
|
|
|
paths << mocDirPath(reader, buildDir) << uiDirPath(reader, buildDir);
|
|
|
|
|
paths.removeDuplicates();
|
|
|
|
|
return paths;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QStringList QmakeProFile::libDirectories(QtSupport::ProFileReader *reader)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
QStringList result;
|
|
|
|
|
foreach (const QString &str, reader->values(QLatin1String("LIBS"))) {
|
|
|
|
|
if (str.startsWith(QLatin1String("-L")))
|
|
|
|
|
result.append(str.mid(2));
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-17 14:07:53 +01:00
|
|
|
FilePaths QmakeProFile::subDirsPaths(QtSupport::ProFileReader *reader,
|
2017-02-09 11:40:25 +01:00
|
|
|
const QString &projectDir,
|
|
|
|
|
QStringList *subProjectsNotToDeploy,
|
|
|
|
|
QStringList *errors)
|
|
|
|
|
{
|
2019-12-17 14:07:53 +01:00
|
|
|
FilePaths subProjectPaths;
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
const QStringList subDirVars = reader->values(QLatin1String("SUBDIRS"));
|
|
|
|
|
|
|
|
|
|
foreach (const QString &subDirVar, subDirVars) {
|
|
|
|
|
// Special case were subdir is just an identifier:
|
|
|
|
|
// "SUBDIR = subid
|
|
|
|
|
// subid.subdir = realdir"
|
|
|
|
|
// or
|
|
|
|
|
// "SUBDIR = subid
|
|
|
|
|
// subid.file = realdir/realfile.pro"
|
|
|
|
|
|
|
|
|
|
QString realDir;
|
|
|
|
|
const QString subDirKey = subDirVar + QLatin1String(".subdir");
|
|
|
|
|
const QString subDirFileKey = subDirVar + QLatin1String(".file");
|
|
|
|
|
if (reader->contains(subDirKey))
|
|
|
|
|
realDir = reader->value(subDirKey);
|
|
|
|
|
else if (reader->contains(subDirFileKey))
|
|
|
|
|
realDir = reader->value(subDirFileKey);
|
|
|
|
|
else
|
|
|
|
|
realDir = subDirVar;
|
|
|
|
|
QFileInfo info(realDir);
|
|
|
|
|
if (!info.isAbsolute())
|
|
|
|
|
info.setFile(projectDir + QLatin1Char('/') + realDir);
|
|
|
|
|
realDir = info.filePath();
|
|
|
|
|
|
|
|
|
|
QString realFile;
|
|
|
|
|
if (info.isDir())
|
|
|
|
|
realFile = QString::fromLatin1("%1/%2.pro").arg(realDir, info.fileName());
|
|
|
|
|
else
|
|
|
|
|
realFile = realDir;
|
|
|
|
|
|
|
|
|
|
if (QFile::exists(realFile)) {
|
|
|
|
|
realFile = QDir::cleanPath(realFile);
|
2019-05-28 13:49:26 +02:00
|
|
|
subProjectPaths << FilePath::fromString(realFile);
|
2017-02-09 11:40:25 +01:00
|
|
|
if (subProjectsNotToDeploy && !subProjectsNotToDeploy->contains(realFile)
|
|
|
|
|
&& reader->values(subDirVar + QLatin1String(".CONFIG"))
|
|
|
|
|
.contains(QLatin1String("no_default_target"))) {
|
|
|
|
|
subProjectsNotToDeploy->append(realFile);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (errors)
|
2017-02-09 16:45:36 +01:00
|
|
|
errors->append(QCoreApplication::translate("QmakeProFile", "Could not find .pro file for subdirectory \"%1\" in \"%2\".")
|
2017-02-09 11:40:25 +01:00
|
|
|
.arg(subDirVar).arg(realDir));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Utils::filteredUnique(subProjectPaths);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 13:44:13 +01:00
|
|
|
TargetInformation QmakeProFile::targetInformation(QtSupport::ProFileReader *reader,
|
|
|
|
|
QtSupport::ProFileReader *readerBuildPass,
|
2019-05-28 13:49:26 +02:00
|
|
|
const FilePath &buildDir,
|
|
|
|
|
const FilePath &projectFilePath)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-15 13:44:13 +01:00
|
|
|
TargetInformation result;
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!reader || !readerBuildPass)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
QStringList builds = reader->values(QLatin1String("BUILDS"));
|
|
|
|
|
if (!builds.isEmpty()) {
|
|
|
|
|
QString build = builds.first();
|
|
|
|
|
result.buildTarget = reader->value(build + QLatin1String(".target"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BUILD DIR
|
|
|
|
|
result.buildDir = buildDir;
|
|
|
|
|
|
|
|
|
|
if (readerBuildPass->contains(QLatin1String("DESTDIR")))
|
2019-05-28 13:49:26 +02:00
|
|
|
result.destDir = FilePath::fromString(readerBuildPass->value(QLatin1String("DESTDIR")));
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
// Target
|
|
|
|
|
result.target = readerBuildPass->value(QLatin1String("TARGET"));
|
|
|
|
|
if (result.target.isEmpty())
|
2017-02-15 12:53:30 +01:00
|
|
|
result.target = projectFilePath.toFileInfo().baseName();
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
result.valid = true;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 13:44:13 +01:00
|
|
|
TargetInformation QmakeProFile::targetInformation() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_qmakeTargetInformation;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 13:44:13 +01:00
|
|
|
InstallsList QmakeProFile::installsList(const QtSupport::ProFileReader *reader, const QString &projectFilePath,
|
|
|
|
|
const QString &projectDir, const QString &buildDir)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-15 13:44:13 +01:00
|
|
|
InstallsList result;
|
2017-02-09 11:40:25 +01:00
|
|
|
if (!reader)
|
|
|
|
|
return result;
|
|
|
|
|
const QStringList &itemList = reader->values(QLatin1String("INSTALLS"));
|
|
|
|
|
if (itemList.isEmpty())
|
|
|
|
|
return result;
|
|
|
|
|
|
2019-12-10 16:32:18 +01:00
|
|
|
const QStringList installPrefixVars{"QT_INSTALL_PREFIX", "QT_INSTALL_EXAMPLES"};
|
|
|
|
|
QList<QPair<QString, QString>> installPrefixValues;
|
|
|
|
|
for (const QString &installPrefix : installPrefixVars) {
|
|
|
|
|
installPrefixValues << qMakePair(reader->propertyValue(installPrefix),
|
|
|
|
|
reader->propertyValue(installPrefix + "/dev"));
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
|
|
|
|
|
foreach (const QString &item, itemList) {
|
2019-07-04 11:30:56 +02:00
|
|
|
const QStringList config = reader->values(item + ".CONFIG");
|
|
|
|
|
const bool active = !config.contains("no_default_install");
|
|
|
|
|
const bool executable = config.contains("executable");
|
2017-02-09 11:40:25 +01:00
|
|
|
const QString pathVar = item + QLatin1String(".path");
|
|
|
|
|
const QStringList &itemPaths = reader->values(pathVar);
|
|
|
|
|
if (itemPaths.count() != 1) {
|
|
|
|
|
qDebug("Invalid RHS: Variable '%s' has %d values.",
|
|
|
|
|
qPrintable(pathVar), itemPaths.count());
|
|
|
|
|
if (itemPaths.isEmpty()) {
|
|
|
|
|
qDebug("%s: Ignoring INSTALLS item '%s', because it has no path.",
|
|
|
|
|
qPrintable(projectFilePath), qPrintable(item));
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString itemPath = itemPaths.last();
|
2019-12-10 16:32:18 +01:00
|
|
|
for (const auto &prefixValuePair : qAsConst(installPrefixValues)) {
|
|
|
|
|
if (prefixValuePair.first == prefixValuePair.second
|
|
|
|
|
|| !itemPath.startsWith(prefixValuePair.first)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-02-09 11:40:25 +01:00
|
|
|
// This is a hack for projects which install into $$[QT_INSTALL_*],
|
|
|
|
|
// in particular Qt itself, examples being most relevant.
|
|
|
|
|
// Projects which implement their own install path policy must
|
|
|
|
|
// parametrize their INSTALLS themselves depending on the intended
|
|
|
|
|
// installation/deployment mode.
|
2019-12-10 16:32:18 +01:00
|
|
|
itemPath.replace(0, prefixValuePair.first.length(), prefixValuePair.second);
|
|
|
|
|
break;
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
if (item == QLatin1String("target")) {
|
|
|
|
|
if (active)
|
|
|
|
|
result.targetPath = itemPath;
|
|
|
|
|
} else {
|
|
|
|
|
const auto &itemFiles = reader->fixifiedValues(
|
2017-10-26 14:29:43 +02:00
|
|
|
item + QLatin1String(".files"), projectDir, buildDir, true);
|
2019-07-04 11:30:56 +02:00
|
|
|
result.items << InstallsItem(itemPath, itemFiles, active, executable);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-15 13:44:13 +01:00
|
|
|
InstallsList QmakeProFile::installsList() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_installsList;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath QmakeProFile::sourceDir() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
2017-02-15 12:53:30 +01:00
|
|
|
return directoryPath();
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-17 14:07:53 +01:00
|
|
|
FilePaths QmakeProFile::generatedFiles(const FilePath &buildDir,
|
2019-05-28 13:49:26 +02:00
|
|
|
const FilePath &sourceFile,
|
2017-02-10 11:16:18 +01:00
|
|
|
const FileType &sourceFileType) const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
// The mechanism for finding the file names is rather crude, but as we
|
|
|
|
|
// cannot parse QMAKE_EXTRA_COMPILERS and qmake has facilities to put
|
|
|
|
|
// ui_*.h files into a special directory, or even change the .h suffix, we
|
|
|
|
|
// cannot help doing this here.
|
2017-02-15 12:53:30 +01:00
|
|
|
|
2017-02-10 11:16:18 +01:00
|
|
|
if (sourceFileType == FileType::Form) {
|
2019-05-28 13:49:26 +02:00
|
|
|
FilePath location;
|
2017-02-09 11:40:25 +01:00
|
|
|
auto it = m_varValues.constFind(Variable::UiDir);
|
|
|
|
|
if (it != m_varValues.constEnd() && !it.value().isEmpty())
|
2019-05-28 13:49:26 +02:00
|
|
|
location = FilePath::fromString(it.value().front());
|
2017-02-09 11:40:25 +01:00
|
|
|
else
|
2017-02-15 12:53:30 +01:00
|
|
|
location = buildDir;
|
2017-02-09 11:40:25 +01:00
|
|
|
if (location.isEmpty())
|
2017-02-15 12:53:30 +01:00
|
|
|
return { };
|
2019-05-17 12:32:05 +02:00
|
|
|
location = location.pathAppended("ui_"
|
|
|
|
|
+ sourceFile.toFileInfo().completeBaseName()
|
|
|
|
|
+ singleVariableValue(Variable::HeaderExtension));
|
2019-05-28 13:49:26 +02:00
|
|
|
return { Utils::FilePath::fromString(QDir::cleanPath(location.toString())) };
|
2017-02-10 11:16:18 +01:00
|
|
|
} else if (sourceFileType == FileType::StateChart) {
|
2017-02-09 11:40:25 +01:00
|
|
|
if (buildDir.isEmpty())
|
2017-02-15 12:53:30 +01:00
|
|
|
return { };
|
2019-05-28 13:49:26 +02:00
|
|
|
const FilePath location = buildDir.pathAppended(sourceFile.toFileInfo().completeBaseName());
|
2019-05-15 08:01:06 +02:00
|
|
|
return {
|
|
|
|
|
location.stringAppended(singleVariableValue(Variable::HeaderExtension)),
|
|
|
|
|
location.stringAppended(singleVariableValue(Variable::CppExtension))
|
|
|
|
|
};
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
2017-02-15 12:53:30 +01:00
|
|
|
return { };
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|
|
|
|
|
|
2017-02-09 16:45:36 +01:00
|
|
|
QList<ExtraCompiler *> QmakeProFile::extraCompilers() const
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
return m_extraCompilers;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
void QmakeProFile::setupExtraCompiler(const FilePath &buildDir,
|
2017-02-10 11:16:18 +01:00
|
|
|
const FileType &fileType, ExtraCompilerFactory *factory)
|
|
|
|
|
{
|
2019-05-28 13:49:26 +02:00
|
|
|
for (const FilePath &fn : collectFiles(fileType)) {
|
2019-12-17 14:07:53 +01:00
|
|
|
const FilePaths generated = generatedFiles(buildDir, fn, fileType);
|
2019-05-06 16:46:03 +02:00
|
|
|
if (!generated.isEmpty())
|
2019-10-25 09:55:32 +02:00
|
|
|
m_extraCompilers.append(factory->create(m_buildSystem->project(), fn, generated));
|
2017-02-10 11:16:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
void QmakeProFile::updateGeneratedFiles(const FilePath &buildDir)
|
2017-02-09 11:40:25 +01:00
|
|
|
{
|
|
|
|
|
// We can do this because other plugins are not supposed to keep the compilers around.
|
|
|
|
|
qDeleteAll(m_extraCompilers);
|
|
|
|
|
m_extraCompilers.clear();
|
|
|
|
|
|
|
|
|
|
// Only those project types can have generated files for us
|
|
|
|
|
if (m_projectType != ProjectType::ApplicationTemplate
|
|
|
|
|
&& m_projectType != ProjectType::SharedLibraryTemplate
|
|
|
|
|
&& m_projectType != ProjectType::StaticLibraryTemplate) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-10 11:16:18 +01:00
|
|
|
const QList<ExtraCompilerFactory *> factories =
|
2017-02-09 11:40:25 +01:00
|
|
|
ProjectExplorer::ExtraCompilerFactory::extraCompilerFactories();
|
|
|
|
|
|
2017-02-10 11:16:18 +01:00
|
|
|
ExtraCompilerFactory *formFactory
|
|
|
|
|
= Utils::findOrDefault(factories, Utils::equal(&ExtraCompilerFactory::sourceType, FileType::Form));
|
|
|
|
|
if (formFactory)
|
|
|
|
|
setupExtraCompiler(buildDir, FileType::Form, formFactory);
|
|
|
|
|
ExtraCompilerFactory *scxmlFactory
|
|
|
|
|
= Utils::findOrDefault(factories, Utils::equal(&ExtraCompilerFactory::sourceType, FileType::StateChart));
|
|
|
|
|
if (scxmlFactory)
|
|
|
|
|
setupExtraCompiler(buildDir, FileType::StateChart, scxmlFactory);
|
2017-02-09 11:40:25 +01:00
|
|
|
}
|