1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#ifndef QMAKEEVALUATOR_H
5#define QMAKEEVALUATOR_H
6
7#if defined(PROEVALUATOR_FULL) && defined(PROEVALUATOR_THREAD_SAFE)
8# error PROEVALUATOR_FULL is incompatible with PROEVALUATOR_THREAD_SAFE due to cache() implementation
9#endif
10
11#include "qmakeparser.h"
12#include "qmakevfs.h"
13#include "ioutils.h"
14
15#include <qlist.h>
16#include <qmap.h>
17#include <qset.h>
18#include <qstack.h>
19#include <qstring.h>
20#include <qstringlist.h>
21#include <qshareddata.h>
22#if QT_CONFIG(process)
23# include <qprocess.h>
24#else
25# include <qiodevice.h>
26#endif
27#ifdef PROEVALUATOR_THREAD_SAFE
28# include <qmutex.h>
29#endif
30
31#include <list>
32
33QT_BEGIN_NAMESPACE
34
35class QMakeGlobals;
36
37class QMAKE_EXPORT QMakeHandler : public QMakeParserHandler
38{
39public:
40 enum {
41 SourceEvaluator = 0x10,
42
43 CumulativeEvalMessage = 0x1000,
44
45 EvalWarnLanguage = SourceEvaluator | WarningMessage | WarnLanguage,
46 EvalWarnDeprecated = SourceEvaluator | WarningMessage | WarnDeprecated,
47
48 EvalError = ErrorMessage | SourceEvaluator
49 };
50
51 // error(), warning() and message() from .pro file
52 virtual void fileMessage(int type, const QString &msg) = 0;
53
54 enum EvalFileType { EvalProjectFile, EvalIncludeFile, EvalConfigFile, EvalFeatureFile, EvalAuxFile };
55 virtual void aboutToEval(ProFile *parent, ProFile *proFile, EvalFileType type) = 0;
56 virtual void doneWithEval(ProFile *parent) = 0;
57};
58
59typedef QPair<QString, QString> QMakeFeatureKey; // key, parent
60typedef QHash<QMakeFeatureKey, QString> QMakeFeatureHash;
61
62class QMAKE_EXPORT QMakeFeatureRoots : public QSharedData
63{
64public:
65 QMakeFeatureRoots(const QStringList &_paths) : paths(_paths) {}
66 const QStringList paths;
67 mutable QMakeFeatureHash cache;
68#ifdef PROEVALUATOR_THREAD_SAFE
69 mutable QMutex mutex;
70#endif
71};
72
73// We use a list-based stack instead of a vector-based one, so that
74// the addresses of value maps stay constant. The qmake generators rely on that.
75class QMAKE_EXPORT ProValueMapStack : public std::list<ProValueMap>
76{
77public:
78 inline void push(const ProValueMap &t) { push_back(x: t); }
79 inline ProValueMap pop() { auto r = std::move(back()); pop_back(); return r; }
80 ProValueMap &top() { return back(); }
81 const ProValueMap &top() const { return back(); }
82};
83
84namespace QMakeInternal { struct QMakeBuiltin; }
85
86class QMAKE_EXPORT QMakeEvaluator
87{
88public:
89 enum LoadFlag {
90 LoadProOnly = 0,
91 LoadPreFiles = 1,
92 LoadPostFiles = 2,
93 LoadAll = LoadPreFiles|LoadPostFiles,
94 LoadSilent = 0x10,
95 LoadHidden = 0x20
96 };
97 Q_DECLARE_FLAGS(LoadFlags, LoadFlag)
98
99 static void initStatics();
100 static void initFunctionStatics();
101 QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
102 QMakeHandler *handler);
103 ~QMakeEvaluator();
104
105 void setExtraVars(const ProValueMap &extraVars) { m_extraVars = extraVars; }
106 void setExtraConfigs(const ProStringList &extraConfigs) { m_extraConfigs = extraConfigs; }
107 void setOutputDir(const QString &outputDir) { m_outputDir = outputDir; }
108
109 ProStringList values(const ProKey &variableName) const;
110 ProStringList &valuesRef(const ProKey &variableName);
111 ProString first(const ProKey &variableName) const;
112 ProString propertyValue(const ProKey &val) const;
113
114 ProString dirSep() const { return m_dirSep; }
115 bool isHostBuild() const { return m_hostBuild; }
116
117 enum VisitReturn {
118 ReturnFalse,
119 ReturnTrue,
120 ReturnError,
121 ReturnBreak,
122 ReturnNext,
123 ReturnReturn
124 };
125
126 static ALWAYS_INLINE VisitReturn returnBool(bool b)
127 { return b ? ReturnTrue : ReturnFalse; }
128
129 static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
130 VisitReturn evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
131 static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
132 static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
133 void skipExpression(const ushort *&tokPtr);
134
135 void loadDefaults();
136 bool prepareProject(const QString &inDir);
137 bool loadSpecInternal();
138 bool loadSpec();
139 void initFrom(const QMakeEvaluator *other);
140 void setupProject();
141 void evaluateCommand(const QString &cmds, const QString &where);
142 void applyExtraConfigs();
143 VisitReturn visitProFile(ProFile *pro, QMakeHandler::EvalFileType type,
144 LoadFlags flags);
145 VisitReturn visitProBlock(ProFile *pro, const ushort *tokPtr);
146 VisitReturn visitProBlock(const ushort *tokPtr);
147 VisitReturn visitProLoop(const ProKey &variable, const ushort *exprPtr,
148 const ushort *tokPtr);
149 void visitProFunctionDef(ushort tok, const ProKey &name, const ushort *tokPtr);
150 VisitReturn visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
151
152 ALWAYS_INLINE const ProKey &map(const ProString &var) { return map(var: var.toKey()); }
153 const ProKey &map(const ProKey &var);
154 ProValueMap *findValues(const ProKey &variableName, ProValueMap::Iterator *it);
155
156 void setTemplate();
157
158 ProStringList split_value_list(QStringView vals, int source = 0);
159 VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined);
160
161 QString currentFileName() const;
162 QString currentDirectory() const;
163 ProFile *currentProFile() const;
164 int currentFileId() const;
165 QString resolvePath(const QString &fileName) const
166 { return QMakeInternal::IoUtils::resolvePath(baseDir: currentDirectory(), fileName); }
167 QString filePathArg0(const ProStringList &args);
168 QString filePathEnvArg0(const ProStringList &args);
169
170 VisitReturn evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type,
171 LoadFlags flags);
172 VisitReturn evaluateFileChecked(const QString &fileName, QMakeHandler::EvalFileType type,
173 LoadFlags flags);
174 VisitReturn evaluateFeatureFile(const QString &fileName, bool silent = false);
175 VisitReturn evaluateFileInto(const QString &fileName,
176 ProValueMap *values, // output-only
177 LoadFlags flags);
178 VisitReturn evaluateConfigFeatures();
179 void message(int type, const QString &msg) const;
180 void evalError(const QString &msg) const
181 { message(type: QMakeHandler::EvalError, msg); }
182 void languageWarning(const QString &msg) const
183 { message(type: QMakeHandler::EvalWarnLanguage, msg); }
184 void deprecationWarning(const QString &msg) const
185 { message(type: QMakeHandler::EvalWarnDeprecated, msg); }
186
187 VisitReturn prepareFunctionArgs(const ushort *&tokPtr, QList<ProStringList> *ret);
188 VisitReturn evaluateFunction(const ProFunctionDef &func,
189 const QList<ProStringList> &argumentsList, ProStringList *ret);
190 VisitReturn evaluateBoolFunction(const ProFunctionDef &func,
191 const QList<ProStringList> &argumentsList,
192 const ProString &function);
193
194 VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret);
195 VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
196
197 VisitReturn evaluateBuiltinExpand(const QMakeInternal::QMakeBuiltin &adef,
198 const ProKey &function, const ProStringList &args, ProStringList &ret);
199 VisitReturn evaluateBuiltinConditional(const QMakeInternal::QMakeBuiltin &adef,
200 const ProKey &function, const ProStringList &args);
201
202 VisitReturn evaluateConditional(QStringView cond, const QString &where, int line = -1);
203#ifdef PROEVALUATOR_FULL
204 VisitReturn checkRequirements(const ProStringList &deps);
205#endif
206
207 void updateMkspecPaths();
208 void updateFeaturePaths();
209
210 bool isActiveConfig(QStringView config, bool regex = false);
211
212 void populateDeps(
213 const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes,
214 const ProString &priosfx,
215 QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
216 QMultiMap<int, ProString> &rootSet) const;
217
218 bool getMemberArgs(const ProKey &name, int srclen, const ProStringList &args,
219 int *start, int *end);
220 VisitReturn parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value);
221
222 VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
223 QMakeVfs::VfsFlags flags, const QString &contents);
224#if QT_CONFIG(process)
225 void runProcess(QProcess *proc, const QString &command) const;
226#endif
227 QByteArray getCommandOutput(const QString &args, int *exitCode) const;
228
229private:
230 // Implementation detail of evaluateBuiltinConditional():
231 VisitReturn testFunc_cache(const ProStringList &args);
232
233public:
234 QMakeEvaluator *m_caller;
235#ifdef PROEVALUATOR_CUMULATIVE
236 bool m_cumulative;
237 int m_skipLevel;
238#else
239 enum { m_cumulative = 0 };
240 enum { m_skipLevel = 0 };
241#endif
242
243 static QString quoteValue(const ProString &val);
244
245#ifdef PROEVALUATOR_DEBUG
246 void debugMsgInternal(int level, const char *fmt, ...) const;
247 void traceMsgInternal(const char *fmt, ...) const;
248 static QString formatValue(const ProString &val, bool forceQuote = false);
249 static QString formatValueList(const ProStringList &vals, bool commas = false);
250 static QString formatValueListList(const QList<ProStringList> &vals);
251
252 const int m_debugLevel;
253#else
254 ALWAYS_INLINE void debugMsgInternal(int, const char *, ...) const {}
255 ALWAYS_INLINE void traceMsgInternal(const char *, ...) const {}
256
257 enum { m_debugLevel = 0 };
258#endif
259
260 struct Location {
261 Location() : pro(nullptr), line(0) {}
262 Location(ProFile *_pro, ushort _line) : pro(_pro), line(_line) {}
263 void clear() { pro = nullptr; line = 0; }
264 ProFile *pro;
265 ushort line;
266 };
267
268 Location m_current; // Currently evaluated location
269 QStack<Location> m_locationStack; // All execution location changes
270 QStack<ProFile *> m_profileStack; // Includes only
271
272 ProValueMap m_extraVars;
273 ProStringList m_extraConfigs;
274 QString m_outputDir;
275
276 int m_listCount;
277 int m_toggle;
278 bool m_valuemapInited;
279 bool m_hostBuild;
280 QString m_qmakespec;
281 QString m_qmakespecName;
282 QString m_superfile;
283 QString m_conffile;
284 QString m_cachefile;
285 QString m_stashfile;
286 QString m_sourceRoot;
287 QString m_buildRoot;
288 QStringList m_qmakepath;
289 QStringList m_qmakefeatures;
290 QStringList m_mkspecPaths;
291 QExplicitlySharedDataPointer<QMakeFeatureRoots> m_featureRoots;
292 ProString m_dirSep;
293 ProFunctionDefs m_functionDefs;
294 ProStringList m_returnValue;
295 ProValueMapStack m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.
296 QString m_tmp1, m_tmp2, m_tmp3, m_tmp[2]; // Temporaries for efficient toQString
297
298 QMakeGlobals *m_option;
299 QMakeParser *m_parser;
300 QMakeHandler *m_handler;
301 QMakeVfs *m_vfs;
302};
303Q_DECLARE_TYPEINFO(QMakeEvaluator::Location, Q_PRIMITIVE_TYPE);
304
305Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags)
306
307QT_END_NAMESPACE
308
309#endif // QMAKEEVALUATOR_H
310

source code of qtbase/qmake/library/qmakeevaluator.h