📄 project.cpp
字号:
/****************************************************************************
**
** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
**
** This file is part of the qmake application of the Qt Toolkit.
**
** This file may be used under the terms of the GNU General Public
** License version 2.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 GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "project.h"
#include "property.h"
#include "option.h"
#include "cachekeys.h"
#include <qdatetime.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qdir.h>
#include <qregexp.h>
#include <qtextstream.h>
#include <qstack.h>
#include <qhash.h>
#ifdef Q_OS_UNIX
# include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef Q_OS_WIN32
#define QT_POPEN _popen
#else
#define QT_POPEN popen
#endif
struct parser_info {
QString file;
int line_no;
bool from_file;
} parser;
static QString remove_quotes(const QString &arg)
{
static bool symbols_init = false;
enum { SINGLEQUOTE, DOUBLEQUOTE };
static ushort symbols[2];
if(!symbols_init) {
symbols_init = true;
symbols[SINGLEQUOTE] = QChar('\'').unicode();
symbols[DOUBLEQUOTE] = QChar('"').unicode();
}
const QChar *arg_data = arg.data();
const ushort first = arg_data->unicode();
const int arg_len = arg.length();
if(first == symbols[SINGLEQUOTE] || first == symbols[DOUBLEQUOTE]) {
const ushort last = (arg_data+arg_len-1)->unicode();
if(last == first)
return arg.mid(1, arg_len-2);
}
return arg;
}
//just a parsable entity
struct ParsableBlock
{
ParsableBlock() { }
virtual ~ParsableBlock() { }
struct Parse {
QString text;
parser_info pi;
Parse(const QString &t) : text(t){ pi = ::parser; }
};
QList<Parse> parser;
protected:
virtual bool continueBlock() = 0;
bool eval(QMakeProject *p, QMap<QString, QStringList> &place);
};
bool ParsableBlock::eval(QMakeProject *p, QMap<QString, QStringList> &place)
{
//save state
parser_info pi = ::parser;
const int block_count = p->scope_blocks.count();
//execute
bool ret = true;
for(int i = 0; i < parser.count(); i++) {
::parser = parser.at(i).pi;
if(!(ret = p->parse(parser.at(i).text, place)) || !continueBlock())
break;
}
//restore state
::parser = pi;
while(p->scope_blocks.count() > block_count)
p->scope_blocks.pop();
return ret;
}
//defined functions
struct FunctionBlock : public ParsableBlock
{
FunctionBlock() : calling_place(0), scope_level(1), cause_return(false) { }
QMap<QString, QStringList> vars;
QMap<QString, QStringList> *calling_place;
QString return_value;
int scope_level;
bool cause_return;
bool exec(const QStringList &args,
QMakeProject *p, QMap<QString, QStringList> &place, QString &functionReturn);
virtual bool continueBlock() { return !cause_return; }
};
bool FunctionBlock::exec(const QStringList &args,
QMakeProject *proj, QMap<QString, QStringList> &place, QString &functionReturn)
{
//save state
#if 1
calling_place = &place;
#else
calling_place = &proj->variables();
#endif
return_value = "";
cause_return = false;
//execute
#if 0
vars = proj->variables();
#else
vars = place;
#endif
vars["ARGS"] = args;
for(int i = 0; i < args.count(); i++)
vars[QString::number(i+1)] = QStringList(args[i]);
bool ret = ParsableBlock::eval(proj, vars);
functionReturn = return_value;
//restore state
calling_place = 0;
return_value.clear();
vars.clear();
return ret;
}
//loops
struct IteratorBlock : public ParsableBlock
{
IteratorBlock() : scope_level(1), loop_forever(false), cause_break(false), cause_next(false) { }
int scope_level;
struct Test {
QString func;
QStringList args;
bool invert;
parser_info pi;
Test(const QString &f, QStringList &a, bool i) : func(f), args(a), invert(i) { pi = ::parser; }
};
QList<Test> test;
QString variable;
bool loop_forever, cause_break, cause_next;
QStringList list;
bool exec(QMakeProject *p, QMap<QString, QStringList> &place);
virtual bool continueBlock() { return !cause_next && !cause_break; }
};
bool IteratorBlock::exec(QMakeProject *p, QMap<QString, QStringList> &place)
{
bool ret = true;
QStringList::Iterator it;
if(!loop_forever)
it = list.begin();
int iterate_count = 0;
//save state
IteratorBlock *saved_iterator = p->iterator;
p->iterator = this;
//do the loop
while(loop_forever || it != list.end()) {
cause_next = cause_break = false;
if(!loop_forever && (*it).isEmpty()) { //ignore empty items
++it;
continue;
}
//set up the loop variable
QStringList va;
if(!variable.isEmpty()) {
va = place[variable];
if(loop_forever)
place[variable] = QStringList(QString::number(iterate_count));
else
place[variable] = QStringList(*it);
}
//do the iterations
bool succeed = true;
for(QList<Test>::Iterator test_it = test.begin(); test_it != test.end(); ++test_it) {
::parser = (*test_it).pi;
succeed = p->doProjectTest((*test_it).func, (*test_it).args, place);
if((*test_it).invert)
succeed = !succeed;
if(!succeed)
break;
}
if(succeed)
ret = ParsableBlock::eval(p, place);
//restore the variable in the map
if(!variable.isEmpty())
place[variable] = va;
//loop counters
if(!loop_forever)
++it;
iterate_count++;
if(!ret || cause_break)
break;
}
//restore state
p->iterator = saved_iterator;
return ret;
}
QMakeProject::ScopeBlock::~ScopeBlock()
{
#if 0
if(iterate)
delete iterate;
#endif
}
static void qmake_error_msg(const QString &msg)
{
fprintf(stderr, "%s:%d: %s\n", parser.file.toLatin1().constData(), parser.line_no,
msg.toLatin1().constData());
}
/*
1) environment variable QMAKEFEATURES (as separated by colons)
2) property variable QMAKEFEATURES (as separated by colons)
3) <project_root> (where .qmake.cache lives) + FEATURES_DIR
4) environment variable QMAKEPATH (as separated by colons) + /mkspecs/FEATURES_DIR
5) your QMAKESPEC/features dir
6) your data_install/mkspecs/FEATURES_DIR
7) your QMAKESPEC/../FEATURES_DIR dir
FEATURES_DIR is defined as:
1) features/(unix|win32|macx)/
2) features/
*/
QStringList qmake_feature_paths(QMakeProperty *prop=0)
{
QStringList concat;
{
const QString base_concat = QDir::separator() + QString("features");
switch(Option::target_mode) {
case Option::TARG_MACX_MODE: //also a unix
concat << base_concat + QDir::separator() + "mac";
concat << base_concat + QDir::separator() + "macx";
concat << base_concat + QDir::separator() + "unix";
break;
case Option::TARG_UNIX_MODE:
concat << base_concat + QDir::separator() + "unix";
break;
case Option::TARG_WIN_MODE:
concat << base_concat + QDir::separator() + "win32";
break;
case Option::TARG_MAC9_MODE:
concat << base_concat + QDir::separator() + "mac";
concat << base_concat + QDir::separator() + "mac9";
break;
case Option::TARG_QNX6_MODE: //also a unix
concat << base_concat + QDir::separator() + "qnx6";
concat << base_concat + QDir::separator() + "unix";
break;
}
concat << base_concat;
}
const QString mkspecs_concat = QDir::separator() + QString("mkspecs");
QStringList feature_roots;
QByteArray mkspec_path = qgetenv("QMAKEFEATURES");
if(!mkspec_path.isNull())
feature_roots += splitPathList(QString::fromLocal8Bit(mkspec_path));
if(prop)
feature_roots += splitPathList(prop->value("QMAKEFEATURES"));
if(!Option::mkfile::cachefile.isEmpty()) {
QString path;
int last_slash = Option::mkfile::cachefile.lastIndexOf(Option::dir_sep);
if(last_slash != -1)
path = Option::fixPathToLocalOS(Option::mkfile::cachefile.left(last_slash));
for(QStringList::Iterator concat_it = concat.begin();
concat_it != concat.end(); ++concat_it)
feature_roots << (path + (*concat_it));
}
QByteArray qmakepath = qgetenv("QMAKEPATH");
if (!qmakepath.isNull()) {
const QStringList lst = splitPathList(QString::fromLocal8Bit(qmakepath));
for(QStringList::ConstIterator it = lst.begin(); it != lst.end(); ++it) {
for(QStringList::Iterator concat_it = concat.begin();
concat_it != concat.end(); ++concat_it)
feature_roots << ((*it) + mkspecs_concat + (*concat_it));
}
}
if(!Option::mkfile::qmakespec.isEmpty())
feature_roots << Option::mkfile::qmakespec + QDir::separator() + "features";
if(!Option::mkfile::qmakespec.isEmpty()) {
QFileInfo specfi(Option::mkfile::qmakespec);
QDir specdir(specfi.absoluteFilePath());
while(!specdir.isRoot()) {
if(!specdir.cdUp() || specdir.isRoot())
break;
if(QFile::exists(specdir.path() + QDir::separator() + "features")) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -