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