Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qmakeglobals.cpp
Go to the documentation of this file.
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#include "qmakeglobals.h"
5
7#include "ioutils.h"
8
9#include <qbytearray.h>
10#include <qdatetime.h>
11#include <qdebug.h>
12#include <qdir.h>
13#include <qfile.h>
14#include <qfileinfo.h>
15#include <qlist.h>
16#include <qset.h>
17#include <qstack.h>
18#include <qstring.h>
19#include <qstringlist.h>
20#include <qtextstream.h>
21#ifdef PROEVALUATOR_THREAD_SAFE
22# include <qthreadpool.h>
23#endif
24
25#ifdef Q_OS_UNIX
26#include <unistd.h>
27#include <sys/utsname.h>
28#else
29#include <qt_windows.h>
30#endif
31#include <stdio.h>
32#include <stdlib.h>
33
34#ifdef Q_OS_WIN32
35#define QT_POPEN _popen
36#define QT_POPEN_READ "rb"
37#define QT_PCLOSE _pclose
38#else
39#define QT_POPEN popen
40#define QT_POPEN_READ "r"
41#define QT_PCLOSE pclose
42#endif
43
45using namespace QMakeInternal; // for IoUtils
46
47#define fL1S(s) QString::fromLatin1(s)
48
50{
51 do_cache = true;
52
53#ifdef PROEVALUATOR_DEBUG
54 debugLevel = 0;
55#endif
56#ifdef Q_OS_WIN
57 dirlist_sep = QLatin1Char(';');
58 dir_sep = QLatin1Char('\\');
59#else
60 dirlist_sep = QLatin1Char(':');
61 dir_sep = QLatin1Char('/');
62#endif
63}
64
66{
67 qDeleteAll(baseEnvs);
68}
69
70QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &spec)
71{
72 QString ret = QDir::cleanPath(spec);
73 if (ret.contains(QLatin1Char('/'))) {
74 QString absRet = IoUtils::resolvePath(state.pwd, ret);
75 if (QFile::exists(absRet))
76 ret = absRet;
77 }
78 return ret;
79}
80
81/*
82 * Return value meanings:
83 * ArgumentUnknown The argument at *pos was not handled by this function.
84 * Leave it to the caller to handle this argument.
85 * ArgumentMalformed There was an error detected.
86 * ArgumentsOk All arguments were known. There are no arguments left to handle.
87 */
89 QMakeCmdLineParserState &state, QStringList &args, int *pos)
90{
91 enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache, ArgQtConf } argState = ArgNone;
92 for (; *pos < args.size(); (*pos)++) {
93 QString arg = args.at(*pos);
94 switch (argState) {
95 case ArgConfig:
96 state.configs[state.phase] << arg;
97 break;
98 case ArgSpec:
99 qmakespec = args[*pos] = cleanSpec(state, arg);
100 break;
101 case ArgXSpec:
102 xqmakespec = args[*pos] = cleanSpec(state, arg);
103 break;
104 case ArgTmpl:
105 user_template = arg;
106 break;
107 case ArgTmplPfx:
108 user_template_prefix = arg;
109 break;
110 case ArgCache:
111 cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg);
112 break;
113 case ArgQtConf:
114 qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg);
115 break;
116 default:
117 if (arg.startsWith(QLatin1Char('-'))) {
118 if (arg == QLatin1String("--")) {
119 state.extraargs = args.mid(*pos + 1);
120 args.erase(args.begin() + *pos, args.end());
121 return ArgumentsOk;
122 }
123 if (arg == QLatin1String("-early"))
124 state.phase = QMakeEvalEarly;
125 else if (arg == QLatin1String("-before"))
126 state.phase = QMakeEvalBefore;
127 else if (arg == QLatin1String("-after"))
128 state.phase = QMakeEvalAfter;
129 else if (arg == QLatin1String("-late"))
130 state.phase = QMakeEvalLate;
131 else if (arg == QLatin1String("-config"))
132 argState = ArgConfig;
133 else if (arg == QLatin1String("-nocache"))
134 do_cache = false;
135 else if (arg == QLatin1String("-cache"))
136 argState = ArgCache;
137 else if (arg == QLatin1String("-qtconf"))
138 argState = ArgQtConf;
139 else if (arg == QLatin1String("-platform") || arg == QLatin1String("-spec"))
140 argState = ArgSpec;
141 else if (arg == QLatin1String("-xplatform") || arg == QLatin1String("-xspec"))
142 argState = ArgXSpec;
143 else if (arg == QLatin1String("-template") || arg == QLatin1String("-t"))
144 argState = ArgTmpl;
145 else if (arg == QLatin1String("-template_prefix") || arg == QLatin1String("-tp"))
146 argState = ArgTmplPfx;
147 else if (arg == QLatin1String("-win32"))
148 dir_sep = QLatin1Char('\\');
149 else if (arg == QLatin1String("-unix"))
150 dir_sep = QLatin1Char('/');
151 else
152 return ArgumentUnknown;
153 } else if (arg.contains(QLatin1Char('='))) {
154 state.cmds[state.phase] << arg;
155 } else {
156 return ArgumentUnknown;
157 }
158 continue;
159 }
160 argState = ArgNone;
161 }
162 if (argState != ArgNone)
163 return ArgumentMalformed;
164 return ArgumentsOk;
165}
166
168{
169 if (!state.extraargs.isEmpty()) {
170 QString extra = fL1S("QMAKE_EXTRA_ARGS =");
171 for (const QString &ea : std::as_const(state.extraargs))
172 extra += QLatin1Char(' ') + QMakeEvaluator::quoteValue(ProString(ea));
173 state.cmds[QMakeEvalBefore] << extra;
174 }
175 for (int p = 0; p < 4; p++) {
176 if (!state.configs[p].isEmpty())
177 state.cmds[p] << (fL1S("CONFIG += ") + state.configs[p].join(QLatin1Char(' ')));
178 extra_cmds[p] = state.cmds[p].join(QLatin1Char('\n'));
179 }
180
181 if (xqmakespec.isEmpty())
182 xqmakespec = qmakespec;
183}
184
186{
187 if (xqmakespec.isEmpty())
188 xqmakespec = getEnv(QLatin1String("XQMAKESPEC"));
189 if (qmakespec.isEmpty()) {
190 qmakespec = getEnv(QLatin1String("QMAKESPEC"));
191 if (xqmakespec.isEmpty())
192 xqmakespec = qmakespec;
193 }
194}
195
196void QMakeGlobals::setCommandLineArguments(const QString &pwd, const QStringList &_args)
197{
198 QStringList args = _args;
199
201 for (int pos = 0; pos < args.size(); pos++)
202 addCommandLineArguments(state, args, &pos);
205}
206
207void QMakeGlobals::setDirectories(const QString &input_dir, const QString &output_dir)
208{
209 if (input_dir != output_dir && !output_dir.isEmpty()) {
210 QString srcpath = input_dir;
211 if (!srcpath.endsWith(QLatin1Char('/')))
212 srcpath += QLatin1Char('/');
213 QString dstpath = output_dir;
214 if (!dstpath.endsWith(QLatin1Char('/')))
215 dstpath += QLatin1Char('/');
216 int srcLen = srcpath.size();
217 int dstLen = dstpath.size();
218 int lastSl = -1;
219 while (++lastSl, --srcLen, --dstLen,
220 srcLen && dstLen && srcpath.at(srcLen) == dstpath.at(dstLen))
221 if (srcpath.at(srcLen) == QLatin1Char('/'))
222 lastSl = 0;
223 source_root = srcpath.left(srcLen + lastSl);
224 build_root = dstpath.left(dstLen + lastSl);
225 }
226}
227
228QString QMakeGlobals::shadowedPath(const QString &fileName) const
229{
230 if (source_root.isEmpty())
231 return fileName;
232 if (fileName.startsWith(source_root)
233 && (fileName.size() == source_root.size()
234 || fileName.at(source_root.size()) == QLatin1Char('/'))) {
235 return build_root + fileName.mid(source_root.size());
236 }
237 return QString();
238}
239
240QStringList QMakeGlobals::splitPathList(const QString &val) const
241{
242 QStringList ret;
243 if (!val.isEmpty()) {
244 QString cwd(QDir::currentPath());
245 const QStringList vals = val.split(dirlist_sep, Qt::SkipEmptyParts);
246 ret.reserve(vals.size());
247 for (const QString &it : vals)
248 ret << IoUtils::resolvePath(cwd, it);
249 }
250 return ret;
251}
252
253QString QMakeGlobals::getEnv(const QString &var) const
254{
255#ifdef PROEVALUATOR_SETENV
256 return environment.value(var);
257#else
258 return QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData()));
259#endif
260}
261
262QStringList QMakeGlobals::getPathListEnv(const QString &var) const
263{
264 return splitPathList(getEnv(var));
265}
266
267QString QMakeGlobals::expandEnvVars(const QString &str) const
268{
269 QString string = str;
270 int startIndex = 0;
271 forever {
272 startIndex = string.indexOf(QLatin1Char('$'), startIndex);
273 if (startIndex < 0)
274 break;
275 if (string.size() < startIndex + 3)
276 break;
277 if (string.at(startIndex + 1) != QLatin1Char('(')) {
278 startIndex++;
279 continue;
280 }
281 int endIndex = string.indexOf(QLatin1Char(')'), startIndex + 2);
282 if (endIndex < 0)
283 break;
284 QString value = getEnv(string.mid(startIndex + 2, endIndex - startIndex - 2));
285 string.replace(startIndex, endIndex - startIndex + 1, value);
286 startIndex += value.size();
287 }
288 return string;
289}
290
291#ifndef QT_BUILD_QMAKE
292#ifdef PROEVALUATOR_INIT_PROPS
293bool QMakeGlobals::initProperties()
294{
295 QByteArray data;
296#if QT_CONFIG(process)
297 QProcess proc;
298 proc.start(qmake_abslocation, QStringList() << QLatin1String("-query"));
299 if (!proc.waitForFinished())
300 return false;
301 data = proc.readAll();
302#else
303 if (FILE *proc = QT_POPEN(QString(IoUtils::shellQuote(qmake_abslocation)
304 + QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) {
305 char buff[1024];
306 while (!feof(proc))
307 data.append(buff, int(fread(buff, 1, 1023, proc)));
308 QT_PCLOSE(proc);
309 }
310#endif
311 parseProperties(data, properties);
312 return true;
313}
314#endif
315
316void QMakeGlobals::parseProperties(const QByteArray &data, QHash<ProKey, ProString> &properties)
317{
318 const auto lines = data.split('\n');
319 for (QByteArray line : lines) {
320 int off = line.indexOf(':');
321 if (off < 0) // huh?
322 continue;
323 if (line.endsWith('\r'))
324 line.chop(1);
325 QString name = QString::fromLatin1(line.left(off));
326 ProString value = ProString(QDir::fromNativeSeparators(
327 QString::fromLocal8Bit(line.mid(off + 1))));
328 if (value.isNull())
329 value = ProString(""); // Make sure it is not null, to discern from missing keys
330 properties.insert(ProKey(name), value);
331 if (name.startsWith(QLatin1String("QT_"))) {
332 enum { PropPut, PropRaw, PropGet } variant;
333 if (name.contains(QLatin1Char('/'))) {
334 if (name.endsWith(QLatin1String("/raw")))
335 variant = PropRaw;
336 else if (name.endsWith(QLatin1String("/get")))
337 variant = PropGet;
338 else // Nothing falls back on /src or /dev.
339 continue;
340 name.chop(4);
341 } else {
342 variant = PropPut;
343 }
344 if (name.startsWith(QLatin1String("QT_INSTALL_"))) {
345 if (variant < PropRaw) {
346 if (name == QLatin1String("QT_INSTALL_PREFIX")
347 || name == QLatin1String("QT_INSTALL_DATA")
348 || name == QLatin1String("QT_INSTALL_LIBS")
349 || name == QLatin1String("QT_INSTALL_BINS")) {
350 // Qt4 fallback
351 QString hname = name;
352 hname.replace(3, 7, QLatin1String("HOST"));
353 properties.insert(ProKey(hname), value);
354 properties.insert(ProKey(hname + QLatin1String("/get")), value);
355 properties.insert(ProKey(hname + QLatin1String("/src")), value);
356 }
357 properties.insert(ProKey(name + QLatin1String("/raw")), value);
358 }
359 if (variant <= PropRaw)
360 properties.insert(ProKey(name + QLatin1String("/dev")), value);
361 } else if (!name.startsWith(QLatin1String("QT_HOST_"))) {
362 continue;
363 }
364 if (variant != PropRaw) {
365 if (variant < PropGet)
366 properties.insert(ProKey(name + QLatin1String("/get")), value);
367 properties.insert(ProKey(name + QLatin1String("/src")), value);
368 }
369 }
370 }
371}
372#endif // QT_BUILD_QMAKE
373
374QT_END_NAMESPACE
\inmodule QtCore
Definition qhash.h:821
QMakeCmdLineParserState(const QString &_pwd)
void useEnvironment()
QStringList splitPathList(const QString &value) const
void setCommandLineArguments(const QString &pwd, const QStringList &args)
void setDirectories(const QString &input_dir, const QString &output_dir)
QString expandEnvVars(const QString &str) const
void commitCommandLineArguments(QMakeCmdLineParserState &state)
ArgumentReturn addCommandLineArguments(QMakeCmdLineParserState &state, QStringList &args, int *pos)
QString shadowedPath(const QString &fileName) const
#define fL1S(s)
Definition ioutils.cpp:21
Combined button and popup list for selecting options.
@ QMakeEvalBefore
@ QMakeEvalLate
@ QMakeEvalEarly
@ QMakeEvalAfter