mirror of
https://github.com/crystalidea/qt6windows7.git
synced 2025-07-03 07:45:30 +08:00
qt 6.5.1 original
This commit is contained in:
300
qmake/library/ioutils.cpp
Normal file
300
qmake/library/ioutils.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "ioutils.h"
|
||||
|
||||
#include <qdir.h>
|
||||
#include <qfile.h>
|
||||
#include <qregularexpression.h>
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <qt_windows.h>
|
||||
# include <private/qsystemerror_p.h>
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <unistd.h>
|
||||
# include <utime.h>
|
||||
# include <fcntl.h>
|
||||
# include <errno.h>
|
||||
#endif
|
||||
|
||||
#define fL1S(s) QString::fromLatin1(s)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
using namespace QMakeInternal;
|
||||
|
||||
QString IoUtils::binaryAbsLocation(const QString &argv0)
|
||||
{
|
||||
QString ret;
|
||||
if (!argv0.isEmpty() && isAbsolutePath(argv0)) {
|
||||
ret = argv0;
|
||||
} else if (argv0.contains(QLatin1Char('/'))
|
||||
#ifdef Q_OS_WIN
|
||||
|| argv0.contains(QLatin1Char('\\'))
|
||||
#endif
|
||||
) { // relative PWD
|
||||
ret = QDir::current().absoluteFilePath(argv0);
|
||||
} else { // in the PATH
|
||||
QByteArray pEnv = qgetenv("PATH");
|
||||
QDir currentDir = QDir::current();
|
||||
#ifdef Q_OS_WIN
|
||||
QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(";"));
|
||||
paths.prepend(QLatin1String("."));
|
||||
#else
|
||||
QStringList paths = QString::fromLocal8Bit(pEnv).split(QLatin1String(":"));
|
||||
#endif
|
||||
for (QStringList::const_iterator p = paths.constBegin(); p != paths.constEnd(); ++p) {
|
||||
if ((*p).isEmpty())
|
||||
continue;
|
||||
QString candidate = currentDir.absoluteFilePath(*p + QLatin1Char('/') + argv0);
|
||||
if (QFile::exists(candidate)) {
|
||||
ret = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QDir::cleanPath(ret);
|
||||
}
|
||||
|
||||
IoUtils::FileType IoUtils::fileType(const QString &fileName)
|
||||
{
|
||||
Q_ASSERT(fileName.isEmpty() || isAbsolutePath(fileName));
|
||||
#ifdef Q_OS_WIN
|
||||
DWORD attr = GetFileAttributesW((WCHAR*)fileName.utf16());
|
||||
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||
return FileNotFound;
|
||||
return (attr & FILE_ATTRIBUTE_DIRECTORY) ? FileIsDir : FileIsRegular;
|
||||
#else
|
||||
struct ::stat st;
|
||||
if (::stat(fileName.toLocal8Bit().constData(), &st))
|
||||
return FileNotFound;
|
||||
return S_ISDIR(st.st_mode) ? FileIsDir : S_ISREG(st.st_mode) ? FileIsRegular : FileNotFound;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool IoUtils::isRelativePath(const QString &path)
|
||||
{
|
||||
#ifdef QMAKE_BUILTIN_PRFS
|
||||
if (path.startsWith(QLatin1String(":/")))
|
||||
return false;
|
||||
#endif
|
||||
#ifdef Q_OS_WIN
|
||||
// Unlike QFileInfo, this considers only paths with both a drive prefix and
|
||||
// a subsequent (back-)slash absolute:
|
||||
if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
|
||||
&& (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
|
||||
return false;
|
||||
}
|
||||
// ... unless, of course, they're UNC:
|
||||
if (path.length() >= 2
|
||||
&& (path.at(0).unicode() == '\\' || path.at(0).unicode() == '/')
|
||||
&& path.at(1) == path.at(0)) {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (path.startsWith(QLatin1Char('/')))
|
||||
return false;
|
||||
#endif // Q_OS_WIN
|
||||
return true;
|
||||
}
|
||||
|
||||
QStringView IoUtils::pathName(const QString &fileName)
|
||||
{
|
||||
return QStringView{fileName}.left(fileName.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
}
|
||||
|
||||
QStringView IoUtils::fileName(const QString &fileName)
|
||||
{
|
||||
return QStringView(fileName).mid(fileName.lastIndexOf(QLatin1Char('/')) + 1);
|
||||
}
|
||||
|
||||
QString IoUtils::resolvePath(const QString &baseDir, const QString &fileName)
|
||||
{
|
||||
if (fileName.isEmpty())
|
||||
return QString();
|
||||
if (isAbsolutePath(fileName))
|
||||
return QDir::cleanPath(fileName);
|
||||
#ifdef Q_OS_WIN // Add drive to otherwise-absolute path:
|
||||
if (fileName.at(0).unicode() == '/' || fileName.at(0).unicode() == '\\') {
|
||||
Q_ASSERT_X(isAbsolutePath(baseDir), "IoUtils::resolvePath", qUtf8Printable(baseDir));
|
||||
return QDir::cleanPath(baseDir.left(2) + fileName);
|
||||
}
|
||||
#endif // Q_OS_WIN
|
||||
return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName);
|
||||
}
|
||||
|
||||
inline static
|
||||
bool isSpecialChar(ushort c, const uchar (&iqm)[16])
|
||||
{
|
||||
if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline static
|
||||
bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
|
||||
{
|
||||
for (int x = arg.size() - 1; x >= 0; --x) {
|
||||
if (isSpecialChar(arg.unicode()[x].unicode(), iqm))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QString IoUtils::shellQuoteUnix(const QString &arg)
|
||||
{
|
||||
// Chars that should be quoted (TM). This includes:
|
||||
static const uchar iqm[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xdf, 0x07, 0x00, 0xd8,
|
||||
0x00, 0x00, 0x00, 0x38, 0x01, 0x00, 0x00, 0x78
|
||||
}; // 0-32 \'"$`<>|;&(){}*?#!~[]
|
||||
|
||||
if (!arg.size())
|
||||
return QString::fromLatin1("''");
|
||||
|
||||
QString ret(arg);
|
||||
if (hasSpecialChars(ret, iqm)) {
|
||||
ret.replace(QLatin1Char('\''), QLatin1String("'\\''"));
|
||||
ret.prepend(QLatin1Char('\''));
|
||||
ret.append(QLatin1Char('\''));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString IoUtils::shellQuoteWin(const QString &arg)
|
||||
{
|
||||
// Chars that should be quoted (TM). This includes:
|
||||
// - control chars & space
|
||||
// - the shell meta chars "&()<>^|
|
||||
// - the potential separators ,;=
|
||||
static const uchar iqm[] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0x45, 0x13, 0x00, 0x78,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
|
||||
};
|
||||
// Shell meta chars that need escaping.
|
||||
static const uchar ism[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x00, 0x50,
|
||||
0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x10
|
||||
}; // &()<>^|
|
||||
|
||||
if (!arg.size())
|
||||
return QString::fromLatin1("\"\"");
|
||||
|
||||
QString ret(arg);
|
||||
if (hasSpecialChars(ret, iqm)) {
|
||||
// The process-level standard quoting allows escaping quotes with backslashes (note
|
||||
// that backslashes don't escape themselves, unless they are followed by a quote).
|
||||
// Consequently, quotes are escaped and their preceding backslashes are doubled.
|
||||
ret.replace(QRegularExpression(QLatin1String("(\\\\*)\"")), QLatin1String("\\1\\1\\\""));
|
||||
// Trailing backslashes must be doubled as well, as they are followed by a quote.
|
||||
ret.replace(QRegularExpression(QLatin1String("(\\\\+)$")), QLatin1String("\\1\\1"));
|
||||
// However, the shell also interprets the command, and no backslash-escaping exists
|
||||
// there - a quote always toggles the quoting state, but is nonetheless passed down
|
||||
// to the called process verbatim. In the unquoted state, the circumflex escapes
|
||||
// meta chars (including itself and quotes), and is removed from the command.
|
||||
bool quoted = true;
|
||||
for (int i = 0; i < ret.size(); i++) {
|
||||
QChar c = ret.unicode()[i];
|
||||
if (c.unicode() == '"')
|
||||
quoted = !quoted;
|
||||
else if (!quoted && isSpecialChar(c.unicode(), ism))
|
||||
ret.insert(i++, QLatin1Char('^'));
|
||||
}
|
||||
if (!quoted)
|
||||
ret.append(QLatin1Char('^'));
|
||||
ret.append(QLatin1Char('"'));
|
||||
ret.prepend(QLatin1Char('"'));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined(PROEVALUATOR_FULL)
|
||||
|
||||
bool IoUtils::touchFile(const QString &targetFileName, const QString &referenceFileName, QString *errorString)
|
||||
{
|
||||
# ifdef Q_OS_UNIX
|
||||
struct stat st;
|
||||
if (stat(referenceFileName.toLocal8Bit().constData(), &st)) {
|
||||
*errorString = fL1S("Cannot stat() reference file %1: %2.").arg(referenceFileName, fL1S(strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
# if defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L
|
||||
const struct timespec times[2] = { { 0, UTIME_NOW }, st.st_mtim };
|
||||
const bool utimeError = utimensat(AT_FDCWD, targetFileName.toLocal8Bit().constData(), times, 0) < 0;
|
||||
# else
|
||||
struct utimbuf utb;
|
||||
utb.actime = time(0);
|
||||
utb.modtime = st.st_mtime;
|
||||
const bool utimeError= utime(targetFileName.toLocal8Bit().constData(), &utb) < 0;
|
||||
# endif
|
||||
if (utimeError) {
|
||||
*errorString = fL1S("Cannot touch %1: %2.").arg(targetFileName, fL1S(strerror(errno)));
|
||||
return false;
|
||||
}
|
||||
# else
|
||||
HANDLE rHand = CreateFile((wchar_t*)referenceFileName.utf16(),
|
||||
GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (rHand == INVALID_HANDLE_VALUE) {
|
||||
*errorString = fL1S("Cannot open reference file %1: %2")
|
||||
.arg(referenceFileName, QSystemError::windowsString());
|
||||
return false;
|
||||
}
|
||||
FILETIME ft;
|
||||
GetFileTime(rHand, NULL, NULL, &ft);
|
||||
CloseHandle(rHand);
|
||||
HANDLE wHand = CreateFile((wchar_t*)targetFileName.utf16(),
|
||||
GENERIC_WRITE, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (wHand == INVALID_HANDLE_VALUE) {
|
||||
*errorString = fL1S("Cannot open %1: %2")
|
||||
.arg(targetFileName, QSystemError::windowsString());
|
||||
return false;
|
||||
}
|
||||
SetFileTime(wHand, NULL, NULL, &ft);
|
||||
CloseHandle(wHand);
|
||||
# endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(QT_BUILD_QMAKE) && defined(Q_OS_UNIX)
|
||||
bool IoUtils::readLinkTarget(const QString &symlinkPath, QString *target)
|
||||
{
|
||||
const QByteArray localSymlinkPath = QFile::encodeName(symlinkPath);
|
||||
# if defined(__GLIBC__) && !defined(PATH_MAX)
|
||||
# define PATH_CHUNK_SIZE 256
|
||||
char *s = 0;
|
||||
int len = -1;
|
||||
int size = PATH_CHUNK_SIZE;
|
||||
|
||||
forever {
|
||||
s = (char *)::realloc(s, size);
|
||||
len = ::readlink(localSymlinkPath.constData(), s, size);
|
||||
if (len < 0) {
|
||||
::free(s);
|
||||
break;
|
||||
}
|
||||
if (len < size)
|
||||
break;
|
||||
size *= 2;
|
||||
}
|
||||
# else
|
||||
char s[PATH_MAX+1];
|
||||
int len = readlink(localSymlinkPath.constData(), s, PATH_MAX);
|
||||
# endif
|
||||
if (len <= 0)
|
||||
return false;
|
||||
*target = QFile::decodeName(QByteArray(s, len));
|
||||
# if defined(__GLIBC__) && !defined(PATH_MAX)
|
||||
::free(s);
|
||||
# endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PROEVALUATOR_FULL
|
||||
|
||||
QT_END_NAMESPACE
|
55
qmake/library/ioutils.h
Normal file
55
qmake/library/ioutils.h
Normal file
@ -0,0 +1,55 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef IOUTILS_H
|
||||
#define IOUTILS_H
|
||||
|
||||
#include "qmake_global.h"
|
||||
|
||||
#include <qstring.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QMakeInternal {
|
||||
|
||||
/*!
|
||||
This class provides replacement functionality for QFileInfo, QFile & QDir,
|
||||
as these are abysmally slow.
|
||||
*/
|
||||
class QMAKE_EXPORT IoUtils {
|
||||
public:
|
||||
enum FileType {
|
||||
FileNotFound = 0,
|
||||
FileIsRegular = 1,
|
||||
FileIsDir = 2
|
||||
};
|
||||
|
||||
static QString binaryAbsLocation(const QString &argv0);
|
||||
static FileType fileType(const QString &fileName);
|
||||
static bool exists(const QString &fileName) { return fileType(fileName) != FileNotFound; }
|
||||
static bool isRelativePath(const QString &fileName);
|
||||
static bool isAbsolutePath(const QString &fileName) { return !isRelativePath(fileName); }
|
||||
static QStringView pathName(const QString &fileName); // Requires normalized path
|
||||
static QStringView fileName(const QString &fileName); // Requires normalized path
|
||||
static QString resolvePath(const QString &baseDir, const QString &fileName);
|
||||
static QString shellQuoteUnix(const QString &arg);
|
||||
static QString shellQuoteWin(const QString &arg);
|
||||
static QString shellQuote(const QString &arg)
|
||||
#ifdef Q_OS_UNIX
|
||||
{ return shellQuoteUnix(arg); }
|
||||
#else
|
||||
{ return shellQuoteWin(arg); }
|
||||
#endif
|
||||
#if defined(PROEVALUATOR_FULL)
|
||||
static bool touchFile(const QString &targetFileName, const QString &referenceFileName, QString *errorString);
|
||||
# if defined(QT_BUILD_QMAKE) && defined(Q_OS_UNIX)
|
||||
static bool readLinkTarget(const QString &symlinkPath, QString *target);
|
||||
# endif
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace ProFileEvaluatorInternal
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // IOUTILS_H
|
468
qmake/library/proitems.cpp
Normal file
468
qmake/library/proitems.cpp
Normal file
@ -0,0 +1,468 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "proitems.h"
|
||||
|
||||
#include <qfileinfo.h>
|
||||
#include <qset.h>
|
||||
#include <qstringlist.h>
|
||||
#include <qtextstream.h>
|
||||
#include <private/qduplicatetracker_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
// from qhash.cpp
|
||||
size_t ProString::hash(const QChar *p, int n)
|
||||
{
|
||||
size_t h = 0;
|
||||
|
||||
while (n--) {
|
||||
h = (h << 4) + (*p++).unicode();
|
||||
h ^= (h & 0xf0000000) >> 23;
|
||||
h &= 0x0fffffff;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
ProString::ProString() :
|
||||
m_offset(0), m_length(0), m_file(0), m_hash(0x80000000)
|
||||
{
|
||||
}
|
||||
|
||||
ProString::ProString(const ProString &other) :
|
||||
m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(other.m_hash)
|
||||
{
|
||||
}
|
||||
|
||||
ProString::ProString(const ProString &other, OmitPreHashing) :
|
||||
m_string(other.m_string), m_offset(other.m_offset), m_length(other.m_length), m_file(other.m_file), m_hash(0x80000000)
|
||||
{
|
||||
}
|
||||
|
||||
ProString::ProString(const QString &str, DoPreHashing) :
|
||||
m_string(str), m_offset(0), m_length(str.size()), m_file(0)
|
||||
{
|
||||
updatedHash();
|
||||
}
|
||||
|
||||
ProString::ProString(const QString &str) :
|
||||
m_string(str), m_offset(0), m_length(str.size()), m_file(0), m_hash(0x80000000)
|
||||
{
|
||||
}
|
||||
|
||||
ProString::ProString(QStringView str) :
|
||||
m_string(str.toString()), m_offset(0), m_length(str.size()), m_file(0), m_hash(0x80000000)
|
||||
{
|
||||
}
|
||||
|
||||
ProString::ProString(const char *str, DoPreHashing) :
|
||||
m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0)
|
||||
{
|
||||
updatedHash();
|
||||
}
|
||||
|
||||
ProString::ProString(const char *str) :
|
||||
m_string(QString::fromLatin1(str)), m_offset(0), m_length(int(qstrlen(str))), m_file(0), m_hash(0x80000000)
|
||||
{
|
||||
}
|
||||
|
||||
ProString::ProString(const QString &str, int offset, int length, DoPreHashing) :
|
||||
m_string(str), m_offset(offset), m_length(length), m_file(0)
|
||||
{
|
||||
updatedHash();
|
||||
}
|
||||
|
||||
ProString::ProString(const QString &str, int offset, int length, uint hash) :
|
||||
m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(hash)
|
||||
{
|
||||
}
|
||||
|
||||
ProString::ProString(const QString &str, int offset, int length) :
|
||||
m_string(str), m_offset(offset), m_length(length), m_file(0), m_hash(0x80000000)
|
||||
{
|
||||
}
|
||||
|
||||
void ProString::setValue(const QString &str)
|
||||
{
|
||||
m_string = str, m_offset = 0, m_length = str.size(), m_hash = 0x80000000;
|
||||
}
|
||||
|
||||
size_t ProString::updatedHash() const
|
||||
{
|
||||
return (m_hash = hash(m_string.constData() + m_offset, m_length));
|
||||
}
|
||||
|
||||
size_t qHash(const ProString &str)
|
||||
{
|
||||
if (!(str.m_hash & 0x80000000))
|
||||
return str.m_hash;
|
||||
return str.updatedHash();
|
||||
}
|
||||
|
||||
ProKey::ProKey(const QString &str) :
|
||||
ProString(str, DoHash)
|
||||
{
|
||||
}
|
||||
|
||||
ProKey::ProKey(const char *str) :
|
||||
ProString(str, DoHash)
|
||||
{
|
||||
}
|
||||
|
||||
ProKey::ProKey(const QString &str, int off, int len) :
|
||||
ProString(str, off, len, DoHash)
|
||||
{
|
||||
}
|
||||
|
||||
ProKey::ProKey(const QString &str, int off, int len, uint hash) :
|
||||
ProString(str, off, len, hash)
|
||||
{
|
||||
}
|
||||
|
||||
void ProKey::setValue(const QString &str)
|
||||
{
|
||||
m_string = str, m_offset = 0, m_length = str.size();
|
||||
updatedHash();
|
||||
}
|
||||
|
||||
QString ProString::toQString() const
|
||||
{
|
||||
return m_string.mid(m_offset, m_length);
|
||||
}
|
||||
|
||||
QString &ProString::toQString(QString &tmp) const
|
||||
{
|
||||
tmp = m_string.mid(m_offset, m_length);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
ProString &ProString::prepend(const ProString &other)
|
||||
{
|
||||
if (other.m_length) {
|
||||
if (!m_length) {
|
||||
*this = other;
|
||||
} else {
|
||||
m_string = other.toQStringView() + toQStringView();
|
||||
m_offset = 0;
|
||||
m_length = m_string.size();
|
||||
if (!m_file)
|
||||
m_file = other.m_file;
|
||||
m_hash = 0x80000000;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProString &ProString::append(const QLatin1String other)
|
||||
{
|
||||
if (other.size()) {
|
||||
if (m_length != m_string.size()) {
|
||||
m_string = toQStringView() + other;
|
||||
m_offset = 0;
|
||||
m_length = m_string.size();
|
||||
} else {
|
||||
Q_ASSERT(m_offset == 0);
|
||||
m_string.append(other);
|
||||
m_length += other.size();
|
||||
}
|
||||
m_hash = 0x80000000;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProString &ProString::append(QChar other)
|
||||
{
|
||||
if (m_length != m_string.size()) {
|
||||
m_string = toQStringView() + other;
|
||||
m_offset = 0;
|
||||
m_length = m_string.size();
|
||||
} else {
|
||||
Q_ASSERT(m_offset == 0);
|
||||
m_string.append(other);
|
||||
++m_length;
|
||||
}
|
||||
m_hash = 0x80000000;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If pending != 0, prefix with space if appending to non-empty non-pending
|
||||
ProString &ProString::append(const ProString &other, bool *pending)
|
||||
{
|
||||
if (other.m_length) {
|
||||
if (!m_length) {
|
||||
*this = other;
|
||||
} else {
|
||||
if (m_length != m_string.size())
|
||||
m_string = toQString();
|
||||
if (pending && !*pending) {
|
||||
m_string += QLatin1Char(' ') + other.toQStringView();
|
||||
} else {
|
||||
m_string += other.toQStringView();
|
||||
}
|
||||
m_length = m_string.size();
|
||||
m_offset = 0;
|
||||
if (other.m_file)
|
||||
m_file = other.m_file;
|
||||
m_hash = 0x80000000;
|
||||
}
|
||||
if (pending)
|
||||
*pending = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ProString &ProString::append(const ProStringList &other, bool *pending, bool skipEmpty1st)
|
||||
{
|
||||
if (const int sz = other.size()) {
|
||||
int startIdx = 0;
|
||||
if (pending && !*pending && skipEmpty1st && other.at(0).isEmpty()) {
|
||||
if (sz == 1)
|
||||
return *this;
|
||||
startIdx = 1;
|
||||
}
|
||||
if (!m_length && sz == startIdx + 1) {
|
||||
*this = other.at(startIdx);
|
||||
} else {
|
||||
bool putSpace = false;
|
||||
if (pending && !*pending && m_length)
|
||||
putSpace = true;
|
||||
|
||||
m_string = toQString();
|
||||
m_offset = 0;
|
||||
for (int i = startIdx; i < sz; ++i) {
|
||||
if (putSpace)
|
||||
m_string += QLatin1Char(' ');
|
||||
else
|
||||
putSpace = true;
|
||||
const ProString &str = other.at(i);
|
||||
m_string += str.toQStringView();
|
||||
}
|
||||
m_length = m_string.size();
|
||||
if (other.last().m_file)
|
||||
m_file = other.last().m_file;
|
||||
m_hash = 0x80000000;
|
||||
}
|
||||
if (pending)
|
||||
*pending = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
QString operator+(const ProString &one, const ProString &two)
|
||||
{
|
||||
if (two.m_length) {
|
||||
if (!one.m_length) {
|
||||
return two.toQString();
|
||||
} else {
|
||||
QString neu(one.m_length + two.m_length, Qt::Uninitialized);
|
||||
ushort *ptr = (ushort *)neu.constData();
|
||||
memcpy(ptr, one.m_string.constData() + one.m_offset, one.m_length * 2);
|
||||
memcpy(ptr + one.m_length, two.m_string.constData() + two.m_offset, two.m_length * 2);
|
||||
return neu;
|
||||
}
|
||||
}
|
||||
return one.toQString();
|
||||
}
|
||||
|
||||
|
||||
ProString ProString::mid(int off, int len) const
|
||||
{
|
||||
ProString ret(*this, NoHash);
|
||||
if (off > m_length)
|
||||
off = m_length;
|
||||
ret.m_offset += off;
|
||||
ret.m_length -= off;
|
||||
if ((uint)ret.m_length > (uint)len) // Unsigned comparison to interpret < 0 as infinite
|
||||
ret.m_length = len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ProString ProString::trimmed() const
|
||||
{
|
||||
ProString ret(*this, NoHash);
|
||||
int cur = m_offset;
|
||||
int end = cur + m_length;
|
||||
const QChar *data = m_string.constData();
|
||||
for (; cur < end; cur++)
|
||||
if (!data[cur].isSpace()) {
|
||||
// No underrun check - we know there is at least one non-whitespace
|
||||
while (data[end - 1].isSpace())
|
||||
end--;
|
||||
break;
|
||||
}
|
||||
ret.m_offset = cur;
|
||||
ret.m_length = end - cur;
|
||||
return ret;
|
||||
}
|
||||
|
||||
QTextStream &operator<<(QTextStream &t, const ProString &str)
|
||||
{
|
||||
t << str.toQStringView();
|
||||
return t;
|
||||
}
|
||||
|
||||
static QString ProStringList_join(const ProStringList &this_, const QChar *sep, const int sepSize)
|
||||
{
|
||||
int totalLength = 0;
|
||||
const int sz = this_.size();
|
||||
|
||||
for (int i = 0; i < sz; ++i)
|
||||
totalLength += this_.at(i).size();
|
||||
|
||||
if (sz)
|
||||
totalLength += sepSize * (sz - 1);
|
||||
|
||||
QString res(totalLength, Qt::Uninitialized);
|
||||
QChar *ptr = (QChar *)res.constData();
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (i) {
|
||||
memcpy(ptr, sep, sepSize * sizeof(QChar));
|
||||
ptr += sepSize;
|
||||
}
|
||||
const ProString &str = this_.at(i);
|
||||
memcpy(ptr, str.constData(), str.size() * sizeof(QChar));
|
||||
ptr += str.size();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
QString ProStringList::join(const ProString &sep) const
|
||||
{
|
||||
return ProStringList_join(*this, sep.constData(), sep.size());
|
||||
}
|
||||
|
||||
QString ProStringList::join(const QString &sep) const
|
||||
{
|
||||
return ProStringList_join(*this, sep.constData(), sep.size());
|
||||
}
|
||||
|
||||
QString ProStringList::join(QChar sep) const
|
||||
{
|
||||
return ProStringList_join(*this, &sep, 1);
|
||||
}
|
||||
|
||||
void ProStringList::removeAll(const ProString &str)
|
||||
{
|
||||
for (int i = size(); --i >= 0; )
|
||||
if (at(i) == str)
|
||||
remove(i);
|
||||
}
|
||||
|
||||
void ProStringList::removeAll(const char *str)
|
||||
{
|
||||
for (int i = size(); --i >= 0; )
|
||||
if (at(i) == str)
|
||||
remove(i);
|
||||
}
|
||||
|
||||
void ProStringList::removeEach(const ProStringList &value)
|
||||
{
|
||||
for (const ProString &str : value) {
|
||||
if (isEmpty())
|
||||
break;
|
||||
if (!str.isEmpty())
|
||||
removeAll(str);
|
||||
}
|
||||
}
|
||||
|
||||
void ProStringList::removeEmpty()
|
||||
{
|
||||
for (int i = size(); --i >= 0;)
|
||||
if (at(i).isEmpty())
|
||||
remove(i);
|
||||
}
|
||||
|
||||
void ProStringList::removeDuplicates()
|
||||
{
|
||||
QDuplicateTracker<ProString> seen(size());
|
||||
removeIf([&](const ProString &s) { return seen.hasSeen(s); });
|
||||
}
|
||||
|
||||
void ProStringList::insertUnique(const ProStringList &value)
|
||||
{
|
||||
for (const ProString &str : value)
|
||||
if (!str.isEmpty() && !contains(str))
|
||||
append(str);
|
||||
}
|
||||
|
||||
ProStringList::ProStringList(const QStringList &list)
|
||||
{
|
||||
reserve(list.size());
|
||||
for (const QString &str : list)
|
||||
*this << ProString(str);
|
||||
}
|
||||
|
||||
QStringList ProStringList::toQStringList() const
|
||||
{
|
||||
QStringList ret;
|
||||
ret.reserve(size());
|
||||
for (const auto &e : *this)
|
||||
ret.append(e.toQString());
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ProStringList::contains(const ProString &str, Qt::CaseSensitivity cs) const
|
||||
{
|
||||
for (int i = 0; i < size(); i++)
|
||||
if (!at(i).compare(str, cs))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProStringList::contains(QStringView str, Qt::CaseSensitivity cs) const
|
||||
{
|
||||
for (int i = 0; i < size(); i++)
|
||||
if (!at(i).toQStringView().compare(str, cs))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ProStringList::contains(const char *str, Qt::CaseSensitivity cs) const
|
||||
{
|
||||
for (int i = 0; i < size(); i++)
|
||||
if (!at(i).compare(str, cs))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
ProFile::ProFile(int id, const QString &fileName)
|
||||
: m_refCount(1),
|
||||
m_fileName(fileName),
|
||||
m_id(id),
|
||||
m_ok(true),
|
||||
m_hostBuild(false)
|
||||
{
|
||||
if (!fileName.startsWith(QLatin1Char('(')))
|
||||
m_directoryName = QFileInfo( // qmake sickness: canonicalize only the directory!
|
||||
fileName.left(fileName.lastIndexOf(QLatin1Char('/')))).canonicalFilePath();
|
||||
}
|
||||
|
||||
ProFile::~ProFile()
|
||||
{
|
||||
}
|
||||
|
||||
ProString ProFile::getStr(const ushort *&tPtr)
|
||||
{
|
||||
uint len = *tPtr++;
|
||||
ProString ret(items(), tPtr - tokPtr(), len);
|
||||
ret.setSource(m_id);
|
||||
tPtr += len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ProKey ProFile::getHashStr(const ushort *&tPtr)
|
||||
{
|
||||
uint hash = *tPtr++;
|
||||
hash |= (uint)*tPtr++ << 16;
|
||||
uint len = *tPtr++;
|
||||
ProKey ret(items(), tPtr - tokPtr(), len, hash);
|
||||
tPtr += len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, const ProString &str)
|
||||
{
|
||||
return debug << str.toQString();
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
489
qmake/library/proitems.h
Normal file
489
qmake/library/proitems.h
Normal file
@ -0,0 +1,489 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef PROITEMS_H
|
||||
#define PROITEMS_H
|
||||
|
||||
#include "qmake_global.h"
|
||||
|
||||
#include <qdebug.h>
|
||||
#include <qhash.h>
|
||||
#include <qlist.h>
|
||||
#include <qmap.h>
|
||||
#include <qstring.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QTextStream;
|
||||
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
typedef QAtomicInt ProItemRefCount;
|
||||
#else
|
||||
class ProItemRefCount {
|
||||
public:
|
||||
ProItemRefCount(int cnt = 0) : m_cnt(cnt) {}
|
||||
bool ref() { return ++m_cnt != 0; }
|
||||
bool deref() { return --m_cnt != 0; }
|
||||
ProItemRefCount &operator=(int value) { m_cnt = value; return *this; }
|
||||
private:
|
||||
int m_cnt;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef QT_BUILD_QMAKE
|
||||
# define PROITEM_EXPLICIT explicit
|
||||
#else
|
||||
# define PROITEM_EXPLICIT
|
||||
#endif
|
||||
|
||||
class ProKey;
|
||||
class ProStringList;
|
||||
class ProFile;
|
||||
|
||||
class ProString {
|
||||
public:
|
||||
ProString();
|
||||
ProString(const ProString &other);
|
||||
ProString &operator=(const ProString &) = default;
|
||||
template<typename A, typename B>
|
||||
ProString &operator=(const QStringBuilder<A, B> &str)
|
||||
{ return *this = QString(str); }
|
||||
ProString(const QString &str);
|
||||
PROITEM_EXPLICIT ProString(QStringView str);
|
||||
PROITEM_EXPLICIT ProString(const char *str);
|
||||
template<typename A, typename B>
|
||||
ProString(const QStringBuilder<A, B> &str)
|
||||
: ProString(QString(str))
|
||||
{}
|
||||
ProString(const QString &str, int offset, int length);
|
||||
void setValue(const QString &str);
|
||||
void clear() { m_string.clear(); m_length = 0; }
|
||||
ProString &setSource(const ProString &other) { m_file = other.m_file; return *this; }
|
||||
ProString &setSource(int id) { m_file = id; return *this; }
|
||||
int sourceFile() const { return m_file; }
|
||||
|
||||
ProString &prepend(const ProString &other);
|
||||
ProString &append(const ProString &other, bool *pending = nullptr);
|
||||
ProString &append(const QString &other) { return append(ProString(other)); }
|
||||
template<typename A, typename B>
|
||||
ProString &append(const QStringBuilder<A, B> &other) { return append(QString(other)); }
|
||||
ProString &append(const QLatin1String other);
|
||||
ProString &append(const char *other) { return append(QLatin1String(other)); }
|
||||
ProString &append(QChar other);
|
||||
ProString &append(const ProStringList &other, bool *pending = nullptr, bool skipEmpty1st = false);
|
||||
ProString &operator+=(const ProString &other) { return append(other); }
|
||||
ProString &operator+=(const QString &other) { return append(other); }
|
||||
template<typename A, typename B>
|
||||
ProString &operator+=(const QStringBuilder<A, B> &other) { return append(QString(other)); }
|
||||
ProString &operator+=(const QLatin1String other) { return append(other); }
|
||||
ProString &operator+=(const char *other) { return append(other); }
|
||||
ProString &operator+=(QChar other) { return append(other); }
|
||||
|
||||
void chop(int n) { Q_ASSERT(n <= m_length); m_length -= n; }
|
||||
void chopFront(int n) { Q_ASSERT(n <= m_length); m_offset += n; m_length -= n; }
|
||||
|
||||
bool operator==(const ProString &other) const { return toQStringView() == other.toQStringView(); }
|
||||
bool operator==(const QString &other) const { return toQStringView() == other; }
|
||||
bool operator==(QStringView other) const { return toQStringView() == other; }
|
||||
bool operator==(QLatin1String other) const { return toQStringView() == other; }
|
||||
bool operator==(const char *other) const { return toQStringView() == QLatin1String(other); }
|
||||
bool operator!=(const ProString &other) const { return !(*this == other); }
|
||||
bool operator!=(const QString &other) const { return !(*this == other); }
|
||||
bool operator!=(QLatin1String other) const { return !(*this == other); }
|
||||
bool operator!=(const char *other) const { return !(*this == other); }
|
||||
bool operator<(const ProString &other) const { return toQStringView() < other.toQStringView(); }
|
||||
bool isNull() const { return m_string.isNull(); }
|
||||
bool isEmpty() const { return !m_length; }
|
||||
int length() const { return m_length; }
|
||||
int size() const { return m_length; }
|
||||
QChar at(int i) const { Q_ASSERT((uint)i < (uint)m_length); return constData()[i]; }
|
||||
const QChar *constData() const { return m_string.constData() + m_offset; }
|
||||
ProString mid(int off, int len = -1) const;
|
||||
ProString left(int len) const { return mid(0, len); }
|
||||
ProString right(int len) const { return mid(qMax(0, size() - len)); }
|
||||
ProString trimmed() const;
|
||||
int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().compare(sub.toQStringView(), cs); }
|
||||
int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().compare(sub, cs); }
|
||||
int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().compare(QLatin1String(sub), cs); }
|
||||
bool startsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(sub.toQStringView(), cs); }
|
||||
bool startsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(sub, cs); }
|
||||
bool startsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(QLatin1String(sub), cs); }
|
||||
bool startsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().startsWith(c, cs); }
|
||||
template<typename A, typename B>
|
||||
bool startsWith(const QStringBuilder<A, B> &str) { return startsWith(QString(str)); }
|
||||
bool endsWith(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(sub.toQStringView(), cs); }
|
||||
bool endsWith(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(sub, cs); }
|
||||
bool endsWith(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(QLatin1String(sub), cs); }
|
||||
template<typename A, typename B>
|
||||
bool endsWith(const QStringBuilder<A, B> &str) { return endsWith(QString(str)); }
|
||||
bool endsWith(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().endsWith(c, cs); }
|
||||
int indexOf(const QString &s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().indexOf(s, from, cs); }
|
||||
int indexOf(const char *s, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().indexOf(QLatin1String(s), from, cs); }
|
||||
int indexOf(QChar c, int from = 0, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().indexOf(c, from, cs); }
|
||||
int lastIndexOf(const QString &s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().lastIndexOf(s, from, cs); }
|
||||
int lastIndexOf(const char *s, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().lastIndexOf(QLatin1String(s), from, cs); }
|
||||
int lastIndexOf(QChar c, int from = -1, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringView().lastIndexOf(c, from, cs); }
|
||||
bool contains(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(s, 0, cs) >= 0; }
|
||||
bool contains(const char *s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(QLatin1String(s), 0, cs) >= 0; }
|
||||
bool contains(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return indexOf(c, 0, cs) >= 0; }
|
||||
qlonglong toLongLong(bool *ok = nullptr, int base = 10) const { return toQStringView().toLongLong(ok, base); }
|
||||
int toInt(bool *ok = nullptr, int base = 10) const { return toQStringView().toInt(ok, base); }
|
||||
short toShort(bool *ok = nullptr, int base = 10) const { return toQStringView().toShort(ok, base); }
|
||||
|
||||
size_t hash() const { return m_hash; }
|
||||
static size_t hash(const QChar *p, int n);
|
||||
|
||||
ALWAYS_INLINE QStringView toQStringView() const { return QStringView(m_string).mid(m_offset, m_length); }
|
||||
|
||||
ALWAYS_INLINE ProKey &toKey() { return *(ProKey *)this; }
|
||||
ALWAYS_INLINE const ProKey &toKey() const { return *(const ProKey *)this; }
|
||||
|
||||
QString toQString() const;
|
||||
QString &toQString(QString &tmp) const;
|
||||
|
||||
QByteArray toLatin1() const { return toQStringView().toLatin1(); }
|
||||
|
||||
private:
|
||||
ProString(const ProKey &other);
|
||||
ProString &operator=(const ProKey &other);
|
||||
|
||||
enum OmitPreHashing { NoHash };
|
||||
ProString(const ProString &other, OmitPreHashing);
|
||||
|
||||
enum DoPreHashing { DoHash };
|
||||
ALWAYS_INLINE ProString(const QString &str, DoPreHashing);
|
||||
ALWAYS_INLINE ProString(const char *str, DoPreHashing);
|
||||
ALWAYS_INLINE ProString(const QString &str, int offset, int length, DoPreHashing);
|
||||
ALWAYS_INLINE ProString(const QString &str, int offset, int length, uint hash);
|
||||
|
||||
QString m_string;
|
||||
int m_offset, m_length;
|
||||
int m_file;
|
||||
mutable size_t m_hash;
|
||||
size_t updatedHash() const;
|
||||
friend size_t qHash(const ProString &str);
|
||||
friend QString operator+(const ProString &one, const ProString &two);
|
||||
friend class ProKey;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(ProString, Q_RELOCATABLE_TYPE);
|
||||
|
||||
|
||||
class ProKey : public ProString {
|
||||
public:
|
||||
ALWAYS_INLINE ProKey() : ProString() {}
|
||||
explicit ProKey(const QString &str);
|
||||
template<typename A, typename B>
|
||||
ProKey(const QStringBuilder<A, B> &str)
|
||||
: ProString(str)
|
||||
{}
|
||||
PROITEM_EXPLICIT ProKey(const char *str);
|
||||
ProKey(const QString &str, int off, int len);
|
||||
ProKey(const QString &str, int off, int len, uint hash);
|
||||
void setValue(const QString &str);
|
||||
|
||||
#ifdef Q_CC_MSVC
|
||||
// Workaround strange MSVC behaviour when exporting classes with ProKey members.
|
||||
ALWAYS_INLINE ProKey(const ProKey &other) : ProString(other.toString()) {}
|
||||
ALWAYS_INLINE ProKey &operator=(const ProKey &other)
|
||||
{
|
||||
toString() = other.toString();
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE ProString &toString() { return *(ProString *)this; }
|
||||
ALWAYS_INLINE const ProString &toString() const { return *(const ProString *)this; }
|
||||
|
||||
private:
|
||||
ProKey(const ProString &other);
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(ProKey, Q_RELOCATABLE_TYPE);
|
||||
|
||||
template <> struct QConcatenable<ProString> : private QAbstractConcatenable
|
||||
{
|
||||
typedef ProString type;
|
||||
typedef QString ConvertTo;
|
||||
enum { ExactSize = true };
|
||||
static int size(const ProString &a) { return a.length(); }
|
||||
static inline void appendTo(const ProString &a, QChar *&out)
|
||||
{
|
||||
const auto n = a.size();
|
||||
if (!n)
|
||||
return;
|
||||
memcpy(out, a.toQStringView().data(), sizeof(QChar) * n);
|
||||
out += n;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct QConcatenable<ProKey> : private QAbstractConcatenable
|
||||
{
|
||||
typedef ProKey type;
|
||||
typedef QString ConvertTo;
|
||||
enum { ExactSize = true };
|
||||
static int size(const ProKey &a) { return a.length(); }
|
||||
static inline void appendTo(const ProKey &a, QChar *&out)
|
||||
{
|
||||
const auto n = a.size();
|
||||
if (!n)
|
||||
return;
|
||||
memcpy(out, a.toQStringView().data(), sizeof(QChar) * n);
|
||||
out += n;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
size_t qHash(const ProString &str);
|
||||
|
||||
inline QString &operator+=(QString &that, const ProString &other)
|
||||
{ return that += other.toQStringView(); }
|
||||
|
||||
QTextStream &operator<<(QTextStream &t, const ProString &str);
|
||||
template<typename A, typename B>
|
||||
QTextStream &operator<<(QTextStream &t, const QStringBuilder<A, B> &str) { return t << QString(str); }
|
||||
|
||||
// This class manages read-only access to a ProString via a raw data QString
|
||||
// temporary, ensuring that the latter is accessed exclusively.
|
||||
class ProStringRoUser
|
||||
{
|
||||
public:
|
||||
ProStringRoUser(QString &rs)
|
||||
{
|
||||
m_rs = &rs;
|
||||
}
|
||||
ProStringRoUser(const ProString &ps, QString &rs)
|
||||
: ProStringRoUser(rs)
|
||||
{
|
||||
ps.toQString(rs);
|
||||
}
|
||||
// No destructor, as a RAII pattern cannot be used: references to the
|
||||
// temporary string can legitimately outlive instances of this class
|
||||
// (if they are held by Qt, e.g. in QRegExp).
|
||||
QString &set(const ProString &ps) { return ps.toQString(*m_rs); }
|
||||
QString &str() { return *m_rs; }
|
||||
|
||||
protected:
|
||||
QString *m_rs;
|
||||
};
|
||||
|
||||
// This class manages read-write access to a ProString via a raw data QString
|
||||
// temporary, ensuring that the latter is accessed exclusively, and that raw
|
||||
// data does not leak outside its source's refcounting.
|
||||
class ProStringRwUser : public ProStringRoUser
|
||||
{
|
||||
public:
|
||||
ProStringRwUser(QString &rs)
|
||||
: ProStringRoUser(rs), m_ps(nullptr) {}
|
||||
ProStringRwUser(const ProString &ps, QString &rs)
|
||||
: ProStringRoUser(ps, rs), m_ps(&ps) {}
|
||||
QString &set(const ProString &ps) { m_ps = &ps; return ProStringRoUser::set(ps); }
|
||||
ProString extract(const QString &s) const
|
||||
{ return s.isSharedWith(*m_rs) ? *m_ps : ProString(s).setSource(*m_ps); }
|
||||
ProString extract(const QString &s, const ProStringRwUser &other) const
|
||||
{
|
||||
if (other.m_ps && s.isSharedWith(*other.m_rs))
|
||||
return *other.m_ps;
|
||||
return extract(s);
|
||||
}
|
||||
|
||||
private:
|
||||
const ProString *m_ps;
|
||||
};
|
||||
|
||||
class ProStringList : public QList<ProString> {
|
||||
public:
|
||||
ProStringList() {}
|
||||
ProStringList(const ProString &str) { *this << str; }
|
||||
explicit ProStringList(const QStringList &list);
|
||||
QStringList toQStringList() const;
|
||||
|
||||
ProStringList &operator<<(const ProString &str)
|
||||
{ QList<ProString>::operator<<(str); return *this; }
|
||||
|
||||
int length() const { return size(); }
|
||||
|
||||
QString join(const ProString &sep) const;
|
||||
QString join(const QString &sep) const;
|
||||
QString join(QChar sep) const;
|
||||
template<typename A, typename B>
|
||||
QString join(const QStringBuilder<A, B> &str) { return join(QString(str)); }
|
||||
|
||||
void insertUnique(const ProStringList &value);
|
||||
|
||||
void removeAll(const ProString &str);
|
||||
void removeAll(const char *str);
|
||||
void removeEach(const ProStringList &value);
|
||||
void removeAt(int idx) { remove(idx); }
|
||||
void removeEmpty();
|
||||
void removeDuplicates();
|
||||
|
||||
bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
|
||||
bool contains(QStringView str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
|
||||
bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
|
||||
{ return contains(ProString(str), cs); }
|
||||
bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(ProStringList, Q_RELOCATABLE_TYPE);
|
||||
|
||||
inline ProStringList operator+(const ProStringList &one, const ProStringList &two)
|
||||
{ ProStringList ret = one; ret += two; return ret; }
|
||||
|
||||
typedef QMap<ProKey, ProStringList> ProValueMap;
|
||||
|
||||
// These token definitions affect both ProFileEvaluator and ProWriter
|
||||
enum ProToken {
|
||||
TokTerminator = 0, // end of stream (possibly not included in length; must be zero)
|
||||
TokLine, // line marker:
|
||||
// - line (1)
|
||||
TokAssign, // variable =
|
||||
TokAppend, // variable +=
|
||||
TokAppendUnique, // variable *=
|
||||
TokRemove, // variable -=
|
||||
TokReplace, // variable ~=
|
||||
// previous literal/expansion is a variable manipulation
|
||||
// - lower bound for expected output length (1)
|
||||
// - value expression + TokValueTerminator
|
||||
TokValueTerminator, // assignment value terminator
|
||||
TokLiteral, // literal string (fully dequoted)
|
||||
// - length (1)
|
||||
// - string data (length; unterminated)
|
||||
TokHashLiteral, // literal string with hash (fully dequoted)
|
||||
// - hash (2)
|
||||
// - length (1)
|
||||
// - string data (length; unterminated)
|
||||
TokVariable, // qmake variable expansion
|
||||
// - hash (2)
|
||||
// - name length (1)
|
||||
// - name (name length; unterminated)
|
||||
TokProperty, // qmake property expansion
|
||||
// - hash (2)
|
||||
// - name length (1)
|
||||
// - name (name length; unterminated)
|
||||
TokEnvVar, // environment variable expansion
|
||||
// - name length (1)
|
||||
// - name (name length; unterminated)
|
||||
TokFuncName, // replace function expansion
|
||||
// - hash (2)
|
||||
// - name length (1)
|
||||
// - name (name length; unterminated)
|
||||
// - ((nested expansion + TokArgSeparator)* + nested expansion)?
|
||||
// - TokFuncTerminator
|
||||
TokArgSeparator, // function argument separator
|
||||
TokFuncTerminator, // function argument list terminator
|
||||
TokCondition, // previous literal/expansion is a conditional
|
||||
TokTestCall, // previous literal/expansion is a test function call
|
||||
// - ((nested expansion + TokArgSeparator)* + nested expansion)?
|
||||
// - TokFuncTerminator
|
||||
TokReturn, // previous literal/expansion is a return value
|
||||
TokBreak, // break loop
|
||||
TokNext, // shortcut to next loop iteration
|
||||
TokNot, // '!' operator
|
||||
TokAnd, // ':' operator
|
||||
TokOr, // '|' operator
|
||||
TokBranch, // branch point:
|
||||
// - then block length (2)
|
||||
// - then block + TokTerminator (then block length)
|
||||
// - else block length (2)
|
||||
// - else block + TokTerminator (else block length)
|
||||
TokForLoop, // for loop:
|
||||
// - variable name: hash (2), length (1), chars (length)
|
||||
// - expression: length (2), bytes + TokValueTerminator (length)
|
||||
// - body length (2)
|
||||
// - body + TokTerminator (body length)
|
||||
TokTestDef, // test function definition:
|
||||
TokReplaceDef, // replace function definition:
|
||||
// - function name: hash (2), length (1), chars (length)
|
||||
// - body length (2)
|
||||
// - body + TokTerminator (body length)
|
||||
TokBypassNesting, // escape from function local variable scopes:
|
||||
// - block length (2)
|
||||
// - block + TokTerminator (block length)
|
||||
TokMask = 0xff,
|
||||
TokQuoted = 0x100, // The expression is quoted => join expanded stringlist
|
||||
TokNewStr = 0x200 // Next stringlist element
|
||||
};
|
||||
|
||||
class QMAKE_EXPORT ProFile
|
||||
{
|
||||
public:
|
||||
ProFile(int id, const QString &fileName);
|
||||
~ProFile();
|
||||
|
||||
int id() const { return m_id; }
|
||||
QString fileName() const { return m_fileName; }
|
||||
QString directoryName() const { return m_directoryName; }
|
||||
const QString &items() const { return m_proitems; }
|
||||
QString *itemsRef() { return &m_proitems; }
|
||||
const ushort *tokPtr() const { return (const ushort *)m_proitems.constData(); }
|
||||
const ushort *tokPtrEnd() const { return (const ushort *)m_proitems.constData() + m_proitems.size(); }
|
||||
|
||||
void ref() { m_refCount.ref(); }
|
||||
void deref() { if (!m_refCount.deref()) delete this; }
|
||||
|
||||
bool isOk() const { return m_ok; }
|
||||
void setOk(bool ok) { m_ok = ok; }
|
||||
|
||||
bool isHostBuild() const { return m_hostBuild; }
|
||||
void setHostBuild(bool host_build) { m_hostBuild = host_build; }
|
||||
|
||||
ProString getStr(const ushort *&tPtr);
|
||||
ProKey getHashStr(const ushort *&tPtr);
|
||||
|
||||
private:
|
||||
ProItemRefCount m_refCount;
|
||||
QString m_proitems;
|
||||
QString m_fileName;
|
||||
QString m_directoryName;
|
||||
int m_id;
|
||||
bool m_ok;
|
||||
bool m_hostBuild;
|
||||
};
|
||||
|
||||
class ProFunctionDef {
|
||||
public:
|
||||
ProFunctionDef(ProFile *pro, int offset) : m_pro(pro), m_offset(offset) { m_pro->ref(); }
|
||||
ProFunctionDef(const ProFunctionDef &o) : m_pro(o.m_pro), m_offset(o.m_offset) { m_pro->ref(); }
|
||||
ProFunctionDef(ProFunctionDef &&other) noexcept
|
||||
: m_pro(other.m_pro), m_offset(other.m_offset) { other.m_pro = nullptr; }
|
||||
~ProFunctionDef() { if (m_pro) m_pro->deref(); }
|
||||
ProFunctionDef &operator=(const ProFunctionDef &o)
|
||||
{
|
||||
if (this != &o) {
|
||||
if (m_pro)
|
||||
m_pro->deref();
|
||||
m_pro = o.m_pro;
|
||||
m_pro->ref();
|
||||
m_offset = o.m_offset;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ProFunctionDef &operator=(ProFunctionDef &&other) noexcept
|
||||
{
|
||||
ProFunctionDef moved(std::move(other));
|
||||
swap(moved);
|
||||
return *this;
|
||||
}
|
||||
void swap(ProFunctionDef &other) noexcept
|
||||
{
|
||||
qSwap(m_pro, other.m_pro);
|
||||
qSwap(m_offset, other.m_offset);
|
||||
}
|
||||
|
||||
ProFile *pro() const { return m_pro; }
|
||||
const ushort *tokPtr() const { return m_pro->tokPtr() + m_offset; }
|
||||
private:
|
||||
ProFile *m_pro;
|
||||
int m_offset;
|
||||
};
|
||||
|
||||
Q_DECLARE_TYPEINFO(ProFunctionDef, Q_RELOCATABLE_TYPE);
|
||||
|
||||
struct ProFunctionDefs {
|
||||
QHash<ProKey, ProFunctionDef> testFunctions;
|
||||
QHash<ProKey, ProFunctionDef> replaceFunctions;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, const ProString &str);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // PROITEMS_H
|
33
qmake/library/qmake_global.h
Normal file
33
qmake/library/qmake_global.h
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QMAKE_GLOBAL_H
|
||||
#define QMAKE_GLOBAL_H
|
||||
|
||||
#include <qglobal.h>
|
||||
|
||||
#if defined(QMAKE_AS_LIBRARY)
|
||||
# if defined(QMAKE_LIBRARY)
|
||||
# define QMAKE_EXPORT Q_DECL_EXPORT
|
||||
# else
|
||||
# define QMAKE_EXPORT Q_DECL_IMPORT
|
||||
# endif
|
||||
#else
|
||||
# define QMAKE_EXPORT
|
||||
#endif
|
||||
|
||||
// Be fast even for debug builds
|
||||
// MinGW GCC 4.5+ has a problem with always_inline putTok and putBlockLen
|
||||
#if defined(__GNUC__) && !(defined(__MINGW32__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 5)
|
||||
# define ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#elif defined(_MSC_VER)
|
||||
# define ALWAYS_INLINE __forceinline
|
||||
#else
|
||||
# define ALWAYS_INLINE inline
|
||||
#endif
|
||||
|
||||
#ifdef PROEVALUATOR_FULL
|
||||
# define PROEVALUATOR_DEBUG
|
||||
#endif
|
||||
|
||||
#endif
|
1895
qmake/library/qmakebuiltins.cpp
Normal file
1895
qmake/library/qmakebuiltins.cpp
Normal file
File diff suppressed because it is too large
Load Diff
2188
qmake/library/qmakeevaluator.cpp
Normal file
2188
qmake/library/qmakeevaluator.cpp
Normal file
File diff suppressed because it is too large
Load Diff
309
qmake/library/qmakeevaluator.h
Normal file
309
qmake/library/qmakeevaluator.h
Normal file
@ -0,0 +1,309 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QMAKEEVALUATOR_H
|
||||
#define QMAKEEVALUATOR_H
|
||||
|
||||
#if defined(PROEVALUATOR_FULL) && defined(PROEVALUATOR_THREAD_SAFE)
|
||||
# error PROEVALUATOR_FULL is incompatible with PROEVALUATOR_THREAD_SAFE due to cache() implementation
|
||||
#endif
|
||||
|
||||
#include "qmakeparser.h"
|
||||
#include "qmakevfs.h"
|
||||
#include "ioutils.h"
|
||||
|
||||
#include <qlist.h>
|
||||
#include <qmap.h>
|
||||
#include <qset.h>
|
||||
#include <qstack.h>
|
||||
#include <qstring.h>
|
||||
#include <qstringlist.h>
|
||||
#include <qshareddata.h>
|
||||
#if QT_CONFIG(process)
|
||||
# include <qprocess.h>
|
||||
#else
|
||||
# include <qiodevice.h>
|
||||
#endif
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
# include <qmutex.h>
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMakeGlobals;
|
||||
|
||||
class QMAKE_EXPORT QMakeHandler : public QMakeParserHandler
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
SourceEvaluator = 0x10,
|
||||
|
||||
CumulativeEvalMessage = 0x1000,
|
||||
|
||||
EvalWarnLanguage = SourceEvaluator | WarningMessage | WarnLanguage,
|
||||
EvalWarnDeprecated = SourceEvaluator | WarningMessage | WarnDeprecated,
|
||||
|
||||
EvalError = ErrorMessage | SourceEvaluator
|
||||
};
|
||||
|
||||
// error(), warning() and message() from .pro file
|
||||
virtual void fileMessage(int type, const QString &msg) = 0;
|
||||
|
||||
enum EvalFileType { EvalProjectFile, EvalIncludeFile, EvalConfigFile, EvalFeatureFile, EvalAuxFile };
|
||||
virtual void aboutToEval(ProFile *parent, ProFile *proFile, EvalFileType type) = 0;
|
||||
virtual void doneWithEval(ProFile *parent) = 0;
|
||||
};
|
||||
|
||||
typedef QPair<QString, QString> QMakeFeatureKey; // key, parent
|
||||
typedef QHash<QMakeFeatureKey, QString> QMakeFeatureHash;
|
||||
|
||||
class QMAKE_EXPORT QMakeFeatureRoots : public QSharedData
|
||||
{
|
||||
public:
|
||||
QMakeFeatureRoots(const QStringList &_paths) : paths(_paths) {}
|
||||
const QStringList paths;
|
||||
mutable QMakeFeatureHash cache;
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
mutable QMutex mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
// We use a list-based stack instead of a vector-based one, so that
|
||||
// the addresses of value maps stay constant. The qmake generators rely on that.
|
||||
class QMAKE_EXPORT ProValueMapStack : public std::list<ProValueMap>
|
||||
{
|
||||
public:
|
||||
inline void push(const ProValueMap &t) { push_back(t); }
|
||||
inline ProValueMap pop() { auto r = std::move(back()); pop_back(); return r; }
|
||||
ProValueMap &top() { return back(); }
|
||||
const ProValueMap &top() const { return back(); }
|
||||
};
|
||||
|
||||
namespace QMakeInternal { struct QMakeBuiltin; }
|
||||
|
||||
class QMAKE_EXPORT QMakeEvaluator
|
||||
{
|
||||
public:
|
||||
enum LoadFlag {
|
||||
LoadProOnly = 0,
|
||||
LoadPreFiles = 1,
|
||||
LoadPostFiles = 2,
|
||||
LoadAll = LoadPreFiles|LoadPostFiles,
|
||||
LoadSilent = 0x10,
|
||||
LoadHidden = 0x20
|
||||
};
|
||||
Q_DECLARE_FLAGS(LoadFlags, LoadFlag)
|
||||
|
||||
static void initStatics();
|
||||
static void initFunctionStatics();
|
||||
QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser, QMakeVfs *vfs,
|
||||
QMakeHandler *handler);
|
||||
~QMakeEvaluator();
|
||||
|
||||
void setExtraVars(const ProValueMap &extraVars) { m_extraVars = extraVars; }
|
||||
void setExtraConfigs(const ProStringList &extraConfigs) { m_extraConfigs = extraConfigs; }
|
||||
void setOutputDir(const QString &outputDir) { m_outputDir = outputDir; }
|
||||
|
||||
ProStringList values(const ProKey &variableName) const;
|
||||
ProStringList &valuesRef(const ProKey &variableName);
|
||||
ProString first(const ProKey &variableName) const;
|
||||
ProString propertyValue(const ProKey &val) const;
|
||||
|
||||
ProString dirSep() const { return m_dirSep; }
|
||||
bool isHostBuild() const { return m_hostBuild; }
|
||||
|
||||
enum VisitReturn {
|
||||
ReturnFalse,
|
||||
ReturnTrue,
|
||||
ReturnError,
|
||||
ReturnBreak,
|
||||
ReturnNext,
|
||||
ReturnReturn
|
||||
};
|
||||
|
||||
static ALWAYS_INLINE VisitReturn returnBool(bool b)
|
||||
{ return b ? ReturnTrue : ReturnFalse; }
|
||||
|
||||
static ALWAYS_INLINE uint getBlockLen(const ushort *&tokPtr);
|
||||
VisitReturn evaluateExpression(const ushort *&tokPtr, ProStringList *ret, bool joined);
|
||||
static ALWAYS_INLINE void skipStr(const ushort *&tokPtr);
|
||||
static ALWAYS_INLINE void skipHashStr(const ushort *&tokPtr);
|
||||
void skipExpression(const ushort *&tokPtr);
|
||||
|
||||
void loadDefaults();
|
||||
bool prepareProject(const QString &inDir);
|
||||
bool loadSpecInternal();
|
||||
bool loadSpec();
|
||||
void initFrom(const QMakeEvaluator *other);
|
||||
void setupProject();
|
||||
void evaluateCommand(const QString &cmds, const QString &where);
|
||||
void applyExtraConfigs();
|
||||
VisitReturn visitProFile(ProFile *pro, QMakeHandler::EvalFileType type,
|
||||
LoadFlags flags);
|
||||
VisitReturn visitProBlock(ProFile *pro, const ushort *tokPtr);
|
||||
VisitReturn visitProBlock(const ushort *tokPtr);
|
||||
VisitReturn visitProLoop(const ProKey &variable, const ushort *exprPtr,
|
||||
const ushort *tokPtr);
|
||||
void visitProFunctionDef(ushort tok, const ProKey &name, const ushort *tokPtr);
|
||||
VisitReturn visitProVariable(ushort tok, const ProStringList &curr, const ushort *&tokPtr);
|
||||
|
||||
ALWAYS_INLINE const ProKey &map(const ProString &var) { return map(var.toKey()); }
|
||||
const ProKey &map(const ProKey &var);
|
||||
ProValueMap *findValues(const ProKey &variableName, ProValueMap::Iterator *it);
|
||||
|
||||
void setTemplate();
|
||||
|
||||
ProStringList split_value_list(QStringView vals, int source = 0);
|
||||
VisitReturn expandVariableReferences(const ushort *&tokPtr, int sizeHint, ProStringList *ret, bool joined);
|
||||
|
||||
QString currentFileName() const;
|
||||
QString currentDirectory() const;
|
||||
ProFile *currentProFile() const;
|
||||
int currentFileId() const;
|
||||
QString resolvePath(const QString &fileName) const
|
||||
{ return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); }
|
||||
QString filePathArg0(const ProStringList &args);
|
||||
QString filePathEnvArg0(const ProStringList &args);
|
||||
|
||||
VisitReturn evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type,
|
||||
LoadFlags flags);
|
||||
VisitReturn evaluateFileChecked(const QString &fileName, QMakeHandler::EvalFileType type,
|
||||
LoadFlags flags);
|
||||
VisitReturn evaluateFeatureFile(const QString &fileName, bool silent = false);
|
||||
VisitReturn evaluateFileInto(const QString &fileName,
|
||||
ProValueMap *values, // output-only
|
||||
LoadFlags flags);
|
||||
VisitReturn evaluateConfigFeatures();
|
||||
void message(int type, const QString &msg) const;
|
||||
void evalError(const QString &msg) const
|
||||
{ message(QMakeHandler::EvalError, msg); }
|
||||
void languageWarning(const QString &msg) const
|
||||
{ message(QMakeHandler::EvalWarnLanguage, msg); }
|
||||
void deprecationWarning(const QString &msg) const
|
||||
{ message(QMakeHandler::EvalWarnDeprecated, msg); }
|
||||
|
||||
VisitReturn prepareFunctionArgs(const ushort *&tokPtr, QList<ProStringList> *ret);
|
||||
VisitReturn evaluateFunction(const ProFunctionDef &func,
|
||||
const QList<ProStringList> &argumentsList, ProStringList *ret);
|
||||
VisitReturn evaluateBoolFunction(const ProFunctionDef &func,
|
||||
const QList<ProStringList> &argumentsList,
|
||||
const ProString &function);
|
||||
|
||||
VisitReturn evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr, ProStringList *ret);
|
||||
VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
|
||||
|
||||
VisitReturn evaluateBuiltinExpand(const QMakeInternal::QMakeBuiltin &adef,
|
||||
const ProKey &function, const ProStringList &args, ProStringList &ret);
|
||||
VisitReturn evaluateBuiltinConditional(const QMakeInternal::QMakeBuiltin &adef,
|
||||
const ProKey &function, const ProStringList &args);
|
||||
|
||||
VisitReturn evaluateConditional(QStringView cond, const QString &where, int line = -1);
|
||||
#ifdef PROEVALUATOR_FULL
|
||||
VisitReturn checkRequirements(const ProStringList &deps);
|
||||
#endif
|
||||
|
||||
void updateMkspecPaths();
|
||||
void updateFeaturePaths();
|
||||
|
||||
bool isActiveConfig(QStringView config, bool regex = false);
|
||||
|
||||
void populateDeps(
|
||||
const ProStringList &deps, const ProString &prefix, const ProStringList &suffixes,
|
||||
const ProString &priosfx,
|
||||
QHash<ProKey, QSet<ProKey> > &dependencies, ProValueMap &dependees,
|
||||
QMultiMap<int, ProString> &rootSet) const;
|
||||
|
||||
bool getMemberArgs(const ProKey &name, int srclen, const ProStringList &args,
|
||||
int *start, int *end);
|
||||
VisitReturn parseJsonInto(const QByteArray &json, const QString &into, ProValueMap *value);
|
||||
|
||||
VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
|
||||
QMakeVfs::VfsFlags flags, const QString &contents);
|
||||
#if QT_CONFIG(process)
|
||||
void runProcess(QProcess *proc, const QString &command) const;
|
||||
#endif
|
||||
QByteArray getCommandOutput(const QString &args, int *exitCode) const;
|
||||
|
||||
private:
|
||||
// Implementation detail of evaluateBuiltinConditional():
|
||||
VisitReturn testFunc_cache(const ProStringList &args);
|
||||
|
||||
public:
|
||||
QMakeEvaluator *m_caller;
|
||||
#ifdef PROEVALUATOR_CUMULATIVE
|
||||
bool m_cumulative;
|
||||
int m_skipLevel;
|
||||
#else
|
||||
enum { m_cumulative = 0 };
|
||||
enum { m_skipLevel = 0 };
|
||||
#endif
|
||||
|
||||
static QString quoteValue(const ProString &val);
|
||||
|
||||
#ifdef PROEVALUATOR_DEBUG
|
||||
void debugMsgInternal(int level, const char *fmt, ...) const;
|
||||
void traceMsgInternal(const char *fmt, ...) const;
|
||||
static QString formatValue(const ProString &val, bool forceQuote = false);
|
||||
static QString formatValueList(const ProStringList &vals, bool commas = false);
|
||||
static QString formatValueListList(const QList<ProStringList> &vals);
|
||||
|
||||
const int m_debugLevel;
|
||||
#else
|
||||
ALWAYS_INLINE void debugMsgInternal(int, const char *, ...) const {}
|
||||
ALWAYS_INLINE void traceMsgInternal(const char *, ...) const {}
|
||||
|
||||
enum { m_debugLevel = 0 };
|
||||
#endif
|
||||
|
||||
struct Location {
|
||||
Location() : pro(nullptr), line(0) {}
|
||||
Location(ProFile *_pro, ushort _line) : pro(_pro), line(_line) {}
|
||||
void clear() { pro = nullptr; line = 0; }
|
||||
ProFile *pro;
|
||||
ushort line;
|
||||
};
|
||||
|
||||
Location m_current; // Currently evaluated location
|
||||
QStack<Location> m_locationStack; // All execution location changes
|
||||
QStack<ProFile *> m_profileStack; // Includes only
|
||||
|
||||
ProValueMap m_extraVars;
|
||||
ProStringList m_extraConfigs;
|
||||
QString m_outputDir;
|
||||
|
||||
int m_listCount;
|
||||
int m_toggle;
|
||||
bool m_valuemapInited;
|
||||
bool m_hostBuild;
|
||||
QString m_qmakespec;
|
||||
QString m_qmakespecName;
|
||||
QString m_superfile;
|
||||
QString m_conffile;
|
||||
QString m_cachefile;
|
||||
QString m_stashfile;
|
||||
QString m_sourceRoot;
|
||||
QString m_buildRoot;
|
||||
QStringList m_qmakepath;
|
||||
QStringList m_qmakefeatures;
|
||||
QStringList m_mkspecPaths;
|
||||
QExplicitlySharedDataPointer<QMakeFeatureRoots> m_featureRoots;
|
||||
ProString m_dirSep;
|
||||
ProFunctionDefs m_functionDefs;
|
||||
ProStringList m_returnValue;
|
||||
ProValueMapStack m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.
|
||||
QString m_tmp1, m_tmp2, m_tmp3, m_tmp[2]; // Temporaries for efficient toQString
|
||||
|
||||
QMakeGlobals *m_option;
|
||||
QMakeParser *m_parser;
|
||||
QMakeHandler *m_handler;
|
||||
QMakeVfs *m_vfs;
|
||||
};
|
||||
Q_DECLARE_TYPEINFO(QMakeEvaluator::Location, Q_PRIMITIVE_TYPE);
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMAKEEVALUATOR_H
|
89
qmake/library/qmakeevaluator_p.h
Normal file
89
qmake/library/qmakeevaluator_p.h
Normal file
@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QMAKEEVALUATOR_P_H
|
||||
#define QMAKEEVALUATOR_P_H
|
||||
|
||||
#include "proitems.h"
|
||||
|
||||
#define debugMsg if (!m_debugLevel) {} else debugMsgInternal
|
||||
#define traceMsg if (!m_debugLevel) {} else traceMsgInternal
|
||||
#ifdef PROEVALUATOR_DEBUG
|
||||
# define dbgBool(b) (b ? "true" : "false")
|
||||
# define dbgReturn(r) \
|
||||
(r == ReturnError ? "error" : \
|
||||
r == ReturnBreak ? "break" : \
|
||||
r == ReturnNext ? "next" : \
|
||||
r == ReturnReturn ? "return" : \
|
||||
"<invalid>")
|
||||
# define dbgKey(s) s.toString().toQStringView().toLocal8Bit().constData()
|
||||
# define dbgStr(s) qPrintable(formatValue(s, true))
|
||||
# define dbgStrList(s) qPrintable(formatValueList(s))
|
||||
# define dbgSepStrList(s) qPrintable(formatValueList(s, true))
|
||||
# define dbgStrListList(s) qPrintable(formatValueListList(s))
|
||||
# define dbgQStr(s) dbgStr(ProString(s))
|
||||
#else
|
||||
# define dbgBool(b) 0
|
||||
# define dbgReturn(r) 0
|
||||
# define dbgKey(s) 0
|
||||
# define dbgStr(s) 0
|
||||
# define dbgStrList(s) 0
|
||||
# define dbgSepStrList(s) 0
|
||||
# define dbgStrListList(s) 0
|
||||
# define dbgQStr(s) 0
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QMakeInternal {
|
||||
|
||||
struct QMakeBuiltinInit
|
||||
{
|
||||
const char *name;
|
||||
int func;
|
||||
enum { VarArgs = 1000 };
|
||||
int min_args, max_args;
|
||||
const char *args;
|
||||
};
|
||||
|
||||
struct QMakeBuiltin
|
||||
{
|
||||
QMakeBuiltin(const QMakeBuiltinInit &data);
|
||||
QString usage;
|
||||
int index, minArgs, maxArgs;
|
||||
};
|
||||
|
||||
struct QMakeStatics {
|
||||
QString field_sep;
|
||||
QString strtrue;
|
||||
QString strfalse;
|
||||
ProKey strCONFIG;
|
||||
ProKey strARGS;
|
||||
ProKey strARGC;
|
||||
QString strDot;
|
||||
QString strDotDot;
|
||||
QString strever;
|
||||
QString strforever;
|
||||
QString strhost_build;
|
||||
ProKey strTEMPLATE;
|
||||
ProKey strQMAKE_PLATFORM;
|
||||
ProKey strQMAKE_DIR_SEP;
|
||||
ProKey strQMAKESPEC;
|
||||
#ifdef PROEVALUATOR_FULL
|
||||
ProKey strREQUIRES;
|
||||
#endif
|
||||
QHash<ProKey, QMakeBuiltin> expands;
|
||||
QHash<ProKey, QMakeBuiltin> functions;
|
||||
QHash<ProKey, ProKey> varMap;
|
||||
ProStringList fakeValue;
|
||||
};
|
||||
|
||||
extern QMakeStatics statics;
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_TYPEINFO(QMakeInternal::QMakeBuiltin, Q_RELOCATABLE_TYPE);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMAKEEVALUATOR_P_H
|
374
qmake/library/qmakeglobals.cpp
Normal file
374
qmake/library/qmakeglobals.cpp
Normal file
@ -0,0 +1,374 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#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 <qt_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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return value meanings:
|
||||
* ArgumentUnknown The argument at *pos was not handled by this function.
|
||||
* Leave it to the caller to handle this argument.
|
||||
* ArgumentMalformed There was an error detected.
|
||||
* ArgumentsOk All arguments were known. There are no arguments left to handle.
|
||||
*/
|
||||
QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
|
||||
QMakeCmdLineParserState &state, QStringList &args, int *pos)
|
||||
{
|
||||
enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache, ArgQtConf } argState = ArgNone;
|
||||
for (; *pos < args.size(); (*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 : std::as_const(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.size();
|
||||
int dstLen = dstpath.size();
|
||||
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.size() == source_root.size()
|
||||
|| fileName.at(source_root.size()) == QLatin1Char('/'))) {
|
||||
return build_root + fileName.mid(source_root.size());
|
||||
}
|
||||
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.size());
|
||||
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.size() < 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.size();
|
||||
}
|
||||
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
|
146
qmake/library/qmakeglobals.h
Normal file
146
qmake/library/qmakeglobals.h
Normal file
@ -0,0 +1,146 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QMAKEGLOBALS_H
|
||||
#define QMAKEGLOBALS_H
|
||||
|
||||
#include "qmake_global.h"
|
||||
#include "proitems.h"
|
||||
|
||||
#ifdef QT_BUILD_QMAKE
|
||||
# include <property.h>
|
||||
#endif
|
||||
|
||||
#include <qhash.h>
|
||||
#include <qstringlist.h>
|
||||
#if QT_CONFIG(process)
|
||||
# include <qprocess.h>
|
||||
#endif
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
# include <qmutex.h>
|
||||
# include <qwaitcondition.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMakeEvaluator;
|
||||
|
||||
enum QMakeEvalPhase { QMakeEvalEarly, QMakeEvalBefore, QMakeEvalAfter, QMakeEvalLate };
|
||||
|
||||
class QMakeBaseKey
|
||||
{
|
||||
public:
|
||||
QMakeBaseKey(const QString &_root, const QString &_stash, bool _hostBuild);
|
||||
|
||||
QString root;
|
||||
QString stash;
|
||||
bool hostBuild;
|
||||
};
|
||||
|
||||
size_t qHash(const QMakeBaseKey &key);
|
||||
bool operator==(const QMakeBaseKey &one, const QMakeBaseKey &two);
|
||||
|
||||
class QMakeBaseEnv
|
||||
{
|
||||
public:
|
||||
QMakeBaseEnv();
|
||||
~QMakeBaseEnv();
|
||||
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutex mutex;
|
||||
QWaitCondition cond;
|
||||
bool inProgress;
|
||||
// The coupling of this flag to thread safety exists because for other
|
||||
// use cases failure is immediately fatal anyway.
|
||||
bool isOk;
|
||||
#endif
|
||||
QMakeEvaluator *evaluator;
|
||||
};
|
||||
|
||||
class QMAKE_EXPORT QMakeCmdLineParserState
|
||||
{
|
||||
public:
|
||||
QMakeCmdLineParserState(const QString &_pwd) : pwd(_pwd), phase(QMakeEvalBefore) {}
|
||||
QString pwd;
|
||||
QStringList cmds[4], configs[4];
|
||||
QStringList extraargs;
|
||||
QMakeEvalPhase phase;
|
||||
|
||||
void flush() { phase = QMakeEvalBefore; }
|
||||
};
|
||||
|
||||
class QMAKE_EXPORT QMakeGlobals
|
||||
{
|
||||
public:
|
||||
QMakeGlobals();
|
||||
~QMakeGlobals();
|
||||
|
||||
bool do_cache;
|
||||
QString dir_sep;
|
||||
QString dirlist_sep;
|
||||
QString cachefile;
|
||||
#ifdef PROEVALUATOR_SETENV
|
||||
QProcessEnvironment environment;
|
||||
#endif
|
||||
QString qmake_abslocation;
|
||||
QStringList qmake_args, qmake_extra_args;
|
||||
|
||||
QString qtconf;
|
||||
QString qmakespec, xqmakespec;
|
||||
QString user_template, user_template_prefix;
|
||||
QString extra_cmds[4];
|
||||
|
||||
#ifdef PROEVALUATOR_DEBUG
|
||||
int debugLevel;
|
||||
#endif
|
||||
|
||||
enum ArgumentReturn { ArgumentUnknown, ArgumentMalformed, ArgumentsOk };
|
||||
ArgumentReturn addCommandLineArguments(QMakeCmdLineParserState &state,
|
||||
QStringList &args, int *pos);
|
||||
void commitCommandLineArguments(QMakeCmdLineParserState &state);
|
||||
void setCommandLineArguments(const QString &pwd, const QStringList &args);
|
||||
void useEnvironment();
|
||||
void setDirectories(const QString &input_dir, const QString &output_dir);
|
||||
#ifdef QT_BUILD_QMAKE
|
||||
void setQMakeProperty(QMakeProperty *prop) { property = prop; }
|
||||
void reloadProperties() { property->reload(); }
|
||||
ProString propertyValue(const ProKey &name) const { return property->value(name); }
|
||||
#else
|
||||
static void parseProperties(const QByteArray &data, QHash<ProKey, ProString> &props);
|
||||
# ifdef PROEVALUATOR_INIT_PROPS
|
||||
bool initProperties();
|
||||
# else
|
||||
void setProperties(const QHash<ProKey, ProString> &props) { properties = props; }
|
||||
# endif
|
||||
ProString propertyValue(const ProKey &name) const { return properties.value(name); }
|
||||
#endif
|
||||
|
||||
QString expandEnvVars(const QString &str) const;
|
||||
QString shadowedPath(const QString &fileName) const;
|
||||
QStringList splitPathList(const QString &value) const;
|
||||
|
||||
private:
|
||||
QString getEnv(const QString &) const;
|
||||
QStringList getPathListEnv(const QString &var) const;
|
||||
|
||||
QString cleanSpec(QMakeCmdLineParserState &state, const QString &spec);
|
||||
|
||||
QString source_root, build_root;
|
||||
|
||||
#ifdef QT_BUILD_QMAKE
|
||||
QMakeProperty *property;
|
||||
#else
|
||||
QHash<ProKey, ProString> properties;
|
||||
#endif
|
||||
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutex mutex;
|
||||
#endif
|
||||
QHash<QMakeBaseKey, QMakeBaseEnv *> baseEnvs;
|
||||
|
||||
friend class QMakeEvaluator;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMAKEGLOBALS_H
|
1550
qmake/library/qmakeparser.cpp
Normal file
1550
qmake/library/qmakeparser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
214
qmake/library/qmakeparser.h
Normal file
214
qmake/library/qmakeparser.h
Normal file
@ -0,0 +1,214 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QMAKEPARSER_H
|
||||
#define QMAKEPARSER_H
|
||||
|
||||
#include "qmake_global.h"
|
||||
#include "qmakevfs.h"
|
||||
#include "proitems.h"
|
||||
|
||||
#include <qhash.h>
|
||||
#include <qstack.h>
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
# include <qmutex.h>
|
||||
# include <qwaitcondition.h>
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QMAKE_EXPORT QMakeParserHandler
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
CategoryMask = 0xf00,
|
||||
InfoMessage = 0x100,
|
||||
WarningMessage = 0x200,
|
||||
ErrorMessage = 0x300,
|
||||
|
||||
SourceMask = 0xf0,
|
||||
SourceParser = 0,
|
||||
|
||||
CodeMask = 0xf,
|
||||
WarnLanguage = 0,
|
||||
WarnDeprecated,
|
||||
|
||||
ParserWarnLanguage = SourceParser | WarningMessage | WarnLanguage,
|
||||
ParserWarnDeprecated = SourceParser | WarningMessage | WarnDeprecated,
|
||||
|
||||
ParserIoError = ErrorMessage | SourceParser,
|
||||
ParserError
|
||||
};
|
||||
virtual void message(int type, const QString &msg,
|
||||
const QString &fileName = QString(), int lineNo = 0) = 0;
|
||||
};
|
||||
|
||||
class ProFileCache;
|
||||
class QMakeVfs;
|
||||
|
||||
class QMAKE_EXPORT QMakeParser
|
||||
{
|
||||
public:
|
||||
// Call this from a concurrency-free context
|
||||
static void initialize();
|
||||
|
||||
enum ParseFlag {
|
||||
ParseDefault = 0,
|
||||
ParseUseCache = 1,
|
||||
ParseReportMissing = 4,
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
ParseCumulative = 8
|
||||
#else
|
||||
ParseCumulative = 0
|
||||
#endif
|
||||
};
|
||||
Q_DECLARE_FLAGS(ParseFlags, ParseFlag)
|
||||
|
||||
QMakeParser(ProFileCache *cache, QMakeVfs *vfs, QMakeParserHandler *handler);
|
||||
|
||||
enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
|
||||
// fileName is expected to be absolute and cleanPath()ed.
|
||||
ProFile *parsedProFile(const QString &fileName, ParseFlags flags = ParseDefault);
|
||||
ProFile *parsedProBlock(QStringView contents, int id, const QString &name, int line = 0,
|
||||
SubGrammar grammar = FullGrammar);
|
||||
|
||||
void discardFileFromCache(int id);
|
||||
|
||||
#ifdef PROPARSER_DEBUG
|
||||
static QString formatProBlock(const QString &block);
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum ScopeNesting {
|
||||
NestNone = 0,
|
||||
NestLoop = 1,
|
||||
NestFunction = 2
|
||||
};
|
||||
|
||||
struct BlockScope {
|
||||
BlockScope() : start(nullptr), braceLevel(0), special(false), inBranch(false), nest(NestNone) {}
|
||||
ushort *start; // Where this block started; store length here
|
||||
int braceLevel; // Nesting of braces in scope
|
||||
bool special; // Single-line conditionals inside loops, etc. cannot have else branches
|
||||
bool inBranch; // The 'else' branch of the previous TokBranch is still open
|
||||
uchar nest; // Into what control structures we are nested
|
||||
};
|
||||
|
||||
enum ScopeState {
|
||||
StNew, // Fresh scope
|
||||
StCtrl, // Control statement (for or else) met on current line
|
||||
StCond // Conditionals met on current line
|
||||
};
|
||||
|
||||
enum Context { CtxTest, CtxValue, CtxPureValue, CtxArgs };
|
||||
struct ParseCtx {
|
||||
int parens; // Nesting of non-functional parentheses
|
||||
int argc; // Number of arguments in current function call
|
||||
int wordCount; // Number of words in current expression
|
||||
Context context;
|
||||
ushort quote; // Enclosing quote type
|
||||
ushort terminator; // '}' if replace function call is braced, ':' if test function
|
||||
};
|
||||
|
||||
bool readFile(int id, QMakeParser::ParseFlags flags, QString *contents);
|
||||
void read(ProFile *pro, QStringView content, int line, SubGrammar grammar);
|
||||
|
||||
ALWAYS_INLINE void putTok(ushort *&tokPtr, ushort tok);
|
||||
ALWAYS_INLINE void putBlockLen(ushort *&tokPtr, uint len);
|
||||
ALWAYS_INLINE void putBlock(ushort *&tokPtr, const ushort *buf, uint len);
|
||||
void putHashStr(ushort *&pTokPtr, const ushort *buf, uint len);
|
||||
void finalizeHashStr(ushort *buf, uint len);
|
||||
void putLineMarker(ushort *&tokPtr);
|
||||
ALWAYS_INLINE bool resolveVariable(ushort *xprPtr, int tlen, int needSep, ushort **ptr,
|
||||
ushort **buf, QString *xprBuff,
|
||||
ushort **tokPtr, QString *tokBuff,
|
||||
const ushort *cur, QStringView in);
|
||||
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
|
||||
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
|
||||
void warnOperator(const char *msg);
|
||||
bool failOperator(const char *msg);
|
||||
bool acceptColon(const char *msg);
|
||||
void putOperator(ushort *&tokPtr);
|
||||
void finalizeTest(ushort *&tokPtr);
|
||||
void bogusTest(ushort *&tokPtr, const QString &msg);
|
||||
void enterScope(ushort *&tokPtr, bool special, ScopeState state);
|
||||
void leaveScope(ushort *&tokPtr);
|
||||
void flushCond(ushort *&tokPtr);
|
||||
void flushScopes(ushort *&tokPtr);
|
||||
|
||||
void message(int type, const QString &msg) const;
|
||||
void parseError(const QString &msg) const
|
||||
{
|
||||
message(QMakeParserHandler::ParserError, msg);
|
||||
m_proFile->setOk(false);
|
||||
}
|
||||
void languageWarning(const QString &msg) const
|
||||
{ message(QMakeParserHandler::ParserWarnLanguage, msg); }
|
||||
void deprecationWarning(const QString &msg) const
|
||||
{ message(QMakeParserHandler::ParserWarnDeprecated, msg); }
|
||||
|
||||
// Current location
|
||||
ProFile *m_proFile;
|
||||
int m_lineNo;
|
||||
|
||||
QStack<BlockScope> m_blockstack;
|
||||
ScopeState m_state;
|
||||
int m_markLine; // Put marker for this line
|
||||
bool m_inError; // Current line had a parsing error; suppress followup error messages
|
||||
bool m_canElse; // Conditionals met on previous line, but no scope was opened
|
||||
int m_invert; // Pending conditional is negated
|
||||
enum { NoOperator, AndOperator, OrOperator } m_operator; // Pending conditional is ORed/ANDed
|
||||
|
||||
QString m_tmp; // Temporary for efficient toQString
|
||||
|
||||
ProFileCache *m_cache;
|
||||
QMakeParserHandler *m_handler;
|
||||
QMakeVfs *m_vfs;
|
||||
|
||||
// This doesn't help gcc 3.3 ...
|
||||
template<typename T> friend class QTypeInfo;
|
||||
|
||||
friend class ProFileCache;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeParser::ParseFlags)
|
||||
|
||||
class QMAKE_EXPORT ProFileCache
|
||||
{
|
||||
public:
|
||||
ProFileCache();
|
||||
~ProFileCache();
|
||||
|
||||
void discardFile(int id);
|
||||
void discardFile(const QString &fileName, QMakeVfs *vfs);
|
||||
void discardFiles(const QString &prefix, QMakeVfs *vfs);
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
ProFile *pro;
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
struct Locker {
|
||||
Locker() : waiters(0), done(false) {}
|
||||
QWaitCondition cond;
|
||||
int waiters;
|
||||
bool done;
|
||||
};
|
||||
Locker *locker;
|
||||
#endif
|
||||
};
|
||||
|
||||
QHash<int, Entry> parsed_files;
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutex mutex;
|
||||
#endif
|
||||
|
||||
friend class QMakeParser;
|
||||
};
|
||||
|
||||
#if !defined(__GNUC__) || __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
|
||||
Q_DECLARE_TYPEINFO(QMakeParser::BlockScope, Q_RELOCATABLE_TYPE);
|
||||
Q_DECLARE_TYPEINFO(QMakeParser::Context, Q_PRIMITIVE_TYPE);
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // PROFILEPARSER_H
|
257
qmake/library/qmakevfs.cpp
Normal file
257
qmake/library/qmakevfs.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qmakevfs.h"
|
||||
|
||||
#include "ioutils.h"
|
||||
using namespace QMakeInternal;
|
||||
|
||||
#include <qdir.h>
|
||||
#include <qfile.h>
|
||||
#include <qfileinfo.h>
|
||||
|
||||
#define fL1S(s) QString::fromLatin1(s)
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QMakeVfs::QMakeVfs()
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
: m_magicMissing(fL1S("missing"))
|
||||
, m_magicExisting(fL1S("existing"))
|
||||
#endif
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
QMakeVfs::~QMakeVfs()
|
||||
{
|
||||
deref();
|
||||
}
|
||||
|
||||
void QMakeVfs::ref()
|
||||
{
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&s_mutex);
|
||||
#endif
|
||||
++s_refCount;
|
||||
}
|
||||
|
||||
void QMakeVfs::deref()
|
||||
{
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&s_mutex);
|
||||
#endif
|
||||
if (!--s_refCount) {
|
||||
s_fileIdCounter = 0;
|
||||
s_fileIdMap.clear();
|
||||
s_idFileMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutex QMakeVfs::s_mutex;
|
||||
#endif
|
||||
int QMakeVfs::s_refCount;
|
||||
QAtomicInt QMakeVfs::s_fileIdCounter;
|
||||
QHash<QString, int> QMakeVfs::s_fileIdMap;
|
||||
QHash<int, QString> QMakeVfs::s_idFileMap;
|
||||
|
||||
int QMakeVfs::idForFileName(const QString &fn, VfsFlags flags)
|
||||
{
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
{
|
||||
# ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&m_vmutex);
|
||||
# endif
|
||||
int idx = (flags & VfsCumulative) ? 1 : 0;
|
||||
if (flags & VfsCreate) {
|
||||
int &id = m_virtualFileIdMap[idx][fn];
|
||||
if (!id) {
|
||||
id = ++s_fileIdCounter;
|
||||
m_virtualIdFileMap[id] = fn;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
int id = m_virtualFileIdMap[idx].value(fn);
|
||||
if (id || (flags & VfsCreatedOnly))
|
||||
return id;
|
||||
}
|
||||
#endif
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&s_mutex);
|
||||
#endif
|
||||
if (!(flags & VfsAccessedOnly)) {
|
||||
int &id = s_fileIdMap[fn];
|
||||
if (!id) {
|
||||
id = ++s_fileIdCounter;
|
||||
s_idFileMap[id] = fn;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
return s_fileIdMap.value(fn);
|
||||
}
|
||||
|
||||
QString QMakeVfs::fileNameForId(int id)
|
||||
{
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
{
|
||||
# ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&m_vmutex);
|
||||
# endif
|
||||
const QString &fn = m_virtualIdFileMap.value(id);
|
||||
if (!fn.isEmpty())
|
||||
return fn;
|
||||
}
|
||||
#endif
|
||||
#ifdef PROPARSER_THREAD_SAFE
|
||||
QMutexLocker locker(&s_mutex);
|
||||
#endif
|
||||
return s_idFileMap.value(id);
|
||||
}
|
||||
|
||||
bool QMakeVfs::writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags,
|
||||
const QString &contents, QString *errStr)
|
||||
{
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
QString *cont = &m_files[id];
|
||||
Q_UNUSED(flags);
|
||||
if (mode & QIODevice::Append)
|
||||
*cont += contents;
|
||||
else
|
||||
*cont = contents;
|
||||
Q_UNUSED(errStr);
|
||||
return true;
|
||||
#else
|
||||
QFileInfo qfi(fileNameForId(id));
|
||||
if (!QDir::current().mkpath(qfi.path())) {
|
||||
*errStr = fL1S("Cannot create parent directory");
|
||||
return false;
|
||||
}
|
||||
QByteArray bytes = contents.toLocal8Bit();
|
||||
QFile cfile(qfi.filePath());
|
||||
if (!(mode & QIODevice::Append) && cfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
if (cfile.readAll() == bytes) {
|
||||
if (flags & VfsExecutable) {
|
||||
cfile.setPermissions(cfile.permissions()
|
||||
| QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
|
||||
} else {
|
||||
cfile.setPermissions(cfile.permissions()
|
||||
& ~(QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
cfile.close();
|
||||
}
|
||||
if (!cfile.open(mode | QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
*errStr = cfile.errorString();
|
||||
return false;
|
||||
}
|
||||
cfile.write(bytes);
|
||||
cfile.close();
|
||||
if (cfile.error() != QFile::NoError) {
|
||||
*errStr = cfile.errorString();
|
||||
return false;
|
||||
}
|
||||
if (flags & VfsExecutable)
|
||||
cfile.setPermissions(cfile.permissions()
|
||||
| QFile::ExeUser | QFile::ExeGroup | QFile::ExeOther);
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
QMakeVfs::ReadResult QMakeVfs::readFile(int id, QString *contents, QString *errStr)
|
||||
{
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
auto it = m_files.constFind(id);
|
||||
if (it != m_files.constEnd()) {
|
||||
if (it->constData() == m_magicMissing.constData()) {
|
||||
*errStr = fL1S("No such file or directory");
|
||||
return ReadNotFound;
|
||||
}
|
||||
if (it->constData() != m_magicExisting.constData()) {
|
||||
*contents = *it;
|
||||
return ReadOk;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
QFile file(fileNameForId(id));
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
if (!file.exists()) {
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
m_files[id] = m_magicMissing;
|
||||
#endif
|
||||
*errStr = fL1S("No such file or directory");
|
||||
return ReadNotFound;
|
||||
}
|
||||
*errStr = file.errorString();
|
||||
return ReadOtherError;
|
||||
}
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
m_files[id] = m_magicExisting;
|
||||
#endif
|
||||
|
||||
QByteArray bcont = file.readAll();
|
||||
if (bcont.startsWith("\xef\xbb\xbf")) {
|
||||
// UTF-8 BOM will cause subtle errors
|
||||
*errStr = fL1S("Unexpected UTF-8 BOM");
|
||||
return ReadOtherError;
|
||||
}
|
||||
*contents = QString::fromLocal8Bit(bcont);
|
||||
return ReadOk;
|
||||
}
|
||||
|
||||
bool QMakeVfs::exists(const QString &fn, VfsFlags flags)
|
||||
{
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
int id = idForFileName(fn, flags);
|
||||
auto it = m_files.constFind(id);
|
||||
if (it != m_files.constEnd())
|
||||
return it->constData() != m_magicMissing.constData();
|
||||
#else
|
||||
Q_UNUSED(flags);
|
||||
#endif
|
||||
bool ex = IoUtils::fileType(fn) == IoUtils::FileIsRegular;
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
m_files[id] = ex ? m_magicExisting : m_magicMissing;
|
||||
#endif
|
||||
return ex;
|
||||
}
|
||||
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
// This should be called when the sources may have changed (e.g., VCS update).
|
||||
void QMakeVfs::invalidateCache()
|
||||
{
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
auto it = m_files.begin(), eit = m_files.end();
|
||||
while (it != eit) {
|
||||
if (it->constData() == m_magicMissing.constData()
|
||||
||it->constData() == m_magicExisting.constData())
|
||||
it = m_files.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
// This should be called when generated files may have changed (e.g., actual build).
|
||||
void QMakeVfs::invalidateContents()
|
||||
{
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutexLocker locker(&m_mutex);
|
||||
# endif
|
||||
m_files.clear();
|
||||
}
|
||||
#endif
|
||||
|
||||
QT_END_NAMESPACE
|
105
qmake/library/qmakevfs.h
Normal file
105
qmake/library/qmakevfs.h
Normal file
@ -0,0 +1,105 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QMAKEVFS_H
|
||||
#define QMAKEVFS_H
|
||||
|
||||
#include "qmake_global.h"
|
||||
|
||||
#include <qiodevice.h>
|
||||
#include <qhash.h>
|
||||
#include <qstring.h>
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
# include <qmutex.h>
|
||||
#endif
|
||||
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
# ifndef PROEVALUATOR_CUMULATIVE
|
||||
# error PROEVALUATOR_DUAL_VFS requires PROEVALUATOR_CUMULATIVE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class QMAKE_EXPORT QMakeVfs
|
||||
{
|
||||
public:
|
||||
enum ReadResult {
|
||||
ReadOk,
|
||||
ReadNotFound,
|
||||
ReadOtherError
|
||||
};
|
||||
|
||||
enum VfsFlag {
|
||||
VfsExecutable = 1,
|
||||
VfsExact = 0,
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
VfsCumulative = 2,
|
||||
VfsCreate = 4,
|
||||
VfsCreatedOnly = 8,
|
||||
#else
|
||||
VfsCumulative = 0,
|
||||
VfsCreate = 0,
|
||||
VfsCreatedOnly = 0,
|
||||
#endif
|
||||
VfsAccessedOnly = 16
|
||||
};
|
||||
Q_DECLARE_FLAGS(VfsFlags, VfsFlag)
|
||||
|
||||
QMakeVfs();
|
||||
~QMakeVfs();
|
||||
|
||||
static void ref();
|
||||
static void deref();
|
||||
|
||||
int idForFileName(const QString &fn, VfsFlags flags);
|
||||
QString fileNameForId(int id);
|
||||
bool writeFile(int id, QIODevice::OpenMode mode, VfsFlags flags, const QString &contents, QString *errStr);
|
||||
ReadResult readFile(int id, QString *contents, QString *errStr);
|
||||
bool exists(const QString &fn, QMakeVfs::VfsFlags flags);
|
||||
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
void invalidateCache();
|
||||
void invalidateContents();
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef PROEVALUATOR_THREAD_SAFE
|
||||
static QMutex s_mutex;
|
||||
#endif
|
||||
static int s_refCount;
|
||||
static QAtomicInt s_fileIdCounter;
|
||||
// Qt Creator's ProFile cache is a singleton to maximize its cross-project
|
||||
// effectiveness (shared prf files from QtVersions).
|
||||
// For this to actually work, real files need a global mapping.
|
||||
// This is fine, because the namespace of real files is indeed global.
|
||||
static QHash<QString, int> s_fileIdMap;
|
||||
static QHash<int, QString> s_idFileMap;
|
||||
#ifdef PROEVALUATOR_DUAL_VFS
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
// The simple way to avoid recursing m_mutex.
|
||||
QMutex m_vmutex;
|
||||
# endif
|
||||
// Virtual files are bound to the project context they were created in,
|
||||
// so their ids need to be local as well.
|
||||
// We violate that rule in lupdate (which has a non-dual VFS), but that
|
||||
// does not matter, because it has only one project context anyway.
|
||||
QHash<QString, int> m_virtualFileIdMap[2]; // Exact and cumulative
|
||||
QHash<int, QString> m_virtualIdFileMap; // Only one map, as ids are unique across realms.
|
||||
#endif
|
||||
|
||||
#ifndef PROEVALUATOR_FULL
|
||||
# ifdef PROEVALUATOR_THREAD_SAFE
|
||||
QMutex m_mutex;
|
||||
# endif
|
||||
QHash<int, QString> m_files;
|
||||
QString m_magicMissing;
|
||||
QString m_magicExisting;
|
||||
#endif
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeVfs::VfsFlags)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QMAKEVFS_H
|
133
qmake/library/registry.cpp
Normal file
133
qmake/library/registry.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <QtCore/qstringlist.h>
|
||||
#include "registry_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
/*
|
||||
Returns the path part of a registry key.
|
||||
e.g.
|
||||
For a key
|
||||
"Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"
|
||||
it returns
|
||||
"Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\"
|
||||
*/
|
||||
static QString keyPath(const QString &rKey)
|
||||
{
|
||||
int idx = rKey.lastIndexOf(QLatin1Char('\\'));
|
||||
if (idx == -1)
|
||||
return QString();
|
||||
return rKey.left(idx + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
Returns the name part of a registry key.
|
||||
e.g.
|
||||
For a key
|
||||
"Software\\Microsoft\\VisualStudio\\8.0\\Setup\\VC\\ProductDir"
|
||||
it returns
|
||||
"ProductDir"
|
||||
*/
|
||||
static QString keyName(const QString &rKey)
|
||||
{
|
||||
int idx = rKey.lastIndexOf(QLatin1Char('\\'));
|
||||
if (idx == -1)
|
||||
return rKey;
|
||||
|
||||
QString res(rKey.mid(idx + 1));
|
||||
if (res == QLatin1String("Default") || res == QLatin1String("."))
|
||||
res = QString();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey, unsigned long options)
|
||||
{
|
||||
QString result;
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
QString rSubkeyName = keyName(rSubkey);
|
||||
QString rSubkeyPath = keyPath(rSubkey);
|
||||
|
||||
HKEY handle = nullptr;
|
||||
LONG res = RegOpenKeyEx(parentHandle, (wchar_t*)rSubkeyPath.utf16(), 0,
|
||||
KEY_READ | options, &handle);
|
||||
|
||||
if (res != ERROR_SUCCESS)
|
||||
return QString();
|
||||
|
||||
// get the size and type of the value
|
||||
DWORD dataType;
|
||||
DWORD dataSize;
|
||||
res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, &dataType, nullptr, &dataSize);
|
||||
if (res != ERROR_SUCCESS) {
|
||||
RegCloseKey(handle);
|
||||
return QString();
|
||||
}
|
||||
|
||||
// get the value
|
||||
QByteArray data(dataSize, 0);
|
||||
res = RegQueryValueEx(handle, (wchar_t*)rSubkeyName.utf16(), nullptr, nullptr,
|
||||
reinterpret_cast<unsigned char*>(data.data()), &dataSize);
|
||||
if (res != ERROR_SUCCESS) {
|
||||
RegCloseKey(handle);
|
||||
return QString();
|
||||
}
|
||||
|
||||
switch (dataType) {
|
||||
case REG_EXPAND_SZ:
|
||||
case REG_SZ: {
|
||||
result = QString::fromWCharArray(((const wchar_t *)data.constData()));
|
||||
break;
|
||||
}
|
||||
|
||||
case REG_MULTI_SZ: {
|
||||
QStringList l;
|
||||
int i = 0;
|
||||
for (;;) {
|
||||
QString s = QString::fromWCharArray((const wchar_t *)data.constData() + i);
|
||||
i += s.length() + 1;
|
||||
|
||||
if (s.isEmpty())
|
||||
break;
|
||||
l.append(s);
|
||||
}
|
||||
result = l.join(QLatin1String(", "));
|
||||
break;
|
||||
}
|
||||
|
||||
case REG_NONE:
|
||||
case REG_BINARY: {
|
||||
result = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
|
||||
break;
|
||||
}
|
||||
|
||||
case REG_DWORD_BIG_ENDIAN:
|
||||
case REG_DWORD: {
|
||||
Q_ASSERT(data.size() == sizeof(int));
|
||||
int i;
|
||||
memcpy((char*)&i, data.constData(), sizeof(int));
|
||||
result = QString::number(i);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
qWarning("QSettings: unknown data %u type in windows registry", quint32(dataType));
|
||||
break;
|
||||
}
|
||||
|
||||
RegCloseKey(handle);
|
||||
#else
|
||||
Q_UNUSED(parentHandle);
|
||||
Q_UNUSED(rSubkey);
|
||||
Q_UNUSED(options);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
48
qmake/library/registry_p.h
Normal file
48
qmake/library/registry_p.h
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2016 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#ifndef QT_WINDOWS_REGISTRY_H
|
||||
#define QT_WINDOWS_REGISTRY_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
#include <QtCore/qt_windows.h>
|
||||
#else
|
||||
typedef void* HKEY;
|
||||
#endif
|
||||
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
/**
|
||||
* Read a value from the Windows registry.
|
||||
*
|
||||
* If the key is not found, or the registry cannot be accessed (for example
|
||||
* if this code is compiled for a platform other than Windows), a null
|
||||
* string is returned.
|
||||
*
|
||||
* 32-bit code reads from the registry's 32 bit view (Wow6432Node),
|
||||
* 64 bit code reads from the 64 bit view.
|
||||
* Pass KEY_WOW64_32KEY to access the 32 bit view regardless of the
|
||||
* application's architecture, KEY_WOW64_64KEY respectively.
|
||||
*/
|
||||
QString qt_readRegistryKey(HKEY parentHandle, const QString &rSubkey,
|
||||
unsigned long options = 0);
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QT_WINDOWS_REGISTRY_H
|
||||
|
Reference in New Issue
Block a user