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 
58 QT_BEGIN_NAMESPACE
59 
60 class QMakeGlobals;
61 
62 class QMAKE_EXPORT QMakeHandler : public QMakeParserHandler
63 {
64 public:
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 
84 typedef QPair<QString, QString> QMakeFeatureKey; // key, parent
85 typedef QHash<QMakeFeatureKey, QString> QMakeFeatureHash;
86 
87 class QMAKE_EXPORT QMakeFeatureRoots : public QSharedData
88 {
89 public:
QMakeFeatureRoots(const QStringList & _paths)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.
100 class QMAKE_EXPORT ProValueMapStack : public std::list<ProValueMap>
101 {
102 public:
push(const ProValueMap & t)103     inline void push(const ProValueMap &t) { push_back(t); }
pop()104     inline ProValueMap pop() { auto r = std::move(back()); pop_back(); return r; }
top()105     ProValueMap &top() { return back(); }
top()106     const ProValueMap &top() const { return back(); }
107 };
108 
109 namespace QMakeInternal { struct QMakeBuiltin; }
110 
111 class QMAKE_EXPORT QMakeEvaluator
112 {
113 public:
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 
setExtraVars(const ProValueMap & extraVars)130     void setExtraVars(const ProValueMap &extraVars) { m_extraVars = extraVars; }
setExtraConfigs(const ProStringList & extraConfigs)131     void setExtraConfigs(const ProStringList &extraConfigs) { m_extraConfigs = extraConfigs; }
setOutputDir(const QString & outputDir)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 
dirSep()139     ProString dirSep() const { return m_dirSep; }
isHostBuild()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 
returnBool(bool b)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 
map(const ProString & var)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(const QStringRef &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;
resolvePath(const QString & fileName)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;
evalError(const QString & msg)205     void evalError(const QString &msg) const
206             { message(QMakeHandler::EvalError, msg); }
languageWarning(const QString & msg)207     void languageWarning(const QString &msg) const
208             { message(QMakeHandler::EvalWarnLanguage, msg); }
deprecationWarning(const QString & 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(const QStringRef &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(const QStringRef &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 
254 private:
255     // Implementation detail of evaluateBuiltinConditional():
256     VisitReturn testFunc_cache(const ProStringList &args);
257 
258 public:
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
debugMsgInternal(int,const char *,...)279     ALWAYS_INLINE void debugMsgInternal(int, const char *, ...) const {}
traceMsgInternal(const char *,...)280     ALWAYS_INLINE void traceMsgInternal(const char *, ...) const {}
281 
282     enum { m_debugLevel = 0 };
283 #endif
284 
285     struct Location {
LocationLocation286         Location() : pro(nullptr), line(0) {}
LocationLocation287         Location(ProFile *_pro, ushort _line) : pro(_pro), line(_line) {}
clearLocation288         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 };
328 Q_DECLARE_TYPEINFO(QMakeEvaluator::Location, Q_PRIMITIVE_TYPE);
329 
330 Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags)
331 
332 QT_END_NAMESPACE
333 
334 #endif // QMAKEEVALUATOR_H
335