port qmake to qt creator's qmake language evaluator

this is a monster commit which does the following things:
- import the evaluator as-is from qt creator into qmake/library/
  - integrate it into qmake's makefiles
  - overwrite proitems.h with actual special types
- remove the parts of Option which are redundant with QMakeGlobals
- make QMakeProperty a singleton owned by Option::globals. the dynamic
  handling so far made no sense.
- make QMakeProject a subclass of QMakeEvaluator, with relatively few
  extensions

the changes to existing qmake code outside project.* and option.* are
minor. implementing the changes gradually would mean changing a lot of
code which will be just replaced in the next commit, so i'm not wasting
my time on it.

Change-Id: I9746650423b8c5b3fbd8c3979a73228982a46195
Reviewed-by: Qt Doc Bot <qt_docbot@qt-project.org>
Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com>
This commit is contained in:
Oswald Buddenhagen 2012-09-05 18:29:19 +02:00 committed by Qt by Nokia
parent ed7594db5d
commit 0e78e50802
28 changed files with 7252 additions and 4102 deletions

View File

@ -11,8 +11,10 @@ QMKLIBSRC = $(QMKSRC)/library
QMKGENSRC = $(QMKSRC)/generators
#qmake code
OBJS=project.o property.o main.o makefile.o unixmake2.o unixmake.o \
mingw_make.o option.o winmakefile.o projectgenerator.o \
OBJS=project.o option.o property.o main.o ioutils.o proitems.o \
qmakeglobals.o qmakeparser.o qmakeevaluator.o qmakebuiltins.o \
makefile.o unixmake2.o unixmake.o \
mingw_make.o winmakefile.o projectgenerator.o \
meta.o makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \
msvc_vcproj.o msvc_vcxproj.o msvc_nmake.o msvc_objectmodel.o msbuild_objectmodel.o \
gbuild.o cesdkhandler.o
@ -36,6 +38,8 @@ QOBJS=qtextcodec.o qutfcodec.o qstring.o qstringbuilder.o qtextstream.o qiodevic
DEPEND_SRC = \
$(QMKSRC)/main.cpp $(QMKSRC)/project.cpp $(QMKSRC)/option.cpp $(QMKSRC)/property.cpp \
$(QMKSRC)/meta.cpp \
$(QMKLIBSRC)/ioutils.cpp $(QMKLIBSRC)/proitems.cpp $(QMKLIBSRC)/qmakeglobals.cpp \
$(QMKLIBSRC)/qmakeparser.cpp $(QMKLIBSRC)/qmakeevaluator.cpp $(QMKLIBSRC)/qmakebuiltins.cpp \
$(QMKGENSRC)/makefiledeps.cpp $(QMKGENSRC)/metamakefile.cpp \
$(QMKGENSRC)/projectgenerator.cpp $(QMKGENSRC)/makefile.cpp \
$(QMKGENSRC)/unix/unixmake.cpp $(QMKGENSRC)/unix/unixmake2.cpp \
@ -90,7 +94,7 @@ CPPFLAGS = -g $(OPENSOURCE_CXXFLAGS) \
-I$(BUILD_PATH)/src/corelib/global -DHAVE_QCONFIG_CPP \
-I$(QMAKESPEC) \
-I$(SOURCE_PATH)/tools/shared \
-DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED \
-DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL -DPROEVALUATOR_DEBUG \
-DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_NO_COMPONENT -DQT_NO_COMPRESS \
-DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM
@ -112,6 +116,24 @@ depend:
makedepend -D__MAKEDEPEND__ $(CPPFLAGS) $(DEPEND_SRC)
ioutils.o: $(QMKLIBSRC)/ioutils.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
proitems.o: $(QMKLIBSRC)/proitems.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qmakeglobals.o: $(QMKLIBSRC)/qmakeglobals.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qmakeparser.o: $(QMKLIBSRC)/qmakeparser.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qmakeevaluator.o: $(QMKLIBSRC)/qmakeevaluator.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qmakebuiltins.o: $(QMKLIBSRC)/qmakebuiltins.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
project.o: $(QMKSRC)/project.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<

View File

@ -38,7 +38,7 @@ CFLAGS_BARE = -c -Fo./ \
-I$(BUILD_PATH)\src\corelib\global -DHAVE_QCONFIG_CPP \
-I$(SOURCE_PATH)\mkspecs\$(QMAKESPEC) \
-I$(SOURCE_PATH)\tools\shared \
-DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED \
-DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL -DPROEVALUATOR_DEBUG \
-DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_NO_COMPONENT -DQT_NO_COMPRESS \
-DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM \
-DUNICODE
@ -57,7 +57,9 @@ ADDCLEAN = vc60.pdb vc70.pdb qmake.pdb qmake.ilk
!ENDIF
#qmake code
OBJS = project.obj main.obj makefile.obj unixmake.obj unixmake2.obj mingw_make.obj \
OBJS = project.obj main.obj ioutils.obj proitems.obj \
qmakeglobals.obj qmakeparser.obj qmakeevaluator.obj qmakebuiltins.obj \
makefile.obj unixmake.obj unixmake2.obj mingw_make.obj \
option.obj winmakefile.obj projectgenerator.obj property.obj meta.obj \
makefiledeps.obj metamakefile.obj xmloutput.obj pbuilder_pbx.obj \
msvc_nmake.obj msvc_vcproj.obj msvc_vcxproj.obj \
@ -164,6 +166,9 @@ $(QTOBJS): qmake_pch.obj
qmake_pch.obj:
$(CXX) $(CXXFLAGS_BARE) -c -Yc -Fpqmake_pch.pch -TP $(QMKSRC)\qmake_pch.h
{$(SOURCE_PATH)\qmake\library}.cpp{}.obj::
$(CXX) $(CXXFLAGS) $<
{$(SOURCE_PATH)\qmake\generators\mac}.cpp{}.obj::
$(CXX) $(CXXFLAGS) $<

View File

@ -49,7 +49,7 @@ CFLAGS = -c -o$@ -O \
-I$(BUILD_PATH)/src/corelib/global -DHAVE_QCONFIG_CPP \
-I$(SOURCE_PATH)/mkspecs/win32-g++ \
-I$(SOURCE_PATH)/tools/shared \
-DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED \
-DQT_BUILD_QMAKE -DQT_BOOTSTRAPPED -DPROEVALUATOR_FULL -DPROEVALUATOR_DEBUG \
-DQT_NO_TEXTCODEC -DQT_NO_UNICODETABLES -DQT_NO_COMPONENT -DQT_NO_COMPRESS \
-DQT_NO_THREAD -DQT_NO_QOBJECT -DQT_NO_GEOM_VARIANT -DQT_NO_DATASTREAM \
-DUNICODE
@ -61,7 +61,9 @@ ADDCLEAN =
#qmake code
OBJS = project.o main.o makefile.o unixmake.o unixmake2.o mingw_make.o \
OBJS = project.o main.o ioutils.o proitems.o \
qmakeglobals.o qmakeparser.o qmakeevaluator.o qmakebuiltins.o \
makefile.o unixmake.o unixmake2.o mingw_make.o \
option.o winmakefile.o projectgenerator.o property.o meta.o \
makefiledeps.o metamakefile.o xmloutput.o pbuilder_pbx.o \
msvc_nmake.o msvc_vcproj.o msvc_vcxproj.o \
@ -149,7 +151,7 @@ distclean:: clean
$(CXX) $(CXXFLAGS) $<
QTVPATH = $(TOOLSRC)/shared/windows:$(CORESRC)/global:$(CORESRC)/kernel:$(CORESRC)/tools:$(CORESRC)/codecs:$(CORESRC)/io:$(CORESRC)/xml:$(CORESRC)/plugin:$(BUILD_PATH)/src/corelib/global
VPATH = $(QMKSRC):$(QMKSRC)/generators:$(QMKSRC)/generators/unix:$(QMKSRC)/generators/mac:$(QMKSRC)/generators/win32:$(QMKSRC)/generators/integrity:$(QTVPATH)
VPATH = $(QMKSRC):$(QMKLIBSRC):$(QMKSRC)/generators:$(QMKSRC)/generators/unix:$(QMKSRC)/generators/mac:$(QMKSRC)/generators/win32:$(QMKSRC)/generators/integrity:$(QTVPATH)
project.o: $(QMKSRC)/project.h $(QMKSRC)/option.h
meta.o: $(QMKSRC)/project.h $(QMKSRC)/option.h

View File

