/src/linguist/shared/qmakeglobals.cpp
C++ | 392 lines | 338 code | 26 blank | 28 comment | 124 complexity | e3f67f5a3aecc248c7b93f331ff04cff MD5 | raw file
- /****************************************************************************
- **
- ** Copyright (C) 2016 The Qt Company Ltd.
- ** Contact: https://www.qt.io/licensing/
- **
- ** This file is part of the Qt Linguist of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:GPL-EXCEPT$
- ** Commercial License Usage
- ** Licensees holding valid commercial Qt licenses may use this file in
- ** accordance with the commercial license agreement provided with the
- ** Software or, alternatively, in accordance with the terms contained in
- ** a written agreement between you and The Qt Company. For licensing terms
- ** and conditions see https://www.qt.io/terms-conditions. For further
- ** information use the contact form at https://www.qt.io/contact-us.
- **
- ** GNU General Public License Usage
- ** Alternatively, this file may be used under the terms of the GNU
- ** General Public License version 3 as published by the Free Software
- ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
- ** included in the packaging of this file. Please review the following
- ** information to ensure the GNU General Public License requirements will
- ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
- **
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
- #include "qmakeglobals.h"
- #include "qmakeevaluator.h"
- #include "ioutils.h"
- #include <qbytearray.h>
- #include <qdatetime.h>
- #include <qdebug.h>
- #include <qdir.h>
- #include <qfile.h>
- #include <qfileinfo.h>
- #include <qlist.h>
- #include <qset.h>
- #include <qstack.h>
- #include <qstring.h>
- #include <qstringlist.h>
- #include <qtextstream.h>
- #ifdef PROEVALUATOR_THREAD_SAFE
- # include <qthreadpool.h>
- #endif
- #ifdef Q_OS_UNIX
- #include <unistd.h>
- #include <sys/utsname.h>
- #else
- #include <windows.h>
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #ifdef Q_OS_WIN32
- #define QT_POPEN _popen
- #define QT_POPEN_READ "rb"
- #define QT_PCLOSE _pclose
- #else
- #define QT_POPEN popen
- #define QT_POPEN_READ "r"
- #define QT_PCLOSE pclose
- #endif
- QT_BEGIN_NAMESPACE
- using namespace QMakeInternal; // for IoUtils
- #define fL1S(s) QString::fromLatin1(s)
- QMakeGlobals::QMakeGlobals()
- {
- do_cache = true;
- #ifdef PROEVALUATOR_DEBUG
- debugLevel = 0;
- #endif
- #ifdef Q_OS_WIN
- dirlist_sep = QLatin1Char(';');
- dir_sep = QLatin1Char('\\');
- #else
- dirlist_sep = QLatin1Char(':');
- dir_sep = QLatin1Char('/');
- #endif
- }
- QMakeGlobals::~QMakeGlobals()
- {
- qDeleteAll(baseEnvs);
- }
- QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &spec)
- {
- QString ret = QDir::cleanPath(spec);
- if (ret.contains(QLatin1Char('/'))) {
- QString absRet = IoUtils::resolvePath(state.pwd, ret);
- if (QFile::exists(absRet))
- ret = absRet;
- }
- return ret;
- }
- QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
- QMakeCmdLineParserState &state, QStringList &args, int *pos)
- {
- enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache, ArgQtConf } argState = ArgNone;
- for (; *pos < args.count(); (*pos)++) {
- QString arg = args.at(*pos);
- switch (argState) {
- case ArgConfig:
- state.configs[state.phase] << arg;
- break;
- case ArgSpec:
- qmakespec = args[*pos] = cleanSpec(state, arg);
- break;
- case ArgXSpec:
- xqmakespec = args[*pos] = cleanSpec(state, arg);
- break;
- case ArgTmpl:
- user_template = arg;
- break;
- case ArgTmplPfx:
- user_template_prefix = arg;
- break;
- case ArgCache:
- cachefile = args[*pos] = IoUtils::resolvePath(state.pwd, arg);
- break;
- case ArgQtConf:
- qtconf = args[*pos] = IoUtils::resolvePath(state.pwd, arg);
- break;
- default:
- if (arg.startsWith(QLatin1Char('-'))) {
- if (arg == QLatin1String("--")) {
- state.extraargs = args.mid(*pos + 1);
- args.erase(args.begin() + *pos, args.end());
- return ArgumentsOk;
- }
- if (arg == QLatin1String("-early"))
- state.phase = QMakeEvalEarly;
- else if (arg == QLatin1String("-before"))
- state.phase = QMakeEvalBefore;
- else if (arg == QLatin1String("-after"))
- state.phase = QMakeEvalAfter;
- else if (arg == QLatin1String("-late"))
- state.phase = QMakeEvalLate;
- else if (arg == QLatin1String("-config"))
- argState = ArgConfig;
- else if (arg == QLatin1String("-nocache"))
- do_cache = false;
- else if (arg == QLatin1String("-cache"))
- argState = ArgCache;
- else if (arg == QLatin1String("-qtconf"))
- argState = ArgQtConf;
- else if (arg == QLatin1String("-platform") || arg == QLatin1String("-spec"))
- argState = ArgSpec;
- else if (arg == QLatin1String("-xplatform") || arg == QLatin1String("-xspec"))
- argState = ArgXSpec;
- else if (arg == QLatin1String("-template") || arg == QLatin1String("-t"))
- argState = ArgTmpl;
- else if (arg == QLatin1String("-template_prefix") || arg == QLatin1String("-tp"))
- argState = ArgTmplPfx;
- else if (arg == QLatin1String("-win32"))
- dir_sep = QLatin1Char('\\');
- else if (arg == QLatin1String("-unix"))
- dir_sep = QLatin1Char('/');
- else
- return ArgumentUnknown;
- } else if (arg.contains(QLatin1Char('='))) {
- state.cmds[state.phase] << arg;
- } else {
- return ArgumentUnknown;
- }
- continue;
- }
- argState = ArgNone;
- }
- if (argState != ArgNone)
- return ArgumentMalformed;
- return ArgumentsOk;
- }
- void QMakeGlobals::commitCommandLineArguments(QMakeCmdLineParserState &state)
- {
- if (!state.extraargs.isEmpty()) {
- QString extra = fL1S("QMAKE_EXTRA_ARGS =");
- for (const QString &ea : qAsConst(state.extraargs))
- extra += QLatin1Char(' ') + QMakeEvaluator::quoteValue(ProString(ea));
- state.cmds[QMakeEvalBefore] << extra;
- }
- for (int p = 0; p < 4; p++) {
- if (!state.configs[p].isEmpty())
- state.cmds[p] << (fL1S("CONFIG += ") + state.configs[p].join(QLatin1Char(' ')));
- extra_cmds[p] = state.cmds[p].join(QLatin1Char('\n'));
- }
- if (xqmakespec.isEmpty())
- xqmakespec = qmakespec;
- }
- void QMakeGlobals::useEnvironment()
- {
- if (xqmakespec.isEmpty())
- xqmakespec = getEnv(QLatin1String("XQMAKESPEC"));
- if (qmakespec.isEmpty()) {
- qmakespec = getEnv(QLatin1String("QMAKESPEC"));
- if (xqmakespec.isEmpty())
- xqmakespec = qmakespec;
- }
- }
- void QMakeGlobals::setCommandLineArguments(const QString &pwd, const QStringList &_args)
- {
- QStringList args = _args;
- QMakeCmdLineParserState state(pwd);
- for (int pos = 0; pos < args.size(); pos++)
- addCommandLineArguments(state, args, &pos);
- commitCommandLineArguments(state);
- useEnvironment();
- }
- void QMakeGlobals::setDirectories(const QString &input_dir, const QString &output_dir)
- {
- if (input_dir != output_dir && !output_dir.isEmpty()) {
- QString srcpath = input_dir;
- if (!srcpath.endsWith(QLatin1Char('/')))
- srcpath += QLatin1Char('/');
- QString dstpath = output_dir;
- if (!dstpath.endsWith(QLatin1Char('/')))
- dstpath += QLatin1Char('/');
- int srcLen = srcpath.length();
- int dstLen = dstpath.length();
- int lastSl = -1;
- while (++lastSl, --srcLen, --dstLen,
- srcLen && dstLen && srcpath.at(srcLen) == dstpath.at(dstLen))
- if (srcpath.at(srcLen) == QLatin1Char('/'))
- lastSl = 0;
- source_root = srcpath.left(srcLen + lastSl);
- build_root = dstpath.left(dstLen + lastSl);
- }
- }
- QString QMakeGlobals::shadowedPath(const QString &fileName) const
- {
- if (source_root.isEmpty())
- return fileName;
- if (fileName.startsWith(source_root)
- && (fileName.length() == source_root.length()
- || fileName.at(source_root.length()) == QLatin1Char('/'))) {
- return build_root + fileName.mid(source_root.length());
- }
- return QString();
- }
- QStringList QMakeGlobals::splitPathList(const QString &val) const
- {
- QStringList ret;
- if (!val.isEmpty()) {
- QString cwd(QDir::currentPath());
- const QStringList vals = val.split(dirlist_sep, Qt::SkipEmptyParts);
- ret.reserve(vals.length());
- for (const QString &it : vals)
- ret << IoUtils::resolvePath(cwd, it);
- }
- return ret;
- }
- QString QMakeGlobals::getEnv(const QString &var) const
- {
- #ifdef PROEVALUATOR_SETENV
- return environment.value(var);
- #else
- return QString::fromLocal8Bit(qgetenv(var.toLocal8Bit().constData()));
- #endif
- }
- QStringList QMakeGlobals::getPathListEnv(const QString &var) const
- {
- return splitPathList(getEnv(var));
- }
- QString QMakeGlobals::expandEnvVars(const QString &str) const
- {
- QString string = str;
- int startIndex = 0;
- forever {
- startIndex = string.indexOf(QLatin1Char('$'), startIndex);
- if (startIndex < 0)
- break;
- if (string.length() < startIndex + 3)
- break;
- if (string.at(startIndex + 1) != QLatin1Char('(')) {
- startIndex++;
- continue;
- }
- int endIndex = string.indexOf(QLatin1Char(')'), startIndex + 2);
- if (endIndex < 0)
- break;
- QString value = getEnv(string.mid(startIndex + 2, endIndex - startIndex - 2));
- string.replace(startIndex, endIndex - startIndex + 1, value);
- startIndex += value.length();
- }
- return string;
- }
- #ifndef QT_BUILD_QMAKE
- #ifdef PROEVALUATOR_INIT_PROPS
- bool QMakeGlobals::initProperties()
- {
- QByteArray data;
- #if QT_CONFIG(process)
- QProcess proc;
- proc.start(qmake_abslocation, QStringList() << QLatin1String("-query"));
- if (!proc.waitForFinished())
- return false;
- data = proc.readAll();
- #else
- if (FILE *proc = QT_POPEN(QString(IoUtils::shellQuote(qmake_abslocation)
- + QLatin1String(" -query")).toLocal8Bit(), QT_POPEN_READ)) {
- char buff[1024];
- while (!feof(proc))
- data.append(buff, int(fread(buff, 1, 1023, proc)));
- QT_PCLOSE(proc);
- }
- #endif
- parseProperties(data, properties);
- return true;
- }
- #endif
- void QMakeGlobals::parseProperties(const QByteArray &data, QHash<ProKey, ProString> &properties)
- {
- const auto lines = data.split('\n');
- for (QByteArray line : lines) {
- int off = line.indexOf(':');
- if (off < 0) // huh?
- continue;
- if (line.endsWith('\r'))
- line.chop(1);
- QString name = QString::fromLatin1(line.left(off));
- ProString value = ProString(QDir::fromNativeSeparators(
- QString::fromLocal8Bit(line.mid(off + 1))));
- if (value.isNull())
- value = ProString(""); // Make sure it is not null, to discern from missing keys
- properties.insert(ProKey(name), value);
- if (name.startsWith(QLatin1String("QT_"))) {
- enum { PropPut, PropRaw, PropGet } variant;
- if (name.contains(QLatin1Char('/'))) {
- if (name.endsWith(QLatin1String("/raw")))
- variant = PropRaw;
- else if (name.endsWith(QLatin1String("/get")))
- variant = PropGet;
- else // Nothing falls back on /src or /dev.
- continue;
- name.chop(4);
- } else {
- variant = PropPut;
- }
- if (name.startsWith(QLatin1String("QT_INSTALL_"))) {
- if (variant < PropRaw) {
- if (name == QLatin1String("QT_INSTALL_PREFIX")
- || name == QLatin1String("QT_INSTALL_DATA")
- || name == QLatin1String("QT_INSTALL_LIBS")
- || name == QLatin1String("QT_INSTALL_BINS")) {
- // Qt4 fallback
- QString hname = name;
- hname.replace(3, 7, QLatin1String("HOST"));
- properties.insert(ProKey(hname), value);
- properties.insert(ProKey(hname + QLatin1String("/get")), value);
- properties.insert(ProKey(hname + QLatin1String("/src")), value);
- }
- properties.insert(ProKey(name + QLatin1String("/raw")), value);
- }
- if (variant <= PropRaw)
- properties.insert(ProKey(name + QLatin1String("/dev")), value);
- } else if (!name.startsWith(QLatin1String("QT_HOST_"))) {
- continue;
- }
- if (variant != PropRaw) {
- if (variant < PropGet)
- properties.insert(ProKey(name + QLatin1String("/get")), value);
- properties.insert(ProKey(name + QLatin1String("/src")), value);
- }
- }
- }
- }
- #endif // QT_BUILD_QMAKE
- QT_END_NAMESPACE