PageRenderTime 57ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/linguist/shared/qmakeglobals.cpp

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