do .qmake.cache search per sub-project

follow suit with qmake ...

Change-Id: I40ed12d8cba4ae39b80f47e34c370f40656b9d83
Reviewed-by: Daniel Teske <daniel.teske@nokia.com>
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@nokia.com>
This commit is contained in:
Oswald Buddenhagen
2012-06-13 19:37:50 +02:00
parent bc4c499684
commit 20baedf3b5
4 changed files with 106 additions and 59 deletions

View File

@@ -68,9 +68,22 @@ QT_BEGIN_NAMESPACE
using namespace ProStringConstants; using namespace ProStringConstants;
#define fL1S(s) QString::fromLatin1(s) #define fL1S(s) QString::fromLatin1(s)
QMakeBaseEnv::QMakeBaseEnv()
: evaluator(0)
{
#ifdef PROEVALUATOR_THREAD_SAFE
inProgress = false;
#endif
}
QMakeBaseEnv::~QMakeBaseEnv()
{
delete evaluator;
}
namespace ProFileEvaluatorInternal { namespace ProFileEvaluatorInternal {
QMakeStatics statics; QMakeStatics statics;
} }
@@ -159,6 +172,9 @@ void QMakeEvaluator::initFrom(const QMakeEvaluator &other)
Q_ASSERT_X(&other, "QMakeEvaluator::visitProFile", "Project not prepared"); Q_ASSERT_X(&other, "QMakeEvaluator::visitProFile", "Project not prepared");
m_functionDefs = other.m_functionDefs; m_functionDefs = other.m_functionDefs;
m_valuemapStack = other.m_valuemapStack; m_valuemapStack = other.m_valuemapStack;
m_qmakespec = other.m_qmakespec;
m_qmakespecName = other.m_qmakespecName;
m_featureRoots = other.m_featureRoots;
} }
//////// Evaluator tools ///////// //////// Evaluator tools /////////
@@ -938,14 +954,9 @@ bool QMakeEvaluator::prepareProject()
} }
} }
if (!qmake_cache.isEmpty()) { if (!qmake_cache.isEmpty()) {
QMakeEvaluator evaluator(m_option, m_parser, m_handler); m_cachefile = qmake_cache;
if (!evaluator.evaluateFileDirect(qmake_cache, QMakeHandler::EvalConfigFile, LoadProOnly)) m_buildRoot = QFileInfo(qmake_cache).path();
return false;
if (m_option->qmakespec.isEmpty())
m_option->qmakespec = evaluator.first(ProString("QMAKESPEC")).toQString();
} }
m_option->cachefile = qmake_cache;
valuesRef(ProString("_QMAKE_CACHE_")) << ProString(qmake_cache, NoHash);
} }
return true; return true;
} }
@@ -955,6 +966,18 @@ bool QMakeEvaluator::loadSpec()
loadDefaults(); loadDefaults();
QString qmakespec = m_option->expandEnvVars(m_option->qmakespec); QString qmakespec = m_option->expandEnvVars(m_option->qmakespec);
{
QMakeEvaluator evaluator(m_option, m_parser, m_handler);
if (!m_cachefile.isEmpty()) {
valuesRef(ProString("_QMAKE_CACHE_")) << ProString(m_cachefile, NoHash);
if (!evaluator.evaluateFileDirect(m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly))
return false;
}
if (qmakespec.isEmpty())
qmakespec = evaluator.first(ProString("QMAKESPEC")).toQString();
}
if (qmakespec.isEmpty()) if (qmakespec.isEmpty())
qmakespec = QLatin1String("default"); qmakespec = QLatin1String("default");
if (IoUtils::isRelativePath(qmakespec)) { if (IoUtils::isRelativePath(qmakespec)) {
@@ -969,32 +992,32 @@ bool QMakeEvaluator::loadSpec()
return false; return false;
} }
cool: cool:
m_option->qmakespec = QDir::cleanPath(qmakespec); m_qmakespec = QDir::cleanPath(qmakespec);
if (!evaluateFeatureFile(QLatin1String("spec_pre.prf"))) if (!evaluateFeatureFile(QLatin1String("spec_pre.prf")))
return false; return false;
QString spec = m_option->qmakespec + QLatin1String("/qmake.conf"); QString spec = m_qmakespec + QLatin1String("/qmake.conf");
if (!evaluateFileDirect(spec, QMakeHandler::EvalConfigFile, LoadProOnly)) { if (!evaluateFileDirect(spec, QMakeHandler::EvalConfigFile, LoadProOnly)) {
m_handler->configError( m_handler->configError(
fL1S("Could not read qmake configuration file %1").arg(spec)); fL1S("Could not read qmake configuration file %1").arg(spec));
return false; return false;
} }
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
QString real_spec = QFileInfo(m_option->qmakespec).canonicalFilePath(); QString real_spec = QFileInfo(m_qmakespec).canonicalFilePath();
#else #else
// We can't resolve symlinks as they do on Unix, so configure.exe puts // We can't resolve symlinks as they do on Unix, so configure.exe puts
// the source of the qmake.conf at the end of the default/qmake.conf in // the source of the qmake.conf at the end of the default/qmake.conf in
// the QMAKESPEC_ORIGINAL variable. // the QMAKESPEC_ORIGINAL variable.
const ProString &orig_spec = first(ProString("QMAKESPEC_ORIGINAL")); const ProString &orig_spec = first(ProString("QMAKESPEC_ORIGINAL"));
QString real_spec = orig_spec.isEmpty() ? m_option->qmakespec : orig_spec.toQString(); QString real_spec = orig_spec.isEmpty() ? m_qmakespec : orig_spec.toQString();
#endif #endif
m_option->qmakespec_name = IoUtils::fileName(real_spec).toString(); m_qmakespecName = IoUtils::fileName(real_spec).toString();
if (!evaluateFeatureFile(QLatin1String("spec_post.prf"))) if (!evaluateFeatureFile(QLatin1String("spec_post.prf")))
return false; return false;
// The spec extends the feature search path, so invalidate the cache. // The spec extends the feature search path, so invalidate the cache.
m_option->feature_roots.clear(); m_featureRoots.clear();
if (!m_option->cachefile.isEmpty() if (!m_cachefile.isEmpty()
&& !evaluateFileDirect(m_option->cachefile, QMakeHandler::EvalConfigFile, LoadProOnly)) { && !evaluateFileDirect(m_cachefile, QMakeHandler::EvalConfigFile, LoadProOnly)) {
return false; return false;
} }
return true; return true;
@@ -1029,35 +1052,46 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
return ReturnFalse; return ReturnFalse;
if (flags & LoadPreFiles) { if (flags & LoadPreFiles) {
if (!prepareProject())
return ReturnFalse;
#ifdef PROEVALUATOR_THREAD_SAFE
m_option->mutex.lock();
#endif
QMakeBaseEnv **baseEnvPtr = &m_option->baseEnvs[QMakeBaseKey(m_buildRoot)];
if (!*baseEnvPtr)
*baseEnvPtr = new QMakeBaseEnv;
QMakeBaseEnv *baseEnv = *baseEnvPtr;
#ifdef PROEVALUATOR_THREAD_SAFE #ifdef PROEVALUATOR_THREAD_SAFE
{ {
QMutexLocker locker(&m_option->mutex); QMutexLocker locker(&baseEnv->mutex);
if (m_option->base_inProgress) { m_option->mutex.unlock();
if (baseEnv->inProgress) {
QThreadPool::globalInstance()->releaseThread(); QThreadPool::globalInstance()->releaseThread();
m_option->cond.wait(&m_option->mutex); baseEnv->cond.wait(&baseEnv->mutex);
QThreadPool::globalInstance()->reserveThread(); QThreadPool::globalInstance()->reserveThread();
if (!m_option->base_isOk) if (!baseEnv->isOk)
return ReturnFalse; return ReturnFalse;
} else } else
#endif #endif
if (!m_option->base_eval) { if (!baseEnv->evaluator) {
#ifdef PROEVALUATOR_THREAD_SAFE #ifdef PROEVALUATOR_THREAD_SAFE
m_option->base_inProgress = true; baseEnv->inProgress = true;
locker.unlock(); locker.unlock();
#endif #endif
bool ok = prepareProject(); QMakeEvaluator *baseEval = new QMakeEvaluator(m_option, m_parser, m_handler);
baseEnv->evaluator = baseEval;
if (ok) { baseEval->m_cachefile = m_cachefile;
m_option->base_eval = new QMakeEvaluator(m_option, m_parser, m_handler); baseEval->m_buildRoot = m_buildRoot;
ok = m_option->base_eval->loadSpec(); bool ok = baseEval->loadSpec();
}
#ifdef PROEVALUATOR_THREAD_SAFE #ifdef PROEVALUATOR_THREAD_SAFE
locker.relock(); locker.relock();
m_option->base_isOk = ok; baseEnv->isOk = ok;
m_option->base_inProgress = false; baseEnv->inProgress = false;
m_option->cond.wakeAll(); baseEnv->cond.wakeAll();
#endif #endif
if (!ok) if (!ok)
@@ -1067,7 +1101,7 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::visitProFile(
} }
#endif #endif
initFrom(*m_option->base_eval); initFrom(*baseEnv->evaluator);
} }
m_handler->aboutToEval(currentProFile(), pro, type); m_handler->aboutToEval(currentProFile(), pro, type);
@@ -1147,8 +1181,8 @@ QStringList QMakeEvaluator::qmakeFeaturePaths() const
feature_roots += propertyValue(QLatin1String("QMAKEFEATURES"), false).split( feature_roots += propertyValue(QLatin1String("QMAKEFEATURES"), false).split(
m_option->dirlist_sep, QString::SkipEmptyParts); m_option->dirlist_sep, QString::SkipEmptyParts);
if (!m_option->cachefile.isEmpty()) { if (!m_cachefile.isEmpty()) {
QString path = m_option->cachefile.left(m_option->cachefile.lastIndexOf((ushort)'/')); QString path = m_cachefile.left(m_cachefile.lastIndexOf((ushort)'/'));
foreach (const QString &concat_it, concat) foreach (const QString &concat_it, concat)
feature_roots << (path + concat_it); feature_roots << (path + concat_it);
} }
@@ -1157,11 +1191,11 @@ QStringList QMakeEvaluator::qmakeFeaturePaths() const
foreach (const QString &concat_it, concat) foreach (const QString &concat_it, concat)
feature_roots << (item + mkspecs_concat + concat_it); feature_roots << (item + mkspecs_concat + concat_it);
if (!m_option->qmakespec.isEmpty()) { if (!m_qmakespec.isEmpty()) {
feature_roots << (m_option->qmakespec + features_concat); feature_roots << (m_qmakespec + features_concat);
// Also check directly under the root directory of the mkspecs collection // Also check directly under the root directory of the mkspecs collection
QDir specdir(m_option->qmakespec); QDir specdir(m_qmakespec);
while (!specdir.isRoot() && specdir.cdUp()) { while (!specdir.isRoot() && specdir.cdUp()) {
const QString specpath = specdir.path(); const QString specpath = specdir.path();
if (specpath.endsWith(mkspecs_concat)) { if (specpath.endsWith(mkspecs_concat)) {
@@ -1512,7 +1546,7 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
QRegExp re(cfg, Qt::CaseSensitive, QRegExp::Wildcard); QRegExp re(cfg, Qt::CaseSensitive, QRegExp::Wildcard);
// mkspecs // mkspecs
if (re.exactMatch(m_option->qmakespec_name)) if (re.exactMatch(m_qmakespecName))
return true; return true;
// CONFIG variable // CONFIG variable
@@ -1524,7 +1558,7 @@ bool QMakeEvaluator::isActiveConfig(const QString &config, bool regex)
} }
} else { } else {
// mkspecs // mkspecs
if (m_option->qmakespec_name == config) if (m_qmakespecName == config)
return true; return true;
// CONFIG variable // CONFIG variable
@@ -1785,19 +1819,19 @@ bool QMakeEvaluator::evaluateFeatureFile(const QString &fileName)
if (!fn.endsWith(QLatin1String(".prf"))) if (!fn.endsWith(QLatin1String(".prf")))
fn += QLatin1String(".prf"); fn += QLatin1String(".prf");
if (m_option->feature_roots.isEmpty()) if (m_featureRoots.isEmpty())
m_option->feature_roots = qmakeFeaturePaths(); m_featureRoots = qmakeFeaturePaths();
int start_root = 0; int start_root = 0;
QString currFn = currentFileName(); QString currFn = currentFileName();
if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) { if (IoUtils::fileName(currFn) == IoUtils::fileName(fn)) {
for (int root = 0; root < m_option->feature_roots.size(); ++root) for (int root = 0; root < m_featureRoots.size(); ++root)
if (currFn == m_option->feature_roots.at(root) + fn) { if (currFn == m_featureRoots.at(root) + fn) {
start_root = root + 1; start_root = root + 1;
break; break;
} }
} }
for (int root = start_root; root < m_option->feature_roots.size(); ++root) { for (int root = start_root; root < m_featureRoots.size(); ++root) {
QString fname = m_option->feature_roots.at(root) + fn; QString fname = m_featureRoots.at(root) + fn;
if (IoUtils::exists(fname)) { if (IoUtils::exists(fname)) {
fn = fname; fn = fname;
goto cool; goto cool;

View File

@@ -198,6 +198,11 @@ public:
QString m_outputDir; QString m_outputDir;
int m_listCount; int m_listCount;
QString m_qmakespec;
QString m_qmakespecName;
QString m_cachefile;
QString m_buildRoot;
QStringList m_featureRoots;
ProFunctionDefs m_functionDefs; ProFunctionDefs m_functionDefs;
ProStringList m_returnValue; ProStringList m_returnValue;
QStack<ProValueMap> m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii. QStack<ProValueMap> m_valuemapStack; // VariableName must be us-ascii, the content however can be non-us-ascii.

View File

@@ -104,16 +104,11 @@ QMakeGlobals::QMakeGlobals()
dir_sep = QLatin1Char('/'); dir_sep = QLatin1Char('/');
#endif #endif
qmakespec = getEnv(QLatin1String("QMAKESPEC")); qmakespec = getEnv(QLatin1String("QMAKESPEC"));
#ifdef PROEVALUATOR_THREAD_SAFE
base_inProgress = false;
#endif
base_eval = 0;
} }
QMakeGlobals::~QMakeGlobals() QMakeGlobals::~QMakeGlobals()
{ {
delete base_eval; qDeleteAll(baseEnvs);
} }
void QMakeGlobals::setCommandLineArguments(const QStringList &args) void QMakeGlobals::setCommandLineArguments(const QStringList &args)

View File

@@ -50,6 +50,25 @@ QT_BEGIN_NAMESPACE
class QMakeEvaluator; class QMakeEvaluator;
typedef QString QMakeBaseKey;
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 QMakeGlobals class QMAKE_EXPORT QMakeGlobals
{ {
public: public:
@@ -81,18 +100,12 @@ private:
QString getEnv(const QString &) const; QString getEnv(const QString &) const;
QStringList getPathListEnv(const QString &var) const; QStringList getPathListEnv(const QString &var) const;
QStringList feature_roots;
QString qmakespec_name;
QString precmds, postcmds; QString precmds, postcmds;
#ifdef PROEVALUATOR_THREAD_SAFE #ifdef PROEVALUATOR_THREAD_SAFE
QMutex mutex; QMutex mutex;
QWaitCondition cond;
bool base_inProgress;
// The coupling of this flag to thread safety exists because for other
// use cases failure is immediately fatal anyway.
bool base_isOk;
#endif #endif
QMakeEvaluator *base_eval; QHash<QMakeBaseKey, QMakeBaseEnv *> baseEnvs;
friend class QMakeEvaluator; friend class QMakeEvaluator;
}; };