1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of Qt Creator. 7 ** 8 ** Commercial License Usage 9 ** Licensees holding valid commercial Qt licenses may use this file in 10 ** accordance with the commercial license agreement provided with the 11 ** Software or, alternatively, in accordance with the terms contained in 12 ** a written agreement between you and The Qt Company. For licensing terms 13 ** and conditions see https://www.qt.io/terms-conditions. For further 14 ** information use the contact form at https://www.qt.io/contact-us. 15 ** 16 ** GNU General Public License Usage 17 ** Alternatively, this file may be used under the terms of the GNU 18 ** General Public License version 3 as published by the Free Software 19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT 20 ** included in the packaging of this file. Please review the following 21 ** information to ensure the GNU General Public License requirements will 22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html. 23 ** 24 ****************************************************************************/ 25 26 #pragma once 27 28 #include "qmakeprojectmanager_global.h" 29 #include "proparser/prowriter.h" 30 #include "proparser/profileevaluator.h" 31 32 #include <coreplugin/idocument.h> 33 #include <cpptools/generatedcodemodelsupport.h> 34 #include <utils/textfileformat.h> 35 36 #include <QFutureWatcher> 37 #include <QHash> 38 #include <QLoggingCategory> 39 #include <QMap> 40 #include <QPair> 41 #include <QStringList> 42 43 #include <memory> 44 45 namespace ProjectExplorer { class BuildConfiguration; } 46 47 namespace Utils { 48 class FilePath; 49 class FileSystemWatcher; 50 } // namespace Utils; 51 52 namespace QtSupport { class ProFileReader; } 53 54 namespace QmakeProjectManager { 55 class QmakeBuildSystem; 56 class QmakeProFile; 57 class QmakeProject; 58 59 // Type of projects 60 enum class ProjectType { 61 Invalid = 0, 62 ApplicationTemplate, 63 StaticLibraryTemplate, 64 SharedLibraryTemplate, 65 ScriptTemplate, 66 AuxTemplate, 67 SubDirsTemplate 68 }; 69 70 // Other variables of interest 71 enum class Variable { 72 Defines = 1, 73 IncludePath, 74 CppFlags, 75 CFlags, 76 ExactSource, 77 CumulativeSource, 78 ExactResource, 79 CumulativeResource, 80 UiDir, 81 HeaderExtension, 82 CppExtension, 83 MocDir, 84 PkgConfig, 85 PrecompiledHeader, 86 LibDirectories, 87 Config, 88 Qt, 89 QmlImportPath, 90 QmlDesignerImportPath, 91 Makefile, 92 ObjectExt, 93 ObjectsDir, 94 Version, 95 TargetExt, 96 TargetVersionExt, 97 StaticLibExtension, 98 ShLibExtension, 99 AndroidArch, 100 AndroidDeploySettingsFile, 101 AndroidAbis, 102 AndroidPackageSourceDir, 103 AndroidExtraLibs, 104 AndroidApplicationArguments, 105 AppmanPackageDir, 106 AppmanManifest, 107 IsoIcons, 108 QmakeProjectName, 109 QmakeCc, 110 QmakeCxx 111 }; 112 uint qHash(Variable key, uint seed = 0); 113 114 namespace Internal { 115 Q_DECLARE_LOGGING_CATEGORY(qmakeNodesLog) 116 class QmakeEvalInput; 117 class QmakeEvalResult; 118 class QmakePriFileEvalResult; 119 } // namespace Internal; 120 121 class InstallsList; 122 123 enum class FileOrigin { ExactParse, CumulativeParse }; 124 uint qHash(FileOrigin fo); 125 using SourceFile = QPair<Utils::FilePath, FileOrigin>; 126 using SourceFiles = QSet<SourceFile>; 127 128 // Implements ProjectNode for qmake .pri files 129 class QMAKEPROJECTMANAGER_EXPORT QmakePriFile 130 { 131 public: 132 QmakePriFile(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile, const Utils::FilePath &filePath); 133 explicit QmakePriFile(const Utils::FilePath &filePath); 134 virtual ~QmakePriFile(); 135 136 void finishInitialization(QmakeBuildSystem *buildSystem, QmakeProFile *qmakeProFile); 137 Utils::FilePath filePath() const; 138 Utils::FilePath directoryPath() const; 139 virtual QString displayName() const; 140 141 QmakePriFile *parent() const; 142 QmakeProject *project() const; 143 QVector<QmakePriFile *> children() const; 144 145 QmakePriFile *findPriFile(const Utils::FilePath &fileName); 146 const QmakePriFile *findPriFile(const Utils::FilePath &fileName) const; 147 148 bool knowsFile(const Utils::FilePath &filePath) const; 149 150 void makeEmpty(); 151 152 // Files of the specified type declared in this file. 153 SourceFiles files(const ProjectExplorer::FileType &type) const; 154 155 // Files of the specified type declared in this file and in included .pri files. 156 const QSet<Utils::FilePath> collectFiles(const ProjectExplorer::FileType &type) const; 157 158 void update(const Internal::QmakePriFileEvalResult &result); 159 160 bool canAddSubProject(const QString &proFilePath) const; 161 162 bool addSubProject(const QString &proFile); 163 bool removeSubProjects(const QString &proFilePath); 164 165 bool addFiles(const Utils::FilePaths &filePaths, Utils::FilePaths *notAdded = nullptr); 166 bool removeFiles(const Utils::FilePaths &filePaths, Utils::FilePaths *notRemoved = nullptr); 167 bool deleteFiles(const Utils::FilePaths &filePaths); 168 bool canRenameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath); 169 bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath); 170 bool addDependencies(const QStringList &dependencies); 171 172 bool setProVariable(const QString &var, const QStringList &values, 173 const QString &scope = QString(), 174 int flags = QmakeProjectManager::Internal::ProWriter::ReplaceValues); 175 176 bool folderChanged(const QString &changedFolder, const QSet<Utils::FilePath> &newFiles); 177 178 bool deploysFolder(const QString &folder) const; 179 180 QmakeProFile *proFile() const; 181 QVector<QmakePriFile *> subPriFilesExact() const; 182 183 // Set by parent 184 bool includedInExactParse() const; 185 186 static QSet<Utils::FilePath> recursiveEnumerate(const QString &folder); 187 188 void scheduleUpdate(); 189 190 QmakeBuildSystem *buildSystem() const; 191 192 protected: 193 void setIncludedInExactParse(bool b); 194 static QStringList varNames(ProjectExplorer::FileType type, QtSupport::ProFileReader *readerExact); 195 static QStringList varNamesForRemoving(); 196 static QString varNameForAdding(const QString &mimeType); 197 static QSet<Utils::FilePath> filterFilesProVariables(ProjectExplorer::FileType fileType, const QSet<Utils::FilePath> &files); 198 static QSet<Utils::FilePath> filterFilesRecursiveEnumerata(ProjectExplorer::FileType fileType, const QSet<Utils::FilePath> &files); 199 200 enum ChangeType { 201 AddToProFile, 202 RemoveFromProFile 203 }; 204 205 enum class Change { Save, TestOnly }; 206 bool renameFile(const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath, Change mode); 207 void changeFiles(const QString &mimeType, 208 const Utils::FilePaths &filePaths, 209 Utils::FilePaths *notChanged, 210 ChangeType change, 211 Change mode = Change::Save); 212 213 void addChild(QmakePriFile *pf); 214 215 private: 216 void setParent(QmakePriFile *p); 217 218 bool prepareForChange(); 219 static bool ensureWriteableProFile(const QString &file); 220 QPair<ProFile *, QStringList> readProFile(); 221 static QPair<ProFile *, QStringList> readProFileFromContents(const QString &contents); 222 void save(const QStringList &lines); 223 bool saveModifiedEditors(); 224 Utils::FilePaths formResources(const Utils::FilePath &formFile) const; 225 static QStringList baseVPaths(QtSupport::ProFileReader *reader, const QString &projectDir, const QString &buildDir); 226 static QStringList fullVPaths(const QStringList &baseVPaths, QtSupport::ProFileReader *reader, const QString &qmakeVariable, const QString &projectDir); 227 static void extractSources(QHash<int, Internal::QmakePriFileEvalResult *> proToResult, 228 Internal::QmakePriFileEvalResult *fallback, 229 QVector<ProFileEvaluator::SourceFile> sourceFiles, ProjectExplorer::FileType type, bool cumulative); 230 static void extractInstalls( 231 QHash<int, Internal::QmakePriFileEvalResult *> proToResult, 232 Internal::QmakePriFileEvalResult *fallback, 233 const InstallsList &installList); 234 static void processValues(Internal::QmakePriFileEvalResult &result); 235 void watchFolders(const QSet<Utils::FilePath> &folders); 236 237 QString continuationIndent() const; 238 239 QPointer<QmakeBuildSystem> m_buildSystem; 240 QmakeProFile *m_qmakeProFile = nullptr; 241 QmakePriFile *m_parent = nullptr; 242 QVector<QmakePriFile *> m_children; 243 244 Utils::TextFileFormat m_textFormat; 245 246 // Memory is cheap... 247 QMap<ProjectExplorer::FileType, SourceFiles> m_files; 248 QSet<Utils::FilePath> m_recursiveEnumerateFiles; // FIXME: Remove this?! 249 QSet<QString> m_watchedFolders; 250 const Utils::FilePath m_filePath; 251 bool m_includedInExactParse = true; 252 253 friend class QmakeProFile; 254 }; 255 256 class QMAKEPROJECTMANAGER_EXPORT TargetInformation 257 { 258 public: 259 bool valid = false; 260 QString target; 261 Utils::FilePath destDir; 262 Utils::FilePath buildDir; 263 QString buildTarget; 264 bool operator==(const TargetInformation &other) const 265 { 266 return target == other.target 267 && valid == other.valid 268 && destDir == other.destDir 269 && buildDir == other.buildDir 270 && buildTarget == other.buildTarget; 271 } 272 bool operator!=(const TargetInformation &other) const 273 { 274 return !(*this == other); 275 } 276 277 TargetInformation() = default; 278 TargetInformation(const TargetInformation &other) = default; 279 }; 280 281 class QMAKEPROJECTMANAGER_EXPORT InstallsItem { 282 public: 283 InstallsItem() = default; InstallsItem(QString p,QVector<ProFileEvaluator::SourceFile> f,bool a,bool e)284 InstallsItem(QString p, QVector<ProFileEvaluator::SourceFile> f, bool a, bool e) 285 : path(p), files(f), active(a), executable(e) {} 286 QString path; 287 QVector<ProFileEvaluator::SourceFile> files; 288 bool active = false; 289 bool executable = false; 290 }; 291 292 class QMAKEPROJECTMANAGER_EXPORT InstallsList { 293 public: clear()294 void clear() { targetPath.clear(); items.clear(); } 295 QString targetPath; 296 QVector<InstallsItem> items; 297 }; 298 299 // Implements ProjectNode for qmake .pro files 300 class QMAKEPROJECTMANAGER_EXPORT QmakeProFile : public QmakePriFile 301 { 302 public: 303 QmakeProFile(QmakeBuildSystem *buildSystem, const Utils::FilePath &filePath); 304 explicit QmakeProFile(const Utils::FilePath &filePath); 305 ~QmakeProFile() override; 306 307 void setupFutureWatcher(); 308 309 bool isParent(QmakeProFile *node); 310 QString displayName() const final; 311 312 QList<QmakeProFile *> allProFiles(); 313 QmakeProFile *findProFile(const Utils::FilePath &fileName); 314 const QmakeProFile *findProFile(const Utils::FilePath &fileName) const; 315 316 ProjectType projectType() const; 317 318 QStringList variableValue(const Variable var) const; 319 QString singleVariableValue(const Variable var) const; 320 isSubProjectDeployable(const Utils::FilePath & filePath)321 bool isSubProjectDeployable(const Utils::FilePath &filePath) const { 322 return !m_subProjectsNotToDeploy.contains(filePath); 323 } 324 325 Utils::FilePath sourceDir() const; 326 327 Utils::FilePaths generatedFiles(const Utils::FilePath &buildDirectory, 328 const Utils::FilePath &sourceFile, 329 const ProjectExplorer::FileType &sourceFileType) const; 330 QList<ProjectExplorer::ExtraCompiler *> extraCompilers() const; 331 332 TargetInformation targetInformation() const; 333 InstallsList installsList() const; featureRoots()334 const QStringList featureRoots() const { return m_featureRoots; } 335 336 QByteArray cxxDefines() const; 337 338 enum AsyncUpdateDelay { ParseNow, ParseLater }; 339 using QmakePriFile::scheduleUpdate; 340 void scheduleUpdate(AsyncUpdateDelay delay); 341 342 bool validParse() const; 343 bool parseInProgress() const; 344 345 void setParseInProgressRecursive(bool b); 346 347 void asyncUpdate(); 348 349 bool isFileFromWildcard(const QString &filePath) const; 350 351 private: 352 void setParseInProgress(bool b); 353 void setValidParseRecursive(bool b); 354 355 void applyAsyncEvaluate(bool apply); 356 357 void setupReader(); 358 Internal::QmakeEvalInput evalInput() const; 359 360 static Internal::QmakeEvalResult *evaluate(const Internal::QmakeEvalInput &input); 361 void applyEvaluate(Internal::QmakeEvalResult *parseResult); 362 363 void asyncEvaluate(QFutureInterface<Internal::QmakeEvalResult *> &fi, Internal::QmakeEvalInput input); 364 void cleanupProFileReaders(); 365 366 void updateGeneratedFiles(const Utils::FilePath &buildDir); 367 368 static QString uiDirPath(QtSupport::ProFileReader *reader, const Utils::FilePath &buildDir); 369 static QString mocDirPath(QtSupport::ProFileReader *reader, const Utils::FilePath &buildDir); 370 static QString sysrootify(const QString &path, const QString &sysroot, const QString &baseDir, const QString &outputDir); 371 static QStringList includePaths(QtSupport::ProFileReader *reader, const Utils::FilePath &sysroot, const Utils::FilePath &buildDir, const QString &projectDir); 372 static QStringList libDirectories(QtSupport::ProFileReader *reader); 373 static Utils::FilePaths subDirsPaths(QtSupport::ProFileReader *reader, const QString &projectDir, QStringList *subProjectsNotToDeploy, QStringList *errors); 374 375 static TargetInformation targetInformation(QtSupport::ProFileReader *reader, QtSupport::ProFileReader *readerBuildPass, const Utils::FilePath &buildDir, const Utils::FilePath &projectFilePath); 376 static InstallsList installsList(const QtSupport::ProFileReader *reader, const QString &projectFilePath, const QString &projectDir, const QString &buildDir); 377 378 void setupExtraCompiler(const Utils::FilePath &buildDir, 379 const ProjectExplorer::FileType &fileType, 380 ProjectExplorer::ExtraCompilerFactory *factory); 381 382 bool m_validParse = false; 383 bool m_parseInProgress = false; 384 385 QString m_displayName; 386 ProjectType m_projectType = ProjectType::Invalid; 387 388 using VariablesHash = QHash<Variable, QStringList>; 389 VariablesHash m_varValues; 390 391 QList<ProjectExplorer::ExtraCompiler *> m_extraCompilers; 392 393 TargetInformation m_qmakeTargetInformation; 394 Utils::FilePaths m_subProjectsNotToDeploy; 395 InstallsList m_installsList; 396 QStringList m_featureRoots; 397 398 std::unique_ptr<Utils::FileSystemWatcher> m_wildcardWatcher; 399 QMap<QString, QStringList> m_wildcardDirectoryContents; 400 401 // Async stuff 402 QFutureWatcher<Internal::QmakeEvalResult *> *m_parseFutureWatcher = nullptr; 403 QtSupport::ProFileReader *m_readerExact = nullptr; 404 QtSupport::ProFileReader *m_readerCumulative = nullptr; 405 }; 406 407 } // namespace QmakeProjectManager 408