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