diff --git a/src/plugins/autotoolsprojectmanager/CMakeLists.txt b/src/plugins/autotoolsprojectmanager/CMakeLists.txt index 83bdeaf6ccb..f78daac7e07 100644 --- a/src/plugins/autotoolsprojectmanager/CMakeLists.txt +++ b/src/plugins/autotoolsprojectmanager/CMakeLists.txt @@ -11,6 +11,5 @@ add_qtc_plugin(AutotoolsProjectManager autotoolsprojectplugin.cpp configurestep.cpp configurestep.h makefileparser.cpp makefileparser.h - makefileparserthread.cpp makefileparserthread.h makestep.cpp makestep.h ) diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp index bbe5bd32d25..38624986d8e 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.cpp @@ -3,7 +3,7 @@ #include "autotoolsbuildsystem.h" -#include "makefileparserthread.h" +#include "makefileparser.h" #include #include @@ -12,10 +12,11 @@ #include -#include +#include #include using namespace ProjectExplorer; +using namespace Tasking; using namespace Utils; namespace AutotoolsProjectManager::Internal { @@ -28,28 +29,35 @@ AutotoolsBuildSystem::AutotoolsBuildSystem(Target *target) connect(target->project(), &Project::projectFileIsDirty, this, [this] { requestParse(); }); } -AutotoolsBuildSystem::~AutotoolsBuildSystem() -{ - delete m_cppCodeModelUpdater; +AutotoolsBuildSystem::~AutotoolsBuildSystem() = default; - if (m_makefileParserThread) - m_makefileParserThread->wait(); +static void parseMakefile(QPromise &promise, const QString &makefile) +{ + MakefileParser parser(makefile); + if (parser.parse()) + promise.addResult(parser.outputData()); + else + promise.future().cancel(); } void AutotoolsBuildSystem::triggerParsing() { - // The thread is still busy parsing a previous configuration. - // Wait until the thread has been finished and delete it. - // TODO: Discuss whether blocking is acceptable. - if (m_makefileParserThread) - m_makefileParserThread->wait(); + const Storage> storage; - // Parse the makefile asynchronously in a thread - m_makefileParserThread.reset(new MakefileParserThread(this)); + const auto onSetup = [this, storage](Async &async) { + *storage = guardParsingRun(); + async.setConcurrentCallData(parseMakefile, projectFilePath().toString()); + }; + const auto onDone = [this, storage](const Async &async) { + (*storage)->markAsSuccess(); + makefileParsingFinished(async.result()); + }; - connect(m_makefileParserThread.get(), &MakefileParserThread::done, - this, &AutotoolsBuildSystem::makefileParsingFinished); - m_makefileParserThread->start(); + const Group recipe { + storage, + AsyncTask(onSetup, onDone, CallDoneIf::Success) + }; + m_parserRunner.start(recipe); } static QStringList filterIncludes(const QString &absSrc, const QString &absBuild, @@ -69,37 +77,28 @@ static QStringList filterIncludes(const QString &absSrc, const QString &absBuild return result; } -void AutotoolsBuildSystem::makefileParsingFinished() +void AutotoolsBuildSystem::makefileParsingFinished(const MakefileParserOutputData &outputData) { - // The parsing has been cancelled by the user. Don't show any project data at all. - if (m_makefileParserThread->isCanceled()) { - m_makefileParserThread.release()->deleteLater(); - return; - } - - if (m_makefileParserThread->hasError()) - qWarning("Parsing of makefile contained errors."); - m_files.clear(); - QSet filesToWatch; + QSet filesToWatch; // Apply sources to m_files, which are returned at AutotoolsBuildSystem::files() const QFileInfo fileInfo = projectFilePath().toFileInfo(); const QDir dir = fileInfo.absoluteDir(); - const QStringList files = m_makefileParserThread->sources(); + const QStringList files = outputData.m_sources; for (const QString& file : files) m_files.append(dir.absoluteFilePath(file)); // Watch for changes of Makefile.am files. If a Makefile.am file // has been changed, the project tree must be reparsed. - const QStringList makefiles = m_makefileParserThread->makefiles(); + const QStringList makefiles = outputData.m_makefiles; for (const QString &makefile : makefiles) { const QString absMakefile = dir.absoluteFilePath(makefile); m_files.append(absMakefile); - filesToWatch.insert(Utils::FilePath::fromString(absMakefile)); + filesToWatch.insert(FilePath::fromString(absMakefile)); } // Add configure.ac file to project and watch for changes. @@ -109,12 +108,12 @@ void AutotoolsBuildSystem::makefileParsingFinished() const QString absConfigureAc = dir.absoluteFilePath(configureAc); m_files.append(absConfigureAc); - filesToWatch.insert(Utils::FilePath::fromString(absConfigureAc)); + filesToWatch.insert(FilePath::fromString(absConfigureAc)); } auto newRoot = std::make_unique(project()->projectDirectory()); for (const QString &f : std::as_const(m_files)) { - const Utils::FilePath path = Utils::FilePath::fromString(f); + const FilePath path = FilePath::fromString(f); newRoot->addNestedNode(std::make_unique(path, FileNode::fileTypeForFileName(path))); } @@ -128,8 +127,8 @@ void AutotoolsBuildSystem::makefileParsingFinished() rpp.setDisplayName(project()->displayName()); rpp.setProjectFileLocation(projectFilePath().toString()); rpp.setQtVersion(kitInfo.projectPartQtVersion); - const QStringList cflags = m_makefileParserThread->cflags(); - QStringList cxxflags = m_makefileParserThread->cxxflags(); + const QStringList cflags = outputData.m_cflags; + QStringList cxxflags = outputData.m_cxxflags; if (cxxflags.isEmpty()) cxxflags = cflags; @@ -142,15 +141,12 @@ void AutotoolsBuildSystem::makefileParsingFinished() const QString absBuild = bc ? bc->buildDirectory().toString() : QString(); - rpp.setIncludePaths(filterIncludes(absSrc, absBuild, m_makefileParserThread->includePaths())); - rpp.setMacros(m_makefileParserThread->macros()); + rpp.setIncludePaths(filterIncludes(absSrc, absBuild, outputData.m_includePaths)); + rpp.setMacros(outputData.m_macros); rpp.setFiles(m_files); m_cppCodeModelUpdater->update({project(), kitInfo, activeParseEnvironment(), {rpp}}); - m_makefileParserThread.release()->deleteLater(); - - emitBuildSystemUpdated(); -} + emitBuildSystemUpdated();} } // AutotoolsProjectManager::Internal diff --git a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h index 04f04263ff3..cb286690f00 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h +++ b/src/plugins/autotoolsprojectmanager/autotoolsbuildsystem.h @@ -5,13 +5,13 @@ #include -#include +#include namespace ProjectExplorer { class ProjectUpdater; } namespace AutotoolsProjectManager::Internal { -class MakefileParserThread; +class MakefileParserOutputData; class AutotoolsBuildSystem final : public ProjectExplorer::BuildSystem { @@ -29,15 +29,15 @@ private: * takes care listen to file changes for Makefile.am and configure.ac * files. */ - void makefileParsingFinished(); + void makefileParsingFinished(const MakefileParserOutputData &outputData); /// Return value for AutotoolsProject::files() QStringList m_files; /// Responsible for parsing the makefiles asynchronously in a thread - std::unique_ptr m_makefileParserThread; + Tasking::TaskTreeRunner m_parserRunner; - ProjectExplorer::ProjectUpdater *m_cppCodeModelUpdater = nullptr; + std::unique_ptr m_cppCodeModelUpdater; }; } // AutotoolsProjectManager::Internal diff --git a/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.qbs b/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.qbs index 960a718c310..cefd8722c21 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.qbs +++ b/src/plugins/autotoolsprojectmanager/autotoolsprojectmanager.qbs @@ -26,8 +26,6 @@ QtcPlugin { "configurestep.h", "makefileparser.cpp", "makefileparser.h", - "makefileparserthread.cpp", - "makefileparserthread.h", "makestep.cpp", "makestep.h", ] diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp b/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp deleted file mode 100644 index 0dc8c12b57d..00000000000 --- a/src/plugins/autotoolsprojectmanager/makefileparserthread.cpp +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright (C) 2016 Openismus GmbH. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "makefileparserthread.h" - -#include - -namespace AutotoolsProjectManager::Internal { - -MakefileParserThread::MakefileParserThread(ProjectExplorer::BuildSystem *bs) - : m_parser(bs->projectFilePath().toString()), - m_guard(bs->guardParsingRun()) -{ - connect(this, &QThread::finished, this, &MakefileParserThread::done, Qt::QueuedConnection); -} - -QStringList MakefileParserThread::sources() const -{ - QMutexLocker locker(&m_mutex); - return m_sources; -} - -QStringList MakefileParserThread::makefiles() const -{ - QMutexLocker locker(&m_mutex); - return m_makefiles; -} - -QString MakefileParserThread::executable() const -{ - QMutexLocker locker(&m_mutex); - return m_executable; -} - -QStringList MakefileParserThread::includePaths() const -{ - QMutexLocker locker(&m_mutex); - return m_includePaths; -} - -ProjectExplorer::Macros MakefileParserThread::macros() const -{ - QMutexLocker locker(&m_mutex); - return m_macros; -} - -QStringList MakefileParserThread::cflags() const -{ - QMutexLocker locker(&m_mutex); - return m_cflags; -} - -QStringList MakefileParserThread::cxxflags() const -{ - QMutexLocker locker(&m_mutex); - return m_cxxflags; -} - -bool MakefileParserThread::hasError() const -{ - QMutexLocker locker(&m_mutex); - return !m_guard.isSuccess(); -} - -bool MakefileParserThread::isCanceled() const -{ - // MakefileParser::isCanceled() is thread-safe - return m_parser.isCanceled(); -} - -void MakefileParserThread::cancel() -{ - m_parser.cancel(); -} - -void MakefileParserThread::run() -{ - const bool success = m_parser.parse(); - - // Important: Start locking the mutex _after_ the parsing has been finished, as - // this prevents long locks if the caller reads a value before the signal - // finished() has been emitted. - QMutexLocker locker(&m_mutex); - if (success) - m_guard.markAsSuccess(); - m_executable = m_parser.executable(); - m_sources = m_parser.sources(); - m_makefiles = m_parser.makefiles(); - m_includePaths = m_parser.includePaths(); - m_macros = m_parser.macros(); - m_cflags = m_parser.cflags(); - m_cxxflags = m_parser.cxxflags(); -} - -} // AutotoolsProjectManager::Internal diff --git a/src/plugins/autotoolsprojectmanager/makefileparserthread.h b/src/plugins/autotoolsprojectmanager/makefileparserthread.h deleted file mode 100644 index d87e6e48a83..00000000000 --- a/src/plugins/autotoolsprojectmanager/makefileparserthread.h +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2016 Openismus GmbH. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include "makefileparser.h" - -#include -#include - -#include -#include -#include -#include - -namespace AutotoolsProjectManager::Internal { - -/** - * @brief Executes the makefile parser in the thread. - * - * After the finished() signal has been emitted, the makefile - * parser output can be read by sources(), makefiles() and executable(). - * A parsing error can be checked by hasError(). - */ -class MakefileParserThread : public QThread -{ - Q_OBJECT - - using Macros = ProjectExplorer::Macros; - -public: - explicit MakefileParserThread(ProjectExplorer::BuildSystem *bs); - - /** @see QThread::run() */ - void run() override; - - /** - * @return List of sources that are set for the _SOURCES target. - * Sources in sub directorties contain the sub directory as - * prefix. Should be invoked, after the signal finished() - * has been emitted. - */ - QStringList sources() const; - - /** - * @return List of Makefile.am files from the current directory and - * all sub directories. The values for sub directories contain - * the sub directory as prefix. Should be invoked, after the - * signal finished() has been emitted. - */ - QStringList makefiles() const; - - /** - * @return File name of the executable. Should be invoked, after the - * signal finished() has been emitted. - */ - QString executable() const; - - /** - * @return List of include paths. Should be invoked, after the signal - * finished() has been emitted. - */ - QStringList includePaths() const; - - /** - * @return Concatenated macros. Should be invoked, after the signal - * finished() has been emitted. - */ - Macros macros() const; - - /** - * @return List of compiler flags for C. Should be invoked, after the signal - * finished() has been emitted. - */ - QStringList cflags() const; - - /** - * @return List of compiler flags for C++. Should be invoked, after the - * signal finished() has been emitted. - */ - QStringList cxxflags() const; - - /** - * @return True, if an error occurred during the parsing. Should be invoked, - * after the signal finished() has been emitted. - */ - bool hasError() const; - - /** - * @return True, if the parsing has been cancelled by MakefileParserThread::cancel(). - */ - bool isCanceled() const; - - /** - * Cancels the parsing of the makefile. MakefileParser::hasError() will - * return true in this case. - */ - void cancel(); - -signals: - /** - * Similar to finished, but emitted from MakefileParserThread thread, i.e. from the - * thread where the MakefileParserThread lives in, not the tread that it creates. - * This helps to avoid race condition when connecting to finished() signal. - */ - void done(); - -private: - MakefileParser m_parser; ///< Is not accessible outside the thread - - mutable QMutex m_mutex; - QString m_executable; ///< Return value for MakefileParserThread::executable() - QStringList m_sources; ///< Return value for MakefileParserThread::sources() - QStringList m_makefiles; ///< Return value for MakefileParserThread::makefiles() - QStringList m_includePaths; ///< Return value for MakefileParserThread::includePaths() - Macros m_macros; ///< Return value for MakefileParserThread::macros() - QStringList m_cflags; ///< Return value for MakefileParserThread::cflags() - QStringList m_cxxflags; ///< Return value for MakefileParserThread::cxxflags() - - ProjectExplorer::BuildSystem::ParseGuard m_guard; -}; - -} // AutotoolsProjectManager::Internal