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