@ -194,7 +194,7 @@ MakefileGenerator::initOutPaths()
ProValueMap &v = project->variables();
//for shadow builds
if(!v.contains("QMAKE_ABSOLUTE_SOURCE_PATH")) {
if (Option::mkfile::do_cache && !project->cacheFile().isEmpty() &&
if (Option::globals->do_cache && !project->cacheFile().isEmpty() &&
v.contains("QMAKE_ABSOLUTE_SOURCE_ROOT")) {
QString root = v["QMAKE_ABSOLUTE_SOURCE_ROOT"].first().toQString();
root = QDir::fromNativeSeparators(root);
@ -884,7 +884,7 @@ MakefileGenerator::init()
// escape qmake command
project->values("QMAKE_QMAKE") =
ProStringList(escapeFilePath(Option::fixPathToTargetOS(Option::qmake_abslocation, false)));
ProStringList(escapeFilePath(Option::fixPathToTargetOS(Option::globals->qmake_abslocation, false)));
}
bool
@ -2682,7 +2682,7 @@ MakefileGenerator::writeMakeQmake(QTextStream &t, bool noDummyQmakeAll)
if(!ofile.isEmpty() && !project->isActiveConfig("no_autoqmake")) {
t << escapeFilePath(ofile) << ": "
<< escapeDependencyPath(fileFixify(project->projectFile())) << " ";
if (Option::mkfile::do_cache) {
if (Option::globals->do_cache) {
if (!project->confFile().isEmpty())
t << escapeDependencyPath(fileFixify(project->confFile())) << " ";
if (!project->cacheFile().isEmpty())

View File

@ -235,7 +235,7 @@ MakefileGenerator
basevars["BUILD_NAME"] = (buildname.isEmpty() ? ProStringList(build) : buildname);
//create project
QMakeProject *build_proj = new QMakeProject(project->properties());
QMakeProject *build_proj = new QMakeProject;
build_proj->setExtraVars(basevars);
build_proj->setExtraConfigs(basecfgs);
@ -317,7 +317,7 @@ SubdirsMetaMakefileGenerator::init()
}
//handle sub project
QMakeProject *sub_proj = new QMakeProject(project->properties());
QMakeProject *sub_proj = new QMakeProject;
for (int ind = 0; ind < sub->indent; ++ind)
printf(" ");
sub->input_dir = subdir.absolutePath();

View File

@ -76,14 +76,17 @@ ProjectGenerator::init()
init_flag = true;
verifyCompilers();
project->read(QMakeProject::ReadFeatures);
project->loadSpec();
project->evaluateFeatureFile("default_pre.prf");
project->evaluateFeatureFile("default_post.prf");
project->evaluateConfigFeatures();
project->values("CONFIG").clear();
Option::postProcessProject(project);
ProValueMap &v = project->variables();
QString templ = Option::user_template.isEmpty() ? QString("app") : Option::user_template;
if(!Option::user_template_prefix.isEmpty())
templ.prepend(Option::user_template_prefix);
QString templ = Option::globals->user_template.isEmpty() ? QString("app") : Option::globals->user_template;
if (!Option::globals->user_template_prefix.isEmpty())
templ.prepend(Option::globals->user_template_prefix);
v["TEMPLATE_ASSIGN"] += templ;
//the scary stuff
@ -344,9 +347,8 @@ ProjectGenerator::writeMakefile(QTextStream &t)
t << "######################################################################" << endl;
t << "# Automatically generated by qmake (" << qmake_version() << ") " << QDateTime::currentDateTime().toString() << endl;
t << "######################################################################" << endl << endl;
int i;
for(i = 0; i < Option::before_user_vars.size(); ++i)
t << Option::before_user_vars[i] << endl;
if (!Option::globals->precmds.isEmpty())
t << Option::globals->precmds << endl;
t << getWritableVar("TEMPLATE_ASSIGN", false);
if(project->first("TEMPLATE_ASSIGN") == "subdirs") {
t << endl << "# Directories" << "\n"
@ -373,8 +375,8 @@ ProjectGenerator::writeMakefile(QTextStream &t)
<< getWritableVar("RESOURCES")
<< getWritableVar("TRANSLATIONS");
}
for(i = 0; i < Option::after_user_vars.size(); ++i)
t << Option::after_user_vars[i] << endl;
if (!Option::globals->postcmds.isEmpty())
t << Option::globals->postcmds << endl;
return true;
}

View File

@ -442,8 +442,8 @@ void VcprojGenerator::writeSubDirs(QTextStream &t)
// Make sure that all temp projects are configured
// for release so that the depends are created
// without the debug <lib>dxxx.lib name mangling
QStringList old_after_vars = Option::after_user_vars;
Option::after_user_vars.append("CONFIG+=release");
QString old_after_vars = Option::globals->postcmds;
Option::globals->postcmds.append("\nCONFIG+=release");
QStringList subdirs = collectSubDirs(project);
for(int i = 0; i < subdirs.size(); ++i) {
@ -627,7 +627,7 @@ nextfile:
t << _slnProjDepBeg;
// Restore previous after_user_var options
Option::after_user_vars = old_after_vars;
Option::globals->postcmds = old_after_vars;
// Figure out dependencies
for(QList<VcsolutionDepend*>::Iterator it = solution_cleanup.begin(); it != solution_cleanup.end(); ++it) {

168
qmake/library/ioutils.cpp Normal file
View File

@ -0,0 +1,168 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "ioutils.h"
#include <qdir.h>
#include <qfile.h>
#ifdef Q_OS_WIN
# include <windows.h>
#else
# include <sys/types.h>
# include <sys/stat.h>
# include <unistd.h>
#endif
QT_BEGIN_NAMESPACE
using namespace QMakeInternal;
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 : FileIsRegular;
#endif
}
bool IoUtils::isRelativePath(const QString &path)
{
if (path.startsWith(QLatin1Char('/')))
return false;
#ifdef Q_OS_WIN
if (path.startsWith(QLatin1Char('\\')))
return false;
// Unlike QFileInfo, this won't accept a relative path with a drive letter.
// Such paths result in a royal mess anyway ...
if (path.length() >= 3 && path.at(1) == QLatin1Char(':') && path.at(0).isLetter()
&& (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\')))
return false;
#endif
return true;
}
QStringRef IoUtils::fileName(const QString &fileName)
{
return fileName.midRef(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);
return QDir::cleanPath(baseDir + QLatin1Char('/') + fileName);
}
inline static
bool hasSpecialChars(const QString &arg, const uchar (&iqm)[16])
{
for (int x = arg.length() - 1; x >= 0; --x) {
ushort c = arg.unicode()[x].unicode();
if ((c < sizeof(iqm) * 8) && (iqm[c / 8] & (1 << (c & 7))))
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.length())
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
};
if (!arg.length())
return QString::fromLatin1("\"\"");
QString ret(arg);
if (hasSpecialChars(ret, iqm)) {
// Quotes are escaped and their preceding backslashes are doubled.
// It's impossible to escape anything inside a quoted string on cmd
// level, so the outer quoting must be "suspended".
ret.replace(QRegExp(QLatin1String("(\\\\*)\"")), QLatin1String("\"\\1\\1\\^\"\""));
// The argument must not end with a \ since this would be interpreted
// as escaping the quote -- rather put the \ behind the quote: e.g.
// rather use "foo"\ than "foo\"
int i = ret.length();
while (i > 0 && ret.at(i - 1) == QLatin1Char('\\'))
--i;
ret.insert(i, QLatin1Char('"'));
ret.prepend(QLatin1Char('"'));
}
return ret;
}
QT_END_NAMESPACE

83
qmake/library/ioutils.h Normal file
View File

@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef IOUTILS_H
#define IOUTILS_H
#include <qstring.h>
QT_BEGIN_NAMESPACE
namespace QMakeInternal {
/*!
This class provides replacement functionality for QFileInfo, QFile & QDir,
as these are abysmally slow.
*/
class IoUtils {
public:
enum FileType {
FileNotFound = 0,
FileIsRegular = 1,
FileIsDir = 2
};
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 QStringRef 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
};
} // namespace ProFileEvaluatorInternal
QT_END_NAMESPACE
#endif // IOUTILS_H

452
qmake/library/proitems.cpp Normal file
View File

@ -0,0 +1,452 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "proitems.h"
#include <qfileinfo.h>
#include <qset.h>
#include <qstringlist.h>
#include <qtextstream.h>
QT_BEGIN_NAMESPACE
// from qhash.cpp
uint ProString::hash(const QChar *p, int n)
{
uint 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.length()), m_file(0)
{
updatedHash();
}
ProString::ProString(const QString &str) :
m_string(str), m_offset(0), m_length(str.length()), m_file(0), m_hash(0x80000000)
{
}
ProString::ProString(const char *str, DoPreHashing) :
m_string(QString::fromLatin1(str)), m_offset(0), m_length(qstrlen(str)), m_file(0)
{
updatedHash();
}
ProString::ProString(const char *str) :
m_string(QString::fromLatin1(str)), m_offset(0), m_length(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.length(), m_hash = 0x80000000;
}
uint ProString::updatedHash() const
{
return (m_hash = hash(m_string.constData() + m_offset, m_length));
}
uint 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.length();
updatedHash();
}
QString ProString::toQString() const
{
return m_string.mid(m_offset, m_length);
}
QString &ProString::toQString(QString &tmp) const
{
return tmp.setRawData(m_string.constData() + m_offset, m_length);
}
QChar *ProString::prepareExtend(int extraLen, int thisTarget, int extraTarget)
{
if (m_string.isDetached() && m_length + extraLen <= m_string.capacity()) {
m_string.reserve(0); // Prevent the resize() below from reallocating
QChar *ptr = (QChar *)m_string.constData();
if (m_offset != thisTarget)
memmove(ptr + thisTarget, ptr + m_offset, m_length * 2);
ptr += extraTarget;
m_offset = 0;
m_length += extraLen;
m_string.resize(m_length);
m_hash = 0x80000000;
return ptr;
} else {
QString neu(m_length + extraLen, Qt::Uninitialized);
QChar *ptr = (QChar *)neu.constData();
memcpy(ptr + thisTarget, m_string.constData() + m_offset, m_length * 2);
ptr += extraTarget;
*this = ProString(neu);
return ptr;
}
}
ProString &ProString::prepend(const ProString &other)
{
if (other.m_length) {
if (!m_length) {
*this = other;
} else {
QChar *ptr = prepareExtend(other.m_length, other.m_length, 0);
memcpy(ptr, other.constData(), other.m_length * 2);
if (!m_file)
m_file = other.m_file;
}
}
return *this;
}
ProString &ProString::append(const QLatin1String other)
{
const char *latin1 = other.latin1();
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
int size = other.size();
#else
int size = strlen(latin1);
#endif
if (size) {
QChar *ptr = prepareExtend(size, 0, m_length);
for (int i = 0; i < size; i++)
*ptr++ = QLatin1Char(latin1[i]);
}
return *this;
}
ProString &ProString::append(QChar other)
{
QChar *ptr = prepareExtend(1, 0, m_length);
*ptr = other;
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 {
QChar *ptr;
if (pending && !*pending) {
ptr = prepareExtend(1 + other.m_length, 0, m_length);
*ptr++ = 32;
} else {
ptr = prepareExtend(other.m_length, 0, m_length);
}
memcpy(ptr, other.m_string.constData() + other.m_offset, other.m_length * 2);
if (other.m_file)
m_file = other.m_file;
}
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 {
int totalLength = sz - startIdx;
for (int i = startIdx; i < sz; ++i)
totalLength += other.at(i).size();
bool putSpace = false;
if (pending && !*pending && m_length)
putSpace = true;
else
totalLength--;
QChar *ptr = prepareExtend(totalLength, 0, m_length);
for (int i = startIdx; i < sz; ++i) {
if (putSpace)
*ptr++ = 32;
else
putSpace = true;
const ProString &str = other.at(i);
memcpy(ptr, str.m_string.constData() + str.m_offset, str.m_length * 2);
ptr += str.m_length;
}
if (other.last().m_file)
m_file = other.last().m_file;
}
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.toQString(); // XXX optimize ... somehow
return t;
}
QString ProStringList::join(const QString &sep) const
{
int totalLength = 0;
const int sz = size();
for (int i = 0; i < sz; ++i)
totalLength += at(i).size();
if (sz)
totalLength += sep.size() * (sz - 1);
QString res(totalLength, Qt::Uninitialized);
QChar *ptr = (QChar *)res.constData();
for (int i = 0; i < sz; ++i) {
if (i) {
memcpy(ptr, sep.constData(), sep.size() * 2);
ptr += sep.size();
}
memcpy(ptr, at(i).constData(), at(i).size() * 2);
ptr += at(i).size();
}
return res;
}
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::removeDuplicates()
{
int n = size();
int j = 0;
QSet<ProString> seen;
seen.reserve(n);
for (int i = 0; i < n; ++i) {
const ProString &s = at(i);
if (seen.contains(s))
continue;
seen.insert(s);
if (j != i)
(*this)[j] = s;
++j;
}
if (n != j)
erase(begin() + j, end());
}
ProStringList::ProStringList(const QStringList &list)
{
reserve(list.size());
foreach (const QString &str, list)
*this << ProString(str);
}
QStringList ProStringList::toQStringList() const
{
QStringList ret;
ret.reserve(size());
foreach (const ProString &str, *this)
ret << str.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(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(const QString &fileName)
: m_refCount(1),
m_fileName(fileName),
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()
{
}
QT_END_NAMESPACE

View File

@ -44,14 +44,29 @@
#include "qmake_global.h"
#include <QString>
#include <QStringList>
#include <QHash>
#include <QTextStream>
#include <qstring.h>
#include <qvector.h>
#include <qhash.h>
QT_BEGIN_NAMESPACE
#if 0
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
@ -59,27 +74,36 @@ QT_BEGIN_NAMESPACE
class ProKey;
class ProStringList;
class ProFile;
class ProString {
public:
ProString() {}
ProString(const ProString &other) : m_string(other.m_string) {}
PROITEM_EXPLICIT ProString(const QString &str) : m_string(str) {}
PROITEM_EXPLICIT ProString(const char *str) : m_string(QLatin1String(str)) {}
void clear() { m_string.clear(); }
ProString();
ProString(const ProString &other);
PROITEM_EXPLICIT ProString(const QString &str);
PROITEM_EXPLICIT ProString(const char *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(const ProFile *pro) { m_file = pro; return *this; }
const ProFile *sourceFile() const { return m_file; }
ProString &prepend(const ProString &other) { m_string.prepend(other.m_string); return *this; }
ProString &append(const ProString &other) { m_string.append(other.m_string); return *this; }
ProString &append(const QString &other) { m_string.append(other); return *this; }
ProString &append(const char *other) { m_string.append(QLatin1String(other)); return *this; }
ProString &append(QChar other) { m_string.append(other); return *this; }
ProString &prepend(const ProString &other);
ProString &append(const ProString &other, bool *pending = 0);
ProString &append(const QString &other) { return append(ProString(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 = 0, bool skipEmpty1st = false);
ProString &operator+=(const ProString &other) { return append(other); }
ProString &operator+=(const QString &other) { return append(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) { m_string.chop(n); }
void chopFront(int n) { m_string.remove(0, n); }
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 toQStringRef() == other.toQStringRef(); }
bool operator==(const QString &other) const { return toQStringRef() == other; }
@ -90,15 +114,15 @@ public:
bool operator!=(QLatin1String other) const { return !(*this == other); }
bool operator!=(const char *other) const { return !(*this == other); }
bool isNull() const { return m_string.isNull(); }
bool isEmpty() const { return m_string.isEmpty(); }
int length() const { return m_string.size(); }
int size() const { return m_string.size(); }
QChar at(int i) const { return m_string.at(i); }
const QChar *constData() const { return m_string.constData(); }
ProString mid(int off, int len = -1) const { return m_string.mid(off, len); }
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 { return m_string.trimmed(); }
ProString trimmed() const;
int compare(const ProString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub.toQStringRef(), cs); }
int compare(const QString &sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(sub, cs); }
int compare(const char *sub, Qt::CaseSensitivity cs = Qt::CaseSensitive) const { return toQStringRef().compare(QLatin1String(sub), cs); }
@ -122,12 +146,15 @@ public:
int toInt(bool *ok = 0) const { return toQString().toInt(ok); } // XXX optimize
short toShort(bool *ok = 0) const { return toQString().toShort(ok); } // XXX optimize
ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, 0, m_string.length()); }
static uint hash(const QChar *p, int n);
ALWAYS_INLINE QStringRef toQStringRef() const { return QStringRef(&m_string, m_offset, m_length); }
ALWAYS_INLINE ProKey &toKey() { return *(ProKey *)this; }
ALWAYS_INLINE const ProKey &toKey() const { return *(const ProKey *)this; }
QString toQString() const { return m_string; }
QString toQString() const;
QString &toQString(QString &tmp) const;
QByteArray toLatin1() const { return toQStringRef().toLatin1(); }
@ -135,10 +162,23 @@ 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;
friend uint qHash(const ProKey &str, uint seed);
int m_offset, m_length;
const ProFile *m_file;
mutable uint m_hash;
QChar *prepareExtend(int extraLen, int thisTarget, int extraTarget);
uint updatedHash() const;
friend uint qHash(const ProString &str);
friend QString operator+(const ProString &one, const ProString &two);
friend QString &operator+=(QString &that, const ProString &other);
friend class ProKey;
};
Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE);
@ -146,8 +186,11 @@ Q_DECLARE_TYPEINFO(ProString, Q_MOVABLE_TYPE);
class ProKey : public ProString {
public:
ALWAYS_INLINE ProKey() : ProString() {}
explicit ProKey(const QString &str) : ProString(str) {}
PROITEM_EXPLICIT ProKey(const char *str) : ProString(str) {}
explicit ProKey(const QString &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.
@ -167,10 +210,8 @@ private:
};
Q_DECLARE_TYPEINFO(ProKey, Q_MOVABLE_TYPE);
inline uint qHash(const ProKey &key, uint seed = 0)
{ return qHash(key.m_string, seed); }
inline QString operator+(const ProString &one, const ProString &two)
{ return one.m_string + two.m_string; }
uint qHash(const ProString &str);
QString operator+(const ProString &one, const ProString &two);
inline QString operator+(const ProString &one, const QString &two)
{ return one + ProString(two); }
inline QString operator+(const QString &one, const ProString &two)
@ -189,29 +230,31 @@ inline bool operator==(const QString &that, const ProString &other)
inline bool operator!=(const QString &that, const ProString &other)
{ return !(other == that); }
inline QTextStream &operator<<(QTextStream &t, const ProString &str)
{ t << str.toQString(); return t; }
QTextStream &operator<<(QTextStream &t, const ProString &str);
class ProStringList : public QList<ProString> {
class ProStringList : public QVector<ProString> {
public:
ProStringList() {}
ProStringList(const ProString &str) { *this << str; }
explicit ProStringList(const QStringList &list) : QList<ProString>(*(const ProStringList *)&list) {}
QStringList toQStringList() const { return *(const QStringList *)this; }
explicit ProStringList(const QStringList &list);
QStringList toQStringList() const;
ProStringList &operator<<(const ProString &str)
{ QList<ProString>::operator<<(str); return *this; }
{ QVector<ProString>::operator<<(str); return *this; }
QString join(const QString &sep) const { return toQStringList().join(sep); }
int length() const { return size(); }
void remove(int idx) { removeAt(idx); }
QString join(const QString &sep) const;
bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return contains(str.toQString(), cs); }
void removeAll(const ProString &str);
void removeAll(const char *str);
void removeAt(int idx) { remove(idx); }
void removeDuplicates();
bool contains(const ProString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
bool contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return (*(const QStringList *)this).contains(str, cs); }
bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const
{ return (*(const QStringList *)this).contains(str, cs); }
{ return contains(ProString(str), cs); }
bool contains(const char *str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
};
Q_DECLARE_TYPEINFO(ProStringList, Q_MOVABLE_TYPE);
@ -220,6 +263,131 @@ inline ProStringList operator+(const ProStringList &one, const ProStringList &tw
typedef QHash<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
// - 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
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)
TokMask = 0xff,
TokQuoted = 0x100, // The expression is quoted => join expanded stringlist
TokNewStr = 0x200 // Next stringlist element
};
class QMAKE_EXPORT ProFile
{
public:
explicit ProFile(const QString &fileName);
~ProFile();
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(); }
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; }
private:
ProItemRefCount m_refCount;
QString m_proitems;
QString m_fileName;
QString m_directoryName;
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() { m_pro->deref(); }
ProFunctionDef &operator=(const ProFunctionDef &o)
{
if (this != &o) {
m_pro->deref();
m_pro = o.m_pro;
m_pro->ref();
m_offset = o.m_offset;
}
return *this;
}
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_MOVABLE_TYPE);
struct ProFunctionDefs {
QHash<ProKey, ProFunctionDef> testFunctions;
QHash<ProKey, ProFunctionDef> replaceFunctions;
};
QT_END_NAMESPACE
#endif // PROITEMS_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,309 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#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 "ioutils.h"
#include <qlist.h>
#include <qlinkedlist.h>
#include <qset.h>
#include <qstack.h>
#include <qstring.h>
#include <qstringlist.h>
#ifndef QT_BOOTSTRAPPED
# include <qprocess.h>
#endif
QT_BEGIN_NAMESPACE
class QMakeGlobals;
class QMAKE_EXPORT QMakeHandler : public QMakeParserHandler
{
public:
enum {
SourceEvaluator = 0x10,
EvalWarnLanguage = SourceEvaluator | WarningMessage | WarnLanguage,
EvalWarnDeprecated = SourceEvaluator | WarningMessage | WarnDeprecated,
EvalError = ErrorMessage | SourceEvaluator
};
// error(), warning() and message() from .pro file
virtual void fileMessage(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;
};
// We use a QLinkedList based stack instead of a QVector based one (QStack), so that
// the addresses of value maps stay constant. The qmake generators rely on that.
class QMAKE_EXPORT ProValueMapStack : public QLinkedList<ProValueMap>
{
public:
inline void push(const ProValueMap &t) { append(t); }
inline ProValueMap pop() { return takeLast(); }
ProValueMap &top() { return last(); }
const ProValueMap &top() const { return last(); }
};
class QMAKE_EXPORT QMakeEvaluator
{
public:
enum LoadFlag {
LoadProOnly = 0,
LoadPreFiles = 1,
LoadPostFiles = 2,
LoadAll = LoadPreFiles|LoadPostFiles,
LoadSilent = 0x10
};
Q_DECLARE_FLAGS(LoadFlags, LoadFlag)
static void initStatics();
static void initFunctionStatics();
QMakeEvaluator(QMakeGlobals *option, QMakeParser *parser,
QMakeHandler *handler);
~QMakeEvaluator();
#ifdef QT_BUILD_QMAKE
void setExtraVars(const ProValueMap &extraVars) { m_extraVars = extraVars; }
void setExtraConfigs(const ProStringList &extraConfigs) { m_extraConfigs = extraConfigs; }
#endif
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);
ProString getStr(const ushort *&tokPtr);
ProKey getHashStr(const ushort *&tokPtr);
void 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);
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);
void 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(const QString &vals, const ProFile *source = 0);
ProStringList expandVariableReferences(const ProString &value, int *pos = 0, bool joined = false);
ProStringList expandVariableReferences(const ushort *&tokPtr, int sizeHint = 0, bool joined = false);
QString currentFileName() const;
QString currentDirectory() const;
ProFile *currentProFile() const;
QString resolvePath(const QString &fileName) const
{ return QMakeInternal::IoUtils::resolvePath(currentDirectory(), fileName); }
bool evaluateFile(const QString &fileName, QMakeHandler::EvalFileType type,
LoadFlags flags);
bool evaluateFileChecked(const QString &fileName, QMakeHandler::EvalFileType type,
LoadFlags flags);
bool evaluateFeatureFile(const QString &fileName, bool silent = false);
bool evaluateFileInto(const QString &fileName,
ProValueMap *values, // output-only
LoadFlags flags);
void 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); }
QList<ProStringList> prepareFunctionArgs(const ushort *&tokPtr);
ProStringList evaluateFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList, bool *ok);
VisitReturn evaluateBoolFunction(const ProFunctionDef &func,
const QList<ProStringList> &argumentsList,
const ProString &function);
ProStringList evaluateExpandFunction(const ProKey &function, const ushort *&tokPtr);
VisitReturn evaluateConditionalFunction(const ProKey &function, const ushort *&tokPtr);
ProStringList evaluateBuiltinExpand(const ProKey &function, const ProStringList &args);
VisitReturn evaluateBuiltinConditional(const ProKey &function, const ProStringList &args);
bool evaluateConditional(const QString &cond, const QString &where, int line = -1);
#ifdef PROEVALUATOR_FULL
void checkRequirements(const ProStringList &deps);
#endif
void updateMkspecPaths();
void updateFeaturePaths();
bool isActiveConfig(const QString &config, bool regex = false);
void populateDeps(
const ProStringList &deps, const ProString &prefix,
QHash<ProKey, QSet<ProKey> > &dependencies,
ProValueMap &dependees, ProStringList &rootSet) const;
VisitReturn writeFile(const QString &ctx, const QString &fn, QIODevice::OpenMode mode,
const QString &contents);
#ifndef QT_BOOTSTRAPPED
void runProcess(QProcess *proc, const QString &command) const;
#endif
QByteArray getCommandOutput(const QString &args) const;
static void removeEach(ProStringList *varlist, const ProStringList &value);
QMakeEvaluator *m_caller;
int m_loopLevel; // To report unexpected break() and next()s
#ifdef PROEVALUATOR_CUMULATIVE
bool m_cumulative;
int m_skipLevel;
#else
enum { m_cumulative = 0 };
enum { m_skipLevel = 0 };
#endif
#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(0), line(0) {}
Location(ProFile *_pro, ushort _line) : pro(_pro), line(_line) {}
void clear() { pro = 0; 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
#ifdef QT_BUILD_QMAKE
ProValueMap m_extraVars;
ProStringList m_extraConfigs;
#endif
QString m_outputDir;
int m_listCount;
bool m_valuemapInited;
bool m_hostBuild;
QString m_qmakespec;
QString m_qmakespecFull;
QString m_qmakespecName;
QString m_superfile;
QString m_conffile;
QString m_cachefile;
QString m_sourceRoot;
QString m_buildRoot;
QStringList m_qmakepath;
QStringList m_qmakefeatures;
QStringList m_mkspecPaths;
QStringList 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
mutable QString m_mtmp;
QMakeGlobals *m_option;
QMakeParser *m_parser;
QMakeHandler *m_handler;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QMakeEvaluator::LoadFlags)
QT_END_NAMESPACE
#endif // QMAKEEVALUATOR_H

View File

@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKEEVALUATOR_P_H
#define QMAKEEVALUATOR_P_H
#include "proitems.h"
#include <qregexp.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) qPrintable(s.toString().toQString())
# 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 QMakeStatics {
QString field_sep;
QString strtrue;
QString strfalse;
ProKey strCONFIG;
ProKey strARGS;
QString strDot;
QString strDotDot;
QString strever;
QString strforever;
QString strhost_build;
ProKey strTEMPLATE;
#ifdef PROEVALUATOR_FULL
ProKey strREQUIRES;
#endif
QHash<ProKey, int> expands;
QHash<ProKey, int> functions;
QHash<ProKey, ProKey> varMap;
ProStringList fakeValue;
};
extern QMakeStatics statics;
}
QT_END_NAMESPACE
#endif // QMAKEEVALUATOR_P_H

View File

@ -0,0 +1,368 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qmakeglobals.h"
#include "qmakeevaluator.h"
#include "ioutils.h"
#include <qbytearray.h>
#include <qdatetime.h>
#include <qdebug.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qlist.h>
#include <qregexp.h>
#include <qset.h>
#include <qstack.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtextstream.h>
#ifdef PROEVALUATOR_THREAD_SAFE
# include <qthreadpool.h>
#endif
#ifdef Q_OS_UNIX
#include <unistd.h>
#include <sys/utsname.h>
#else
#include <windows.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef Q_OS_WIN32
#define QT_POPEN _popen
#define QT_PCLOSE _pclose
#else
#define QT_POPEN popen
#define QT_PCLOSE pclose
#endif
QT_BEGIN_NAMESPACE
#define fL1S(s) QString::fromLatin1(s)
namespace { // MSVC doesn't seem to know the semantics of "static" ...
static struct {
QRegExp reg_variableName;
} statics;
}
static void initStatics()
{
if (!statics.reg_variableName.isEmpty())
return;
statics.reg_variableName.setPattern(QLatin1String("\\$\\(.*\\)"));
statics.reg_variableName.setMinimal(true);
}
QMakeGlobals::QMakeGlobals()
{
initStatics();
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
qmakespec = getEnv(QLatin1String("QMAKESPEC"));
}
QMakeGlobals::~QMakeGlobals()
{
qDeleteAll(baseEnvs);
}
QString QMakeGlobals::cleanSpec(QMakeCmdLineParserState &state, const QString &spec)
{
QString ret = QDir::cleanPath(spec);
if (ret.contains(QLatin1Char('/'))) {
QString absRet = QDir(state.pwd).absoluteFilePath(ret);
if (QFile::exists(absRet))
ret = QDir::cleanPath(absRet);
}
return ret;
}
QMakeGlobals::ArgumentReturn QMakeGlobals::addCommandLineArguments(
QMakeCmdLineParserState &state, QStringList &args, int *pos)
{
enum { ArgNone, ArgConfig, ArgSpec, ArgXSpec, ArgTmpl, ArgTmplPfx, ArgCache } argState = ArgNone;
for (; *pos < args.count(); (*pos)++) {
QString arg = args.at(*pos);
switch (argState) {
case ArgConfig:
if (state.after)
state.postconfigs << arg;
else
state.preconfigs << 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] = QDir::cleanPath(QDir(state.pwd).absoluteFilePath(arg));
break;
default:
if (arg.startsWith(QLatin1Char('-'))) {
if (arg == QLatin1String("-after")) {
state.after = true;
} 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("-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('='))) {
if (state.after)
state.postcmds << arg;
else
state.precmds << arg;
} else {
return ArgumentUnknown;
}
continue;
}
argState = ArgNone;
}
if (argState != ArgNone)
return ArgumentMalformed;
return ArgumentsOk;
}
void QMakeGlobals::commitCommandLineArguments(QMakeCmdLineParserState &state)
{
if (!state.preconfigs.isEmpty())
state.precmds << (fL1S("CONFIG += ") + state.preconfigs.join(fL1S(" ")));
precmds = state.precmds.join(fL1S("\n"));
if (!state.postconfigs.isEmpty())
state.postcmds << (fL1S("CONFIG += ") + state.postconfigs.join(fL1S(" ")));
postcmds = state.postcmds.join(fL1S("\n"));
if (xqmakespec.isEmpty())
xqmakespec = qmakespec;
}
void QMakeGlobals::useEnvironment()
{
if (xqmakespec.isEmpty())
xqmakespec = getEnv(QLatin1String("XQMAKESPEC"));
if (qmakespec.isEmpty()) {
qmakespec = getEnv(QLatin1String("QMAKESPEC"));
if (xqmakespec.isEmpty())
xqmakespec = qmakespec;
}
}
void QMakeGlobals::setCommandLineArguments(const QString &pwd, const QStringList &_args)
{
QStringList args = _args;
QMakeCmdLineParserState state(pwd);
for (int pos = 0; pos < args.size(); pos++)
addCommandLineArguments(state, args, &pos);
commitCommandLineArguments(state);
useEnvironment();
}
void QMakeGlobals::setDirectories(const QString &input_dir, const QString &output_dir)
{
if (input_dir != output_dir && !output_dir.isEmpty()) {
QString srcpath = input_dir;
if (!srcpath.endsWith(QLatin1Char('/')))
srcpath += QLatin1Char('/');
QString dstpath = output_dir;
if (!dstpath.endsWith(QLatin1Char('/')))
dstpath += QLatin1Char('/');
int srcLen = srcpath.length();
int dstLen = dstpath.length();
int lastSl = -1;
while (++lastSl, srcpath.at(--srcLen) == dstpath.at(--dstLen))
if (srcpath.at(srcLen) == QLatin1Char('/'))
lastSl = 0;
source_root = srcpath.left(srcLen + lastSl);
build_root = dstpath.left(dstLen + lastSl);
}
}
QString QMakeGlobals::shadowedPath(const QString &fileName) const
{
if (source_root.isEmpty())
return fileName;
if (fileName.startsWith(source_root)
&& (fileName.length() == source_root.length()
|| fileName.at(source_root.length()) == QLatin1Char('/'))) {
return build_root + fileName.mid(source_root.length());
}
return QString();
}
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
{
QStringList ret;
QString val = getEnv(var);
if (!val.isEmpty()) {
QDir bdir;
QStringList vals = val.split(dirlist_sep);
ret.reserve(vals.length());
foreach (const QString &it, vals)
ret << QDir::cleanPath(bdir.absoluteFilePath(it));
}
return ret;
}
QString QMakeGlobals::expandEnvVars(const QString &str) const
{
QString string = str;
int rep;
QRegExp reg_variableName = statics.reg_variableName; // Copy for thread safety
while ((rep = reg_variableName.indexIn(string)) != -1)
string.replace(rep, reg_variableName.matchedLength(),
getEnv(string.mid(rep + 2, reg_variableName.matchedLength() - 3)));
return string;
}
#ifndef QT_BUILD_QMAKE
#ifdef PROEVALUATOR_INIT_PROPS
bool QMakeGlobals::initProperties()
{
QByteArray data;
#ifndef QT_BOOTSTRAPPED
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(), "r")) {
char buff[1024];
while (!feof(proc))
data.append(buff, int(fread(buff, 1, 1023, proc)));
QT_PCLOSE(proc);
}
#endif
foreach (QByteArray line, data.split('\n'))
if (!line.startsWith("QMAKE_")) {
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))));
properties.insert(ProKey(name), value);
if (name.startsWith(QLatin1String("QT_")) && !name.contains(QLatin1Char('/'))) {
if (name.startsWith(QLatin1String("QT_INSTALL_"))) {
properties.insert(ProKey(name + QLatin1String("/raw")), value);
properties.insert(ProKey(name + QLatin1String("/get")), value);
if (name == QLatin1String("QT_INSTALL_PREFIX")
|| name == QLatin1String("QT_INSTALL_DATA")
|| name == QLatin1String("QT_INSTALL_BINS")) {
name.replace(3, 7, QLatin1String("HOST"));
properties.insert(ProKey(name), value);
properties.insert(ProKey(name + QLatin1String("/get")), value);
}
} else if (name.startsWith(QLatin1String("QT_HOST_"))) {
properties.insert(ProKey(name + QLatin1String("/get")), value);
}
}
}
properties.insert(ProKey("QMAKE_VERSION"), ProString("2.01a"));
return true;
}
#else
void QMakeGlobals::setProperties(const QHash<QString, QString> &props)
{
QHash<QString, QString>::ConstIterator it = props.constBegin(), eit = props.constEnd();
for (; it != eit; ++it)
properties.insert(ProKey(it.key()), ProString(it.value()));
}
#endif
#endif // QT_BUILD_QMAKE
QT_END_NAMESPACE

View File

@ -0,0 +1,173 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#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>
#ifndef QT_BOOTSTRAPPED
# include <qprocess.h>
#endif
#ifdef PROEVALUATOR_THREAD_SAFE
# include <qmutex.h>
# include <qwaitcondition.h>
#endif
QT_BEGIN_NAMESPACE
class QMakeEvaluator;
class QMakeBaseKey
{
public:
QMakeBaseKey(const QString &_root, bool _hostBuild);
QString root;
bool hostBuild;
};
uint 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), after(false) {}
QString pwd;
QStringList precmds, preconfigs, postcmds, postconfigs;
bool after;
};
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;
QString qmakespec, xqmakespec;
QString user_template, user_template_prefix;
QString precmds, postcmds;
#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; }
ProString propertyValue(const ProKey &name) const { return property->value(name); }
#else
# ifdef PROEVALUATOR_INIT_PROPS
bool initProperties();
# else
void setProperties(const QHash<QString, QString> &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;
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

File diff suppressed because it is too large Load Diff

214
qmake/library/qmakeparser.h Normal file
View File

@ -0,0 +1,214 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the qmake application of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QMAKEPARSER_H
#define QMAKEPARSER_H
#include "qmake_global.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,
WarningMessage = 0x000,
ErrorMessage = 0x100,
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 QMAKE_EXPORT QMakeParser
{
public:
// Call this from a concurrency-free context
static void initialize();
QMakeParser(ProFileCache *cache, QMakeParserHandler *handler);
enum SubGrammar { FullGrammar, TestGrammar, ValueGrammar };
// fileName is expected to be absolute and cleanPath()ed.
ProFile *parsedProFile(const QString &fileName, bool cache = false);
ProFile *parsedProBlock(const QString &contents, const QString &name, int line = 0,
SubGrammar grammar = FullGrammar);
private:
struct BlockScope {
BlockScope() : start(0), braceLevel(0), special(false), inBranch(false) {}
BlockScope(const BlockScope &other) { *this = other; }
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
};
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 read(ProFile *pro);
bool read(ProFile *pro, const QString &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, const QString &in);
void finalizeCond(ushort *&tokPtr, ushort *uc, ushort *ptr, int wordCount);
void finalizeCall(ushort *&tokPtr, ushort *uc, ushort *ptr, int argc);
void finalizeTest(ushort *&tokPtr);
void bogusTest(ushort *&tokPtr);
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); }
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
bool 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;
// This doesn't help gcc 3.3 ...
template<typename T> friend class QTypeInfo;
friend class ProFileCache;
};
class QMAKE_EXPORT ProFileCache
{
public:
ProFileCache() {}
~ProFileCache();
void discardFile(const QString &fileName);
void discardFiles(const QString &prefix);
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<QString, 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_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QMakeParser::Context, Q_PRIMITIVE_TYPE);
#endif
QT_END_NAMESPACE
#endif // PROFILEPARSER_H

View File

@ -85,6 +85,9 @@ int runQMake(int argc, char **argv)
// This is particularly important for things like QtCreator and scripted builds.
setvbuf(stdout, (char *)NULL, _IONBF, 0);
QMakeGlobals globals;
Option::globals = &globals;
// parse command line
int ret = Option::init(argc, argv);
if(ret != Option::QMAKE_CMDLINE_SUCCESS) {
@ -125,8 +128,14 @@ int runQMake(int argc, char **argv)
Option::qmake_mode == Option::QMAKE_SET_PROPERTY ||
Option::qmake_mode == Option::QMAKE_UNSET_PROPERTY)
return prop.exec() ? 0 : 101;
globals.setQMakeProperty(&prop);
QMakeProject project(&prop);
ProFileCache proFileCache;
Option::proFileCache = &proFileCache;
QMakeParser parser(&proFileCache, &Option::evalHandler);
Option::parser = &parser;
QMakeProject project;
int exit_val = 0;
QStringList files;
if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT)

View File

@ -76,7 +76,7 @@ QMakeMetaInfo::readLib(QString lib)
meta_type = "libtool";
} else if(meta_file.endsWith(Option::prl_ext)) {
QMakeProject proj;
if(!proj.read(Option::normalizePath(meta_file), QMakeProject::ReadProFile))
if (!proj.read(Option::normalizePath(meta_file), QMakeEvaluator::LoadProOnly))
return false;
meta_type = "qmake";
vars = proj.variables();
@ -136,7 +136,7 @@ QMakeMetaInfo::readLibtoolFile(const QString &f)
/* I can just run the .la through the .pro parser since they are compatible.. */
QMakeProject proj;
QString nf = Option::normalizePath(f);
if(!proj.read(nf, QMakeProject::ReadProFile))
if (!proj.read(nf, QMakeEvaluator::LoadProOnly))
return false;
QString dirf = nf.section(QLatin1Char('/'), 0, -2);
if(dirf == nf)

View File

@ -51,6 +51,11 @@
QT_BEGIN_NAMESPACE
EvalHandler Option::evalHandler;
QMakeGlobals *Option::globals;
ProFileCache *Option::proFileCache;
QMakeParser *Option::parser;
//convenience
const char *Option::application_argv0 = 0;
QString Option::prf_ext;
@ -67,7 +72,6 @@ QString Option::lex_ext;
QString Option::yacc_ext;
QString Option::pro_ext;
QString Option::dir_sep;
QString Option::dirlist_sep;
QString Option::h_moc_mod;
QString Option::yacc_mod;
QString Option::lex_mod;
@ -78,17 +82,12 @@ char Option::field_sep;
Option::QMAKE_MODE Option::qmake_mode = Option::QMAKE_GENERATE_NOTHING;
//all modes
QString Option::qmake_abslocation;
QStringList Option::qmake_args;
int Option::warn_level = WarnLogic | WarnDeprecated;
int Option::debug_level = 0;
QFile Option::output;
QString Option::output_dir;
bool Option::recursive = false;
QStringList Option::before_user_vars;
QStringList Option::after_user_vars;
QString Option::user_template;
QString Option::user_template_prefix;
//QMAKE_*_PROPERTY stuff
QStringList Option::prop::properties;
@ -98,18 +97,12 @@ bool Option::projfile::do_pwd = true;
QStringList Option::projfile::project_dirs;
//QMAKE_GENERATE_MAKEFILE stuff
QString Option::mkfile::qmakespec;
QString Option::mkfile::xqmakespec;
int Option::mkfile::cachefile_depth = -1;
bool Option::mkfile::do_deps = true;
bool Option::mkfile::do_mocs = true;
bool Option::mkfile::do_dep_heuristics = true;
bool Option::mkfile::do_preprocess = false;
bool Option::mkfile::do_stub_makefile = false;
bool Option::mkfile::do_cache = true;
QString Option::mkfile::source_root;
QString Option::mkfile::build_root;
QString Option::mkfile::cachefile;
QStringList Option::mkfile::project_files;
static Option::QMAKE_MODE default_mode(QString progname)
@ -138,17 +131,6 @@ static QString detectProjectFile(const QString &path)
return ret;
}
static QString cleanSpec(const QString &spec)
{
QString ret = QDir::cleanPath(spec);
if (ret.contains('/')) {
const QFileInfo specDirInfo(ret);
if (specDirInfo.exists() && specDirInfo.isDir())
ret = QDir::cleanPath(specDirInfo.absoluteFilePath());
}
return ret;
}
QString project_builtin_regx();
bool usage(const char *a0)
{
@ -213,102 +195,87 @@ bool usage(const char *a0)
int
Option::parseCommandLine(QStringList &args)
{
QStringList user_configs;
bool before = true;
args << QString(); // Avoid bounds checking for options which take an argument
for (int x = 0; x < args.size() - 1; ) {
QString arg = args.at(x);
if (arg.size() > 1 && arg.startsWith('-')) { /* options */
QString opt = arg.mid(1);
if(opt == "o" || opt == "output") {
Option::output.setFileName(args.at(x + 1));
args.erase(args.begin() + x, args.begin() + x + 2);
continue;
} else if(opt == "after") {
before = false;
} else if(opt == "t" || opt == "template") {
Option::user_template = args.at(++x);
} else if(opt == "tp" || opt == "template_prefix") {
Option::user_template_prefix = args.at(++x);
} else if(opt == "unix") {
Option::dir_sep = "/";
} else if(opt == "win32") {
Option::dir_sep = "\\";
} else if(opt == "d") {
Option::debug_level++;
} else if(opt == "version" || opt == "v" || opt == "-version") {
fprintf(stdout,
"QMake version %s\n"
"Using Qt version %s in %s\n",
qmake_version(), QT_VERSION_STR,
QLibraryInfo::location(QLibraryInfo::LibrariesPath).toLatin1().constData());
QMakeCmdLineParserState state(QDir::currentPath());
enum { ArgNone, ArgOutput } argState = ArgNone;
int x = 0;
while (x < args.count()) {
switch (argState) {
case ArgOutput:
Option::output.setFileName(args.at(x--));
args.erase(args.begin() + x, args.begin() + x + 2);
argState = ArgNone;
continue;
default:
QMakeGlobals::ArgumentReturn cmdRet = globals->addCommandLineArguments(state, args, &x);
if (cmdRet == QMakeGlobals::ArgumentsOk)
break;
if (cmdRet == QMakeGlobals::ArgumentMalformed) {
fprintf(stderr, "***Option %s requires a parameter\n", qPrintable(args.at(x - 1)));
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
}
Q_ASSERT(cmdRet == QMakeGlobals::ArgumentUnknown);
QString arg = args.at(x);
if (arg.startsWith(QLatin1Char('-'))) {
if (arg == "-d") {
Option::debug_level++;
} else if (arg == "-v" || arg == "-version" || arg == "--version") {
fprintf(stdout,
"QMake version %s\n"
"Using Qt version %s in %s\n",
qmake_version(), QT_VERSION_STR,
QLibraryInfo::location(QLibraryInfo::LibrariesPath).toLatin1().constData());
#ifdef QMAKE_OPENSOURCE_VERSION
fprintf(stdout, "QMake is Open Source software from Nokia Corporation and/or its subsidiary(-ies).\n");
fprintf(stdout, "QMake is Open Source software from Nokia Corporation and/or its subsidiary(-ies).\n");
#endif
return Option::QMAKE_CMDLINE_BAIL;
} else if(opt == "h" || opt == "help") {
return Option::QMAKE_CMDLINE_SHOW_USAGE;
} else if(opt == "Wall") {
Option::warn_level |= WarnAll;
} else if(opt == "Wparser") {
Option::warn_level |= WarnParser;
} else if(opt == "Wlogic") {
Option::warn_level |= WarnLogic;
} else if(opt == "Wdeprecated") {
Option::warn_level |= WarnDeprecated;
} else if(opt == "Wnone") {
Option::warn_level = WarnNone;
} else if(opt == "r" || opt == "recursive") {
Option::recursive = true;
args.removeAt(x);
continue;
} else if(opt == "nr" || opt == "norecursive") {
Option::recursive = false;
args.removeAt(x);
continue;
} else if(opt == "config") {
user_configs += args.at(++x);
} else {
if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
if(opt == "nodepend" || opt == "nodepends") {
Option::mkfile::do_deps = false;
} else if(opt == "nomoc") {
Option::mkfile::do_mocs = false;
} else if(opt == "nocache") {
Option::mkfile::do_cache = false;
} else if(opt == "createstub") {
Option::mkfile::do_stub_makefile = true;
} else if(opt == "nodependheuristics") {
Option::mkfile::do_dep_heuristics = false;
} else if(opt == "E") {
Option::mkfile::do_preprocess = true;
} else if(opt == "cache") {
Option::mkfile::cachefile = args.at(++x);
} else if(opt == "platform" || opt == "spec") {
Option::mkfile::qmakespec = args[x] = cleanSpec(args.at(++x));
} else if (opt == "xplatform" || opt == "xspec") {
Option::mkfile::xqmakespec = args[x] = cleanSpec(args.at(x));
} else {
fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
}
} else if(Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
if(opt == "nopwd") {
Option::projfile::do_pwd = false;
} else {
fprintf(stderr, "***Unknown option -%s\n", opt.toLatin1().constData());
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
return Option::QMAKE_CMDLINE_BAIL;
} else if (arg == "-h" || arg == "-help" || arg == "--help") {
return Option::QMAKE_CMDLINE_SHOW_USAGE;
} else if (arg == "-Wall") {
Option::warn_level |= WarnAll;
} else if (arg == "-Wparser") {
Option::warn_level |= WarnParser;
} else if (arg == "-Wlogic") {
Option::warn_level |= WarnLogic;
} else if (arg == "-Wdeprecated") {
Option::warn_level |= WarnDeprecated;
} else if (arg == "-Wnone") {
Option::warn_level = WarnNone;
} else if (arg == "-r" || arg == "-recursive") {
Option::recursive = true;
args.removeAt(x);
continue;
} else if (arg == "-nr" || arg == "-norecursive") {
Option::recursive = false;
args.removeAt(x);
continue;
} else if (arg == "-o" || arg == "-output") {
argState = ArgOutput;
} else {
if (Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
if (arg == "-nodepend" || arg == "-nodepends") {
Option::mkfile::do_deps = false;
} else if (arg == "-nomoc") {
Option::mkfile::do_mocs = false;
} else if (arg == "-createstub") {
Option::mkfile::do_stub_makefile = true;
} else if (arg == "-nodependheuristics") {
Option::mkfile::do_dep_heuristics = false;
} else if (arg == "-E") {
Option::mkfile::do_preprocess = true;
} else {
fprintf(stderr, "***Unknown option %s\n", arg.toLatin1().constData());
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
}
} else if (Option::qmake_mode == Option::QMAKE_GENERATE_PROJECT) {
if (arg == "-nopwd") {
Option::projfile::do_pwd = false;
} else {
fprintf(stderr, "***Unknown option %s\n", arg.toLatin1().constData());
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
}
}
}
}
} else {
if(arg.indexOf('=') != -1) {
if(before)
Option::before_user_vars.append(arg);
else
Option::after_user_vars.append(arg);
} else {
bool handled = true;
if(Option::qmake_mode == Option::QMAKE_QUERY_PROPERTY ||
@ -342,14 +309,12 @@ Option::parseCommandLine(QStringList &args)
}
x++;
}
if (!user_configs.isEmpty())
Option::before_user_vars += "CONFIG += " + user_configs.join(" ");
if (Option::mkfile::xqmakespec.isEmpty())
Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
args.takeLast();
if (argState != ArgNone) {
fprintf(stderr, "***Option %s requires a parameter\n", qPrintable(args.at(x - 1)));
return Option::QMAKE_CMDLINE_SHOW_USAGE | Option::QMAKE_CMDLINE_ERROR;
}
globals->commitCommandLineArguments(state);
globals->debugLevel = Option::debug_level;
return Option::QMAKE_CMDLINE_SUCCESS;
}
@ -359,13 +324,6 @@ Option::init(int argc, char **argv)
Option::application_argv0 = 0;
Option::prf_ext = ".prf";
Option::pro_ext = ".pro";
#ifdef Q_OS_WIN
Option::dir_sep = "\\";
Option::dirlist_sep = ";";
#else
Option::dir_sep = "/";
Option::dirlist_sep = ":";
#endif
Option::field_sep = ' ';
if(argc && argv) {
@ -374,13 +332,13 @@ Option::init(int argc, char **argv)
if(Option::qmake_mode == Option::QMAKE_GENERATE_NOTHING)
Option::qmake_mode = default_mode(argv0);
if(!argv0.isEmpty() && !QFileInfo(argv0).isRelative()) {
Option::qmake_abslocation = argv0;
globals->qmake_abslocation = argv0;
} else if (argv0.contains(QLatin1Char('/'))
#ifdef Q_OS_WIN
|| argv0.contains(QLatin1Char('\\'))
#endif
) { //relative PWD
Option::qmake_abslocation = QDir::current().absoluteFilePath(argv0);
globals->qmake_abslocation = QDir::current().absoluteFilePath(argv0);
} else { //in the PATH
QByteArray pEnv = qgetenv("PATH");
QDir currentDir = QDir::current();
@ -397,16 +355,16 @@ Option::init(int argc, char **argv)
candidate += ".exe";
#endif
if (QFile::exists(candidate)) {
Option::qmake_abslocation = candidate;
globals->qmake_abslocation = candidate;
break;
}
}
}
if(!Option::qmake_abslocation.isNull())
Option::qmake_abslocation = QDir::cleanPath(Option::qmake_abslocation);
if (!globals->qmake_abslocation.isNull())
globals->qmake_abslocation = QDir::cleanPath(globals->qmake_abslocation);
else // This is rather unlikely to ever happen on a modern system ...
Option::qmake_abslocation = QLibraryInfo::rawLocation(QLibraryInfo::HostBinariesPath,
QLibraryInfo::EffectivePaths) +
globals->qmake_abslocation = QLibraryInfo::rawLocation(QLibraryInfo::HostBinariesPath,
QLibraryInfo::EffectivePaths) +
#ifdef Q_OS_WIN
"/qmake.exe";
#else
@ -485,13 +443,7 @@ Option::init(int argc, char **argv)
//last chance for defaults
if(Option::qmake_mode == Option::QMAKE_GENERATE_MAKEFILE ||
Option::qmake_mode == Option::QMAKE_GENERATE_PRL) {
if (Option::mkfile::xqmakespec.isEmpty())
Option::mkfile::xqmakespec = QString::fromLocal8Bit(qgetenv("XQMAKESPEC").constData());
if (Option::mkfile::qmakespec.isEmpty()) {
Option::mkfile::qmakespec = QString::fromLocal8Bit(qgetenv("QMAKESPEC").constData());
if (Option::mkfile::xqmakespec.isEmpty())
Option::mkfile::xqmakespec = Option::mkfile::qmakespec;
}
globals->useEnvironment();
//try REALLY hard to do it for them, lazy..
if(Option::mkfile::project_files.isEmpty()) {
@ -513,23 +465,7 @@ Option::init(int argc, char **argv)
void Option::prepareProject(const QString &pfile)
{
QString srcpath = QDir::cleanPath(QFileInfo(pfile).absolutePath());
if (srcpath != output_dir) {
if (!srcpath.endsWith(QLatin1Char('/')))
srcpath += QLatin1Char('/');
QString dstpath = output_dir;
if (!dstpath.endsWith(QLatin1Char('/')))
dstpath += QLatin1Char('/');
int srcLen = srcpath.length();
int dstLen = dstpath.length();
int lastSl = -1;
while (++lastSl, srcpath.at(--srcLen) == dstpath.at(--dstLen))
if (srcpath.at(srcLen) == QLatin1Char('/'))
lastSl = 0;
mkfile::source_root = srcpath.left(srcLen + lastSl);
mkfile::build_root = dstpath.left(dstLen + lastSl);
} else {
mkfile::source_root.clear();
}
globals->setDirectories(srcpath, output_dir);
}
bool Option::postProcessProject(QMakeProject *project)
@ -550,6 +486,8 @@ bool Option::postProcessProject(QMakeProject *project)
Option::lex_mod = project->first("QMAKE_MOD_LEX").toQString();
Option::yacc_mod = project->first("QMAKE_MOD_YACC").toQString();
Option::dir_sep = project->dirSep().toQString();
if (Option::output_dir.startsWith(project->buildRoot()))
Option::mkfile::cachefile_depth =
Option::output_dir.mid(project->buildRoot().length()).count('/');
@ -665,6 +603,37 @@ void warn_msg(QMakeWarn type, const char *fmt, ...)
fprintf(stderr, "\n");
}
void EvalHandler::message(int type, const QString &msg, const QString &fileName, int lineNo)
{
QString pfx;
if ((type & QMakeHandler::CategoryMask) == QMakeHandler::WarningMessage) {
int code = (type & QMakeHandler::CodeMask);
if ((code == QMakeHandler::WarnLanguage && !(Option::warn_level & WarnParser))
|| (code == QMakeHandler::WarnDeprecated && !(Option::warn_level & WarnDeprecated)))
return;
pfx = QString::fromLatin1("WARNING: ");
}
if (lineNo > 0)
fprintf(stderr, "%s%s:%d: %s\n", qPrintable(pfx), qPrintable(fileName), lineNo, qPrintable(msg));
else if (lineNo)
fprintf(stderr, "%s%s: %s\n", qPrintable(pfx), qPrintable(fileName), qPrintable(msg));
else
fprintf(stderr, "%s%s\n", qPrintable(pfx), qPrintable(msg));
}
void EvalHandler::fileMessage(const QString &msg)
{
fprintf(stderr, "%s\n", qPrintable(msg));
}
void EvalHandler::aboutToEval(ProFile *, ProFile *, EvalFileType)
{
}
void EvalHandler::doneWithEval(ProFile *)
{
}
class QMakeCacheClearItem {
private:
qmakeCacheClearFunc func;
@ -693,8 +662,8 @@ qmakeAddCacheClear(qmakeCacheClearFunc func, void **data)
QString qmake_libraryInfoFile()
{
if(!Option::qmake_abslocation.isEmpty())
return QDir(QFileInfo(Option::qmake_abslocation).absolutePath()).filePath("qt.conf");
if (!Option::globals->qmake_abslocation.isEmpty())
return QDir(QFileInfo(Option::globals->qmake_abslocation).absolutePath()).filePath("qt.conf");
return QString();
}

View File

@ -42,7 +42,10 @@
#ifndef OPTION_H
#define OPTION_H
#include "project.h"
#include <qmakeglobals.h>
#include <qmakeparser.h>
#include <qmakeevaluator.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qfile.h>
@ -69,8 +72,26 @@ enum QMakeWarn {
};
void warn_msg(QMakeWarn t, const char *fmt, ...);
class QMakeProject;
class EvalHandler : public QMakeHandler {
public:
void message(int type, const QString &msg, const QString &fileName, int lineNo);
void fileMessage(const QString &msg);
void aboutToEval(ProFile *, ProFile *, EvalFileType);
void doneWithEval(ProFile *);
};
struct Option
{
static EvalHandler evalHandler;
static QMakeGlobals *globals;
static ProFileCache *proFileCache;
static QMakeParser *parser;
//simply global convenience
static QString libtool_ext;
static QString pkgcfg_ext;
@ -88,7 +109,6 @@ struct Option
static QString lex_mod;
static QString yacc_mod;
static QString dir_sep;
static QString dirlist_sep;
static QString pro_ext;
static QString res_ext;
static char field_sep;
@ -160,15 +180,12 @@ struct Option
static QMAKE_MODE qmake_mode;
//all modes
static QString qmake_abslocation;
static QStringList qmake_args;
static QFile output;
static QString output_dir;
static int debug_level;
static int warn_level;
static bool recursive;
static QStringList before_user_vars, after_user_vars;
static QString user_template, user_template_prefix;
//QMAKE_*_PROPERTY options
struct prop {
@ -183,17 +200,11 @@ struct Option
//QMAKE_GENERATE_MAKEFILE options
struct mkfile {
static QString qmakespec;
static QString xqmakespec;
static bool do_cache;
static bool do_deps;
static bool do_mocs;
static bool do_dep_heuristics;
static bool do_preprocess;
static bool do_stub_makefile;
static QString source_root;
static QString build_root;
static QString cachefile;
static int cachefile_depth;
static QStringList project_files;
};
@ -203,7 +214,7 @@ private:
};
inline QString fixEnvVariables(const QString &x) { return Option::fixString(x, Option::FixEnvVars); }
inline QStringList splitPathList(const QString &paths) { return paths.isEmpty() ? QStringList() : paths.split(Option::dirlist_sep); }
inline QStringList splitPathList(const QString &paths) { return paths.isEmpty() ? QStringList() : paths.split(Option::globals->dirlist_sep); }
QT_END_NAMESPACE

File diff suppressed because it is too large Load Diff

View File

@ -42,165 +42,54 @@
#ifndef PROJECT_H
#define PROJECT_H
#include <proitems.h>
#include <qstringlist.h>
#include <qtextstream.h>
#include <qstring.h>
#include <qstack.h>
#include <qhash.h>
#include <qmetatype.h>
#include <qmakeevaluator.h>
QT_BEGIN_NAMESPACE
class QMakeProperty;
struct ParsableBlock;
struct IteratorBlock;
struct FunctionBlock;
class QMakeProject
class QMakeProject : private QMakeEvaluator
{
struct ScopeBlock
{
enum TestStatus { TestNone, TestFound, TestSeek };
ScopeBlock() : iterate(0), ignore(false), else_status(TestNone) { }
ScopeBlock(bool i) : iterate(0), ignore(i), else_status(TestNone) { }
~ScopeBlock();
IteratorBlock *iterate;
uint ignore : 1, else_status : 2;
};
friend struct ParsableBlock;
friend struct IteratorBlock;
friend struct FunctionBlock;
QStack<ScopeBlock> scope_blocks;
QStack<FunctionBlock *> function_blocks;
IteratorBlock *iterator;
FunctionBlock *function;
QHash<QString, FunctionBlock*> testFunctions, replaceFunctions;
bool host_build;
bool need_restart;
bool own_prop;
bool backslashWarned;
QString project_build_root;
QString conffile;
QString superfile;
QString cachefile;
QString real_spec, short_spec;
QString pfile;
QMakeProperty *prop;
void reset();
ProStringList extra_configs;
ProValueMap extra_vars;
QHash<QString, QStringList> vars, init_vars, base_vars;
bool parse(const QString &text, QHash<QString, QStringList> &place, int line_count=1);
enum IncludeStatus {
IncludeSuccess,
IncludeFeatureAlreadyLoaded,
IncludeFailure,
IncludeNoExist,
IncludeParseFailure
};
enum IncludeFlags {
IncludeFlagNone = 0x00,
IncludeFlagFeature = 0x01,
IncludeFlagNewParser = 0x02,
IncludeFlagNewProject = 0x04
};
IncludeStatus doProjectInclude(QString file, uchar flags, QHash<QString, QStringList> &place);
bool doProjectCheckReqs(const QStringList &deps, QHash<QString, QStringList> &place);
bool doVariableReplace(QString &str, QHash<QString, QStringList> &place);
QStringList doVariableReplaceExpand(const QString &str, QHash<QString, QStringList> &place, bool *ok=0);
void init(QMakeProperty *);
void cleanup();
void loadDefaults();
void setupProject();
QStringList &values(const QString &v, QHash<QString, QStringList> &place);
QStringList magicValues(const QString &v, const QHash<QString, QStringList> &place) const;
QStringList qmakeFeaturePaths();
QString m_projectFile;
public:
QMakeProject(QMakeProperty *p = 0) { init(p); }
QMakeProject(QMakeProject *p, const QHash<QString, QStringList> *nvars=0);
~QMakeProject();
QMakeProject();
QMakeProject(QMakeProject *p);
void setExtraVars(const ProValueMap &_vars) { extra_vars = _vars; }
void setExtraConfigs(const ProStringList &_cfgs) { extra_configs = _cfgs; }
bool read(const QString &project, LoadFlags what = LoadAll);
enum { ReadProFile=0x01, ReadSetup=0x02, ReadFeatures=0x04, ReadAll=0xFF };
inline bool parse(const QString &text) { return parse(text, vars); }
bool read(const QString &project, uchar cmd=ReadAll);
bool read(uchar cmd=ReadAll);
QString projectFile() const { return m_projectFile; }
QString buildRoot() const { return m_buildRoot; }
QString confFile() const { return m_conffile; }
QString cacheFile() const { return m_cachefile; }
QString specDir() const { return m_qmakespecFull; }
QStringList userExpandFunctions() { return replaceFunctions.keys(); }
QStringList userTestFunctions() { return testFunctions.keys(); }
QString projectFile();
QString buildRoot() const { return project_build_root; }
QString confFile() const { return conffile; }
QString cacheFile() const { return cachefile; }
QString specDir() const { return real_spec; }
inline QMakeProperty *properties() { return prop; }
bool doProjectTest(QString str, QHash<QString, QStringList> &place);
bool doProjectTest(QString func, const QString &params,
QHash<QString, QStringList> &place);
bool doProjectTest(QString func, QStringList args,
QHash<QString, QStringList> &place);
bool doProjectTest(QString func, QList<QStringList> args,
QHash<QString, QStringList> &place);
QStringList doProjectExpand(QString func, const QString &params,
QHash<QString, QStringList> &place);
QStringList doProjectExpand(QString func, QStringList args,
QHash<QString, QStringList> &place);
QStringList doProjectExpand(QString func, QList<QStringList> args,
QHash<QString, QStringList> &place);
QStringList expand(const QString &v);
QString expand(const QString &v, const QString &file, int line);
ProString expand(const QString &v, const QString &file, int line);
QStringList expand(const ProKey &func, const QList<ProStringList> &args);
bool test(const QString &v);
bool test(const QString &v)
{ m_current.clear(); return evaluateConditional(v, QStringLiteral("(generator)")); }
bool test(const ProKey &func, const QList<ProStringList> &args);
bool isActiveConfig(const QString &x, bool regex=false,
QHash<QString, QStringList> *place=NULL);
bool isSet(const ProKey &v) const { return (*(const ProValueMap *)&vars).contains(v); }
bool isSet(const ProKey &v) const { return m_valuemapStack.first().contains(v); }
bool isEmpty(const ProKey &v) const;
ProStringList values(const ProKey &v) const { return (*(const ProValueMap *)&vars)[v]; }
ProStringList &values(const ProKey &v) { return (*(ProValueMap *)&vars)[v]; }
ProString first(const ProKey &v) const;
ProStringList &values(const ProKey &v) { return valuesRef(v); }
int intValue(const ProKey &v, int defaultValue = 0) const;
const ProValueMap &variables() const { return *(const ProValueMap *)&vars; }
ProValueMap &variables() { return *(ProValueMap *)&vars; }
const ProValueMap &variables() const { return m_valuemapStack.first(); }
ProValueMap &variables() { return m_valuemapStack.first(); }
void dump() const;
bool isHostBuild() const { return host_build; }
protected:
friend class MakefileGenerator;
bool read(const QString &file, QHash<QString, QStringList> &place);
bool read(QTextStream &file, QHash<QString, QStringList> &place);
using QMakeEvaluator::LoadFlags;
using QMakeEvaluator::setExtraVars;
using QMakeEvaluator::setExtraConfigs;
using QMakeEvaluator::loadSpec;
using QMakeEvaluator::evaluateFeatureFile;
using QMakeEvaluator::evaluateConfigFeatures;
using QMakeEvaluator::evaluateExpression;
using QMakeEvaluator::values;
using QMakeEvaluator::first;
using QMakeEvaluator::isActiveConfig;
using QMakeEvaluator::isHostBuild;
using QMakeEvaluator::dirSep;
};
Q_DECLARE_METATYPE(QMakeProject*)
inline QString QMakeProject::projectFile()
{
return pfile;
}
inline ProString QMakeProject::first(const ProKey &v) const
{
const ProStringList &vals = values(v);
if(vals.isEmpty())
return ProString("");
return vals.first();
}
inline int QMakeProject::intValue(const ProKey &v, int defaultValue) const
{

View File

@ -5,7 +5,10 @@ DEFINES += QT_NO_TEXTCODEC QT_NO_LIBRARY QT_NO_COMPRESS QT_NO_UNICODETABLES \
QT_NO_GEOM_VARIANT QT_NO_DATASTREAM
#qmake code
SOURCES += project.cpp property.cpp main.cpp generators/makefile.cpp \
SOURCES += project.cpp property.cpp main.cpp \
library/ioutils.cpp library/proitems.cpp library/qmakeglobals.cpp \
library/qmakeparser.cpp library/qmakeevaluator.cpp library/qmakebuiltins.cpp \
generators/makefile.cpp \
generators/unix/unixmake2.cpp generators/unix/unixmake.cpp meta.cpp \
option.cpp generators/win32/winmakefile.cpp generators/win32/mingw_make.cpp \
generators/makefiledeps.cpp generators/metamakefile.cpp generators/mac/pbuilder_pbx.cpp \
@ -18,7 +21,8 @@ SOURCES += project.cpp property.cpp main.cpp generators/makefile.cpp \
generators/win32/cesdkhandler.cpp
HEADERS += project.h property.h \
library/qmake_global.h library/proitems.h \
library/qmake_global.h library/ioutils.h library/proitems.h library/qmakeglobals.h \
library/qmakeparser.h library/qmakeevaluator.h library/qmakeevaluator_p.h \
generators/makefile.h \
generators/unix/unixmake.h meta.h option.h cachekeys.h \
generators/win32/winmakefile.h generators/win32/mingw_make.h generators/projectgenerator.h \

View File

@ -6,7 +6,8 @@
option(host_build)
CONFIG += console bootstrap
CONFIG -= qt shared app_bundle uic
DEFINES += QT_BUILD_QMAKE QT_BOOTSTRAPPED
DEFINES += QT_BUILD_QMAKE QT_BOOTSTRAPPED \
PROEVALUATOR_FULL PROEVALUATOR_DEBUG
DESTDIR = ../bin/
OBJECTS_DIR = .

View File

@ -484,7 +484,7 @@ void tst_qmake::bundle_spaces()
void tst_qmake::includefunction()
{
QString workDir = base_path + "/testdata/include_function";
QString warningMsg("Unable to find file for inclusion");
QRegExp warningMsg("Include file .* not found");
QVERIFY(test_compiler.qmake( workDir, "include_existing_file"));
QVERIFY(!test_compiler.commandOutput().contains(warningMsg));