OSDN Git Service

Merge remote branch 'origin/2.1'
[qt-creator-jp/qt-creator-jp.git] / src / plugins / qt4projectmanager / qt4buildconfiguration.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "qt4buildconfiguration.h"
31
32 #include "qt4project.h"
33 #include "qt4target.h"
34 #include "qt4projectmanagerconstants.h"
35 #include "qt4nodes.h"
36 #include "qmakestep.h"
37 #include "makestep.h"
38
39 #include <utils/qtcassert.h>
40 #include <utils/qtcprocess.h>
41 #include <limits>
42 #include <projectexplorer/buildsteplist.h>
43 #include <projectexplorer/projectexplorerconstants.h>
44
45 #include <QtCore/QDebug>
46
47 #include <QtGui/QInputDialog>
48
49 using namespace Qt4ProjectManager;
50 using namespace Qt4ProjectManager::Internal;
51 using namespace ProjectExplorer;
52
53 namespace {
54 const char * const QT4_BC_ID_PREFIX("Qt4ProjectManager.Qt4BuildConfiguration.");
55 const char * const QT4_BC_ID("Qt4ProjectManager.Qt4BuildConfiguration");
56
57 const char * const USE_SHADOW_BUILD_KEY("Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild");
58 const char * const BUILD_DIRECTORY_KEY("Qt4ProjectManager.Qt4BuildConfiguration.BuildDirectory");
59 const char * const TOOLCHAIN_KEY("Qt4ProjectManager.Qt4BuildConfiguration.ToolChain");
60 const char * const BUILD_CONFIGURATION_KEY("Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration");
61 const char * const QT_VERSION_ID_KEY("Qt4ProjectManager.Qt4BuildConfiguration.QtVersionId");
62
63 enum { debug = 0 };
64 }
65
66 Qt4BuildConfiguration::Qt4BuildConfiguration(Qt4Target *target) :
67     BuildConfiguration(target, QLatin1String(QT4_BC_ID)),
68     m_shadowBuild(true),
69     m_qtVersionId(-1),
70     m_toolChainType(-1), // toolChainType() makes sure to return the default toolchainType
71     m_qmakeBuildConfiguration(0),
72     m_subNodeBuild(0)
73 {
74     ctor();
75 }
76
77 Qt4BuildConfiguration::Qt4BuildConfiguration(Qt4Target *target, const QString &id) :
78     BuildConfiguration(target, id),
79     m_shadowBuild(true),
80     m_qtVersionId(-1),
81     m_toolChainType(-1), // toolChainType() makes sure to return the default toolchainType
82     m_qmakeBuildConfiguration(0),
83     m_subNodeBuild(0)
84 {
85     ctor();
86 }
87
88 Qt4BuildConfiguration::Qt4BuildConfiguration(Qt4Target *target, Qt4BuildConfiguration *source) :
89     BuildConfiguration(target, source),
90     m_shadowBuild(source->m_shadowBuild),
91     m_buildDirectory(source->m_buildDirectory),
92     m_qtVersionId(source->m_qtVersionId),
93     m_toolChainType(source->m_toolChainType),
94     m_qmakeBuildConfiguration(source->m_qmakeBuildConfiguration),
95     m_subNodeBuild(0) // temporary value, so not copied
96 {
97     cloneSteps(source);
98     ctor();
99 }
100
101 Qt4BuildConfiguration::~Qt4BuildConfiguration()
102 {
103 }
104
105 QVariantMap Qt4BuildConfiguration::toMap() const
106 {
107     QVariantMap map(BuildConfiguration::toMap());
108     map.insert(QLatin1String(USE_SHADOW_BUILD_KEY), m_shadowBuild);
109     map.insert(QLatin1String(BUILD_DIRECTORY_KEY), m_buildDirectory);
110     map.insert(QLatin1String(QT_VERSION_ID_KEY), m_qtVersionId);
111     map.insert(QLatin1String(TOOLCHAIN_KEY), m_toolChainType);
112     map.insert(QLatin1String(BUILD_CONFIGURATION_KEY), int(m_qmakeBuildConfiguration));
113     return map;
114 }
115
116
117 bool Qt4BuildConfiguration::fromMap(const QVariantMap &map)
118 {
119     if (!BuildConfiguration::fromMap(map))
120         return false;
121
122     int fileVersion = map.value(ProjectExplorer::Constants::USERFILE_PREVIOUS_VERSION_KEY,
123                                 std::numeric_limits<int>::max()).toInt();
124     m_shadowBuild = map.value(QLatin1String(USE_SHADOW_BUILD_KEY), true).toBool();
125     m_buildDirectory = map.value(QLatin1String(BUILD_DIRECTORY_KEY), qt4Target()->defaultBuildDirectory()).toString();
126     m_qtVersionId = map.value(QLatin1String(QT_VERSION_ID_KEY)).toInt();
127     m_toolChainType = map.value(QLatin1String(TOOLCHAIN_KEY)).toInt();
128     m_qmakeBuildConfiguration = QtVersion::QmakeBuildConfigs(map.value(QLatin1String(BUILD_CONFIGURATION_KEY)).toInt());
129
130     // Pick a Qt version if the default version is used:
131     // We assume that the default Qt version was used in earlier versions of Qt creator.
132     // Pick a Qt version that is supporting a desktop.
133     if (m_qtVersionId == 0) {
134         QList<QtVersion *> versions = QtVersionManager::instance()->versions();
135         foreach (QtVersion *v, versions) {
136             if (v->isValid() && v->supportsTargetId(QLatin1String(Constants::DESKTOP_TARGET_ID))) {
137                 m_qtVersionId = v->uniqueId();
138                 break;
139             }
140         }
141         if (m_qtVersionId == 0)
142             m_qtVersionId = versions.at(0)->uniqueId();
143     }
144
145     QtVersion *version = qtVersion();
146     if (fileVersion >= 1) { // we are not upgrading from pre-targets!
147         if (version->isValid() && !version->supportedTargetIds().contains(target()->id())) {
148             qWarning() << "Buildconfiguration" << displayName() << ": Qt" << version->displayName() << "not supported by target" << target()->id();
149             return false;
150         }
151     } else {
152         if (!version->isValid() || !version->supportedTargetIds().contains(target()->id())) {
153             qWarning() << "Buildconfiguration" << displayName() << ": Qt" << version->displayName() << "not supported by target" << target()->id();
154             return false;
155         }
156     }
157
158     if (version->isValid())
159         m_shadowBuild = (m_shadowBuild && version->supportsShadowBuilds());
160
161     QList<ProjectExplorer::ToolChainType> possibleTcs(qt4Target()->filterToolChainTypes(qtVersion()->possibleToolChainTypes()));
162     if (!possibleTcs.contains(toolChainType()))
163         setToolChainType(qt4Target()->preferredToolChainType(possibleTcs));
164
165     if (toolChainType() == ProjectExplorer::ToolChain_INVALID) {
166         qWarning() << "No toolchain available for" << qtVersion()->displayName() << "used in" << target()->id() << "!";
167         return false;
168     }
169
170     return true;
171 }
172
173 void Qt4BuildConfiguration::ctor()
174 {
175     m_buildDirectory = qt4Target()->defaultBuildDirectory();
176     if (m_buildDirectory == target()->project()->projectDirectory())
177         m_shadowBuild = false;
178
179     m_lastEmmitedBuildDirectory = buildDirectory();
180
181     connect(this, SIGNAL(environmentChanged()),
182             this, SLOT(emitBuildDirectoryChanged()));
183
184     QtVersionManager *vm = QtVersionManager::instance();
185     connect(vm, SIGNAL(qtVersionsChanged(QList<int>)),
186             this, SLOT(qtVersionsChanged(QList<int>)));
187 }
188
189 void Qt4BuildConfiguration::emitBuildDirectoryChanged()
190 {
191     if (buildDirectory() != m_lastEmmitedBuildDirectory) {
192         m_lastEmmitedBuildDirectory = buildDirectory();
193         emit buildDirectoryChanged();
194     }
195 }
196
197 void Qt4BuildConfiguration::pickValidQtVersion()
198 {
199     QList<QtVersion *> versions = QtVersionManager::instance()->versionsForTargetId(qt4Target()->id());
200     if (!versions.isEmpty())
201         setQtVersion(versions.at(0));
202     else
203         setQtVersion(QtVersionManager::instance()->emptyVersion());
204 }
205
206 Qt4Target *Qt4BuildConfiguration::qt4Target() const
207 {
208     return static_cast<Qt4Target *>(target());
209 }
210
211 Utils::Environment Qt4BuildConfiguration::baseEnvironment() const
212 {
213     Utils::Environment env = BuildConfiguration::baseEnvironment();
214     qtVersion()->addToEnvironment(env);
215
216     ToolChain *tc = toolChain();
217     if (tc)
218         tc->addToEnvironment(env);
219     return env;
220 }
221
222 /// returns the unexpanded build directory
223 QString Qt4BuildConfiguration::rawBuildDirectory() const
224 {
225     QString workingDirectory;
226     if (m_shadowBuild) {
227         if (!m_buildDirectory.isEmpty())
228             workingDirectory = m_buildDirectory;
229         else
230             workingDirectory = qt4Target()->defaultBuildDirectory();
231     }
232     if (workingDirectory.isEmpty())
233         workingDirectory = target()->project()->projectDirectory();
234     return workingDirectory;
235 }
236
237 /// returns the build directory
238 QString Qt4BuildConfiguration::buildDirectory() const
239 {
240     return QDir::cleanPath(environment().expandVariables(rawBuildDirectory()));
241 }
242
243 /// If only a sub tree should be build this function returns which sub node
244 /// should be build
245 /// \see Qt4BuildConfiguration::setSubNodeBuild
246 Qt4ProjectManager::Internal::Qt4ProFileNode *Qt4BuildConfiguration::subNodeBuild() const
247 {
248     return m_subNodeBuild;
249 }
250
251 /// A sub node build on builds a sub node of the project
252 /// That is triggered by a right click in the project explorer tree
253 /// The sub node to be build is set via this function immediately before
254 /// calling BuildManager::buildProject( BuildConfiguration * )
255 /// and reset immediately afterwards
256 /// That is m_subNodesBuild is set only temporarly
257 void Qt4BuildConfiguration::setSubNodeBuild(Qt4ProjectManager::Internal::Qt4ProFileNode *node)
258 {
259     m_subNodeBuild = node;
260 }
261
262 /// returns whether this is a shadow build configuration or not
263 /// note, even if shadowBuild() returns true, it might be using the
264 /// source directory as the shadow build directory, thus it
265 /// still is a in-source build
266 bool Qt4BuildConfiguration::shadowBuild() const
267 {
268     return m_shadowBuild;
269 }
270
271 /// returns the shadow build directory if set
272 /// \note buildDirectory() is probably the function you want to call
273 QString Qt4BuildConfiguration::shadowBuildDirectory() const
274 {
275     if (m_buildDirectory.isEmpty())
276         return qt4Target()->defaultBuildDirectory();
277     return m_buildDirectory;
278 }
279
280 void Qt4BuildConfiguration::setShadowBuildAndDirectory(bool shadowBuild, const QString &buildDirectory)
281 {
282     QtVersion *version = qtVersion();
283     QString directoryToSet = buildDirectory;
284     bool toSet = (shadowBuild && version->isValid() && version->supportsShadowBuilds());
285     if (m_shadowBuild == toSet && m_buildDirectory == directoryToSet)
286         return;
287
288     m_shadowBuild = toSet;
289     m_buildDirectory = directoryToSet;
290
291     emit environmentChanged();
292     emitBuildDirectoryChanged();
293     emit proFileEvaluateNeeded(this);
294 }
295
296 ProjectExplorer::ToolChain *Qt4BuildConfiguration::toolChain() const
297 {
298     const ProjectExplorer::ToolChainType tct = toolChainType();
299     return qtVersion()->toolChain(tct);
300 }
301
302 QString Qt4BuildConfiguration::makeCommand() const
303 {
304     ToolChain *tc = toolChain();
305     return tc ? tc->makeCommand() : "make";
306 }
307
308 static inline QString symbianMakeTarget(QtVersion::QmakeBuildConfigs buildConfig,
309                                         const QString &type)
310 {
311     QString rc = (buildConfig & QtVersion::DebugBuild) ?
312                  QLatin1String("debug-") : QLatin1String("release-");
313     rc += type;
314     return rc;
315 }
316
317 QString Qt4BuildConfiguration::defaultMakeTarget() const
318 {
319     ToolChain *tc = toolChain();
320     if (!tc)
321         return QString();
322     const QtVersion::QmakeBuildConfigs buildConfig = qmakeBuildConfiguration();
323
324     switch (tc->type()) {
325     case ProjectExplorer::ToolChain_GCCE:
326         return symbianMakeTarget(buildConfig, QLatin1String("gcce"));
327     case ProjectExplorer::ToolChain_RVCT_ARMV5:
328         return symbianMakeTarget(buildConfig, QLatin1String("armv5"));
329     case ProjectExplorer::ToolChain_RVCT_ARMV6:
330         return symbianMakeTarget(buildConfig, QLatin1String("armv6"));
331     case ProjectExplorer::ToolChain_RVCT_ARMV5_GNUPOC:
332     case ProjectExplorer::ToolChain_GCCE_GNUPOC:
333     default:
334         break;
335     }
336     return QString();
337 }
338
339 QString Qt4BuildConfiguration::makefile() const
340 {
341     if (qt4Target()->id() == Constants::S60_DEVICE_TARGET_ID)
342         return QString();
343     return qt4Target()->qt4Project()->rootProjectNode()->makefile();
344 }
345
346 QtVersion *Qt4BuildConfiguration::qtVersion() const
347 {
348     QtVersionManager *vm = QtVersionManager::instance();
349     return vm->version(m_qtVersionId);
350 }
351
352 void Qt4BuildConfiguration::setQtVersion(QtVersion *version)
353 {
354     Q_ASSERT(version);
355
356     if (m_qtVersionId == version->uniqueId())
357         return;
358
359     m_qtVersionId = version->uniqueId();
360
361     if (!version->possibleToolChainTypes().contains(ProjectExplorer::ToolChainType(m_toolChainType))) {
362         QList<ProjectExplorer::ToolChainType> candidates =
363                 qt4Target()->filterToolChainTypes(qtVersion()->possibleToolChainTypes());
364         if (candidates.isEmpty())
365             m_toolChainType = ProjectExplorer::ToolChain_INVALID;
366         else
367             m_toolChainType = candidates.first();
368     }
369
370     m_shadowBuild = m_shadowBuild && qtVersion()->supportsShadowBuilds();
371
372     emit proFileEvaluateNeeded(this);
373     emit qtVersionChanged();
374     emit environmentChanged();
375     emitBuildDirectoryChanged();
376 }
377
378 void Qt4BuildConfiguration::setToolChainType(ProjectExplorer::ToolChainType type)
379 {
380     if (!qt4Target()->filterToolChainTypes(qtVersion()->possibleToolChainTypes()).contains(type)
381         || m_toolChainType == type)
382         return;
383
384     m_toolChainType = type;
385
386     emit proFileEvaluateNeeded(this);
387     emit toolChainTypeChanged();
388     emit environmentChanged();
389     emitBuildDirectoryChanged();
390 }
391
392 ProjectExplorer::ToolChainType Qt4BuildConfiguration::toolChainType() const
393 {
394     return ProjectExplorer::ToolChainType(m_toolChainType);
395 }
396
397 QtVersion::QmakeBuildConfigs Qt4BuildConfiguration::qmakeBuildConfiguration() const
398 {
399     return m_qmakeBuildConfiguration;
400 }
401
402 void Qt4BuildConfiguration::setQMakeBuildConfiguration(QtVersion::QmakeBuildConfigs config)
403 {
404     if (m_qmakeBuildConfiguration == config)
405         return;
406     m_qmakeBuildConfiguration = config;
407
408     emit proFileEvaluateNeeded(this);
409     emit qmakeBuildConfigurationChanged();
410 }
411
412 void Qt4BuildConfiguration::emitProFileEvaluteNeeded()
413 {
414     emit proFileEvaluateNeeded(this);
415 }
416
417 void Qt4BuildConfiguration::emitQMakeBuildConfigurationChanged()
418 {
419     emit qmakeBuildConfigurationChanged();
420 }
421
422 void Qt4BuildConfiguration::emitBuildDirectoryInitialized()
423 {
424     emit buildDirectoryInitialized();
425 }
426
427 void Qt4BuildConfiguration::emitS60CreatesSmartInstallerChanged()
428 {
429     emit s60CreatesSmartInstallerChanged();
430 }
431
432
433 QStringList Qt4BuildConfiguration::configCommandLineArguments() const
434 {
435     QStringList result;
436     QtVersion::QmakeBuildConfigs defaultBuildConfiguration = qtVersion()->defaultBuildConfig();
437     QtVersion::QmakeBuildConfigs userBuildConfiguration = m_qmakeBuildConfiguration;
438     if ((defaultBuildConfiguration & QtVersion::BuildAll) && !(userBuildConfiguration & QtVersion::BuildAll))
439         result << "CONFIG-=debug_and_release";
440
441     if (!(defaultBuildConfiguration & QtVersion::BuildAll) && (userBuildConfiguration & QtVersion::BuildAll))
442         result << "CONFIG+=debug_and_release";
443     if ((defaultBuildConfiguration & QtVersion::DebugBuild)
444             && !(userBuildConfiguration & QtVersion::DebugBuild)
445             && !(userBuildConfiguration & QtVersion::BuildAll))
446         result << "CONFIG+=release";
447     if (!(defaultBuildConfiguration & QtVersion::DebugBuild)
448             && (userBuildConfiguration & QtVersion::DebugBuild)
449             && !(userBuildConfiguration & QtVersion::BuildAll))
450         result << "CONFIG+=debug";
451     return result;
452 }
453
454 QMakeStep *Qt4BuildConfiguration::qmakeStep() const
455 {
456     QMakeStep *qs = 0;
457     BuildStepList *bsl = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
458     Q_ASSERT(bsl);
459     for (int i = 0; i < bsl->count(); ++i)
460         if ((qs = qobject_cast<QMakeStep *>(bsl->at(i))) != 0)
461             return qs;
462     return 0;
463 }
464
465 MakeStep *Qt4BuildConfiguration::makeStep() const
466 {
467     MakeStep *ms = 0;
468     BuildStepList *bsl = stepList(ProjectExplorer::Constants::BUILDSTEPS_BUILD);
469     Q_ASSERT(bsl);
470     for (int i = 0; i < bsl->count(); ++i)
471         if ((ms = qobject_cast<MakeStep *>(bsl->at(i))) != 0)
472             return ms;
473     return 0;
474 }
475
476 void Qt4BuildConfiguration::qtVersionsChanged(const QList<int> &changedVersions)
477 {
478     if (!changedVersions.contains(m_qtVersionId) ||
479         qtVersion()->isValid())
480         return;
481
482     pickValidQtVersion();
483 }
484
485 // returns true if both are equal
486 bool Qt4BuildConfiguration::compareToImportFrom(const QString &makefile)
487 {
488     QMakeStep *qs = qmakeStep();
489     if (QFileInfo(makefile).exists() && qs) {
490         QString qmakePath = QtVersionManager::findQMakeBinaryFromMakefile(makefile);
491         QtVersion *version = qtVersion();
492         if (version->qmakeCommand() == qmakePath) {
493             // same qtversion
494             QPair<QtVersion::QmakeBuildConfigs, QString> result =
495                     QtVersionManager::scanMakeFile(makefile, version->defaultBuildConfig());
496             if (qmakeBuildConfiguration() == result.first) {
497                 // The qmake Build Configuration are the same,
498                 // now compare arguments lists
499                 // we have to compare without the spec/platform cmd argument
500                 // and compare that on its own
501                 QString workingDirectory = QFileInfo(makefile).absolutePath();
502                 QString userArgs = qs->userArguments();
503                 QStringList actualArgs;
504                 QString actualSpec = extractSpecFromArguments(&userArgs, workingDirectory, version, &actualArgs);
505                 if (actualSpec.isEmpty()) {
506                     // Easy one: the user has chosen not to override the settings
507                     actualSpec = version->mkspec();
508                 }
509                 actualArgs += qs->moreArguments();
510
511                 QString qmakeArgs = result.second;
512                 QStringList parsedArgs;
513                 QString parsedSpec = extractSpecFromArguments(&qmakeArgs, workingDirectory, version, &parsedArgs);
514
515                 if (debug) {
516                     qDebug()<<"Actual args:"<<actualArgs;
517                     qDebug()<<"Parsed args:"<<parsedArgs;
518                     qDebug()<<"Actual spec:"<<actualSpec;
519                     qDebug()<<"Parsed spec:"<<parsedSpec;
520                 }
521
522                 // Comparing the sorted list is obviously wrong
523                 // Though haven written a more complete version
524                 // that managed had around 200 lines and yet faild
525                 // to be actually foolproof at all, I think it's
526                 // not feasible without actually taking the qmake
527                 // command line parsing code
528
529                 // Things, sorting gets wrong:
530                 // parameters to positional parameters matter
531                 //  e.g. -o -spec is different from -spec -o
532                 //       -o 1 -spec 2 is diffrent from -spec 1 -o 2
533                 // variable assignment order matters
534                 // variable assignment vs -after
535                 // -norecursive vs. recursive
536                 actualArgs.sort();
537                 parsedArgs.sort();
538                 if (actualArgs == parsedArgs) {
539                     // Specs match exactly
540                     if (actualSpec == parsedSpec)
541                         return true;
542                     // Actual spec is the default one
543 //                    qDebug()<<"AS vs VS"<<actualSpec<<version->mkspec();
544                     if ((actualSpec == version->mkspec() || actualSpec == "default")
545                         && (parsedSpec == version->mkspec() || parsedSpec == "default" || parsedSpec.isEmpty()))
546                         return true;
547                 }
548             } else if (debug) {
549                 qDebug()<<"different qmake buildconfigurations buildconfiguration:"<<qmakeBuildConfiguration()<<" Makefile:"<<result.first;
550             }
551         } else if (debug) {
552             qDebug()<<"diffrent qt versions, buildconfiguration:"<<version->qmakeCommand()<<" Makefile:"<<qmakePath;
553         }
554     }
555     return false;
556 }
557
558 void Qt4BuildConfiguration::removeQMLInspectorFromArguments(QString *args)
559 {
560     for (Utils::QtcProcess::ArgIterator ait(args); ait.next(); )
561         if (ait.value().startsWith(QLatin1String(Constants::QMAKEVAR_QMLJSDEBUGGER_PATH)))
562             ait.deleteArg();
563 }
564
565 QString Qt4BuildConfiguration::extractSpecFromArguments(QString *args,
566                                                         const QString &directory, const QtVersion *version,
567                                                         QStringList *outArgs)
568 {
569     QString parsedSpec;
570
571     bool ignoreNext = false;
572     bool nextIsSpec = false;
573     for (Utils::QtcProcess::ArgIterator ait(args); ait.next(); ) {
574         if (ignoreNext) {
575             ignoreNext = false;
576             ait.deleteArg();
577         } else if (nextIsSpec) {
578             nextIsSpec = false;
579             parsedSpec = QDir::cleanPath(ait.value());
580             ait.deleteArg();
581         } else if (ait.value() == QLatin1String("-spec") || ait.value() == QLatin1String("-platform")) {
582             nextIsSpec = true;
583             ait.deleteArg();
584         } else if (ait.value() == QLatin1String("-cache")) {
585             // We ignore -cache, because qmake contained a bug that it didn't
586             // mention the -cache in the Makefile.
587             // That means changing the -cache option in the additional arguments
588             // does not automatically rerun qmake. Alas, we could try more
589             // intelligent matching for -cache, but i guess people rarely
590             // do use that.
591             ignoreNext = true;
592             ait.deleteArg();
593         } else if (outArgs && ait.isSimple()) {
594             outArgs->append(ait.value());
595         }
596     }
597
598     if (parsedSpec.isEmpty())
599         return QString();
600
601     QString baseMkspecDir = version->versionInfo().value("QMAKE_MKSPECS");
602     if (baseMkspecDir.isEmpty())
603         baseMkspecDir = version->versionInfo().value("QT_INSTALL_DATA") + "/mkspecs";
604
605 #ifdef Q_OS_WIN
606     baseMkspecDir = baseMkspecDir.toLower();
607     parsedSpec = parsedSpec.toLower();
608 #endif
609     // if the path is relative it can be
610     // relative to the working directory (as found in the Makefiles)
611     // or relatively to the mkspec directory
612     // if it is the former we need to get the canonical form
613     // for the other one we don't need to do anything
614     if (QFileInfo(parsedSpec).isRelative()) {
615         if(QFileInfo(directory + QLatin1Char('/') + parsedSpec).exists()) {
616             parsedSpec = QDir::cleanPath(directory + QLatin1Char('/') + parsedSpec);
617 #ifdef Q_OS_WIN
618             parsedSpec = parsedSpec.toLower();
619 #endif
620         } else {
621             parsedSpec = baseMkspecDir + QLatin1Char('/') + parsedSpec;
622         }
623     }
624
625     QFileInfo f2(parsedSpec);
626     while (f2.isSymLink()) {
627         parsedSpec = f2.symLinkTarget();
628         f2.setFile(parsedSpec);
629     }
630
631     if (parsedSpec.startsWith(baseMkspecDir)) {
632         parsedSpec = parsedSpec.mid(baseMkspecDir.length() + 1);
633     } else {
634         QString sourceMkSpecPath = version->sourcePath() + "/mkspecs";
635         if (parsedSpec.startsWith(sourceMkSpecPath)) {
636             parsedSpec = parsedSpec.mid(sourceMkSpecPath.length() + 1);
637         }
638     }
639 #ifdef Q_OS_WIN
640     parsedSpec = parsedSpec.toLower();
641 #endif
642     return parsedSpec;
643 }
644
645 ProjectExplorer::IOutputParser *Qt4BuildConfiguration::createOutputParser() const
646 {
647     ToolChain *tc = toolChain();
648     if (tc)
649         return toolChain()->outputParser();
650     return 0;
651 }
652
653 /*!
654   \class Qt4BuildConfigurationFactory
655 */
656
657 Qt4BuildConfigurationFactory::Qt4BuildConfigurationFactory(QObject *parent) :
658     ProjectExplorer::IBuildConfigurationFactory(parent)
659 {
660     update();
661
662     QtVersionManager *vm = QtVersionManager::instance();
663     connect(vm, SIGNAL(qtVersionsChanged(QList<int>)),
664             this, SLOT(update()));
665 }
666
667 Qt4BuildConfigurationFactory::~Qt4BuildConfigurationFactory()
668 {
669 }
670
671 void Qt4BuildConfigurationFactory::update()
672 {
673     m_versions.clear();
674     QtVersionManager *vm = QtVersionManager::instance();
675     foreach (const QtVersion *version, vm->versions()) {
676         if (version->isValid()) {
677             QString key = QString::fromLatin1(QT4_BC_ID_PREFIX)
678                     + QString::fromLatin1("Qt%1").arg(version->uniqueId());
679             VersionInfo info(tr("Using Qt Version \"%1\"").arg(version->displayName()), version->uniqueId());
680             m_versions.insert(key, info);
681         }
682     }
683     emit availableCreationIdsChanged();
684 }
685
686 QStringList Qt4BuildConfigurationFactory::availableCreationIds(ProjectExplorer::Target *parent) const
687 {
688     if (!qobject_cast<Qt4Target *>(parent))
689         return QStringList();
690
691     QStringList results;
692     QtVersionManager *vm = QtVersionManager::instance();
693     for (QMap<QString, VersionInfo>::const_iterator i = m_versions.constBegin();
694          i != m_versions.constEnd(); ++i) {
695         if (vm->version(i.value().versionId)->supportsTargetId(parent->id()))
696             results.append(i.key());
697     }
698     return results;
699 }
700
701 QString Qt4BuildConfigurationFactory::displayNameForId(const QString &id) const
702 {
703     if (!m_versions.contains(id))
704         return QString();
705     return m_versions.value(id).displayName;
706 }
707
708 bool Qt4BuildConfigurationFactory::canCreate(ProjectExplorer::Target *parent, const QString &id) const
709 {
710     if (!qobject_cast<Qt4Target *>(parent))
711         return false;
712     if (!m_versions.contains(id))
713         return false;
714     const VersionInfo &info = m_versions.value(id);
715     QtVersion *version = QtVersionManager::instance()->version(info.versionId);
716     if (!version ||
717         !version->supportsTargetId(parent->id()))
718         return false;
719     return true;
720 }
721
722 BuildConfiguration *Qt4BuildConfigurationFactory::create(ProjectExplorer::Target *parent, const QString &id)
723 {
724     if (!canCreate(parent, id))
725         return 0;
726
727     const VersionInfo &info = m_versions.value(id);
728     QtVersion *version = QtVersionManager::instance()->version(info.versionId);
729     Q_ASSERT(version);
730
731     Qt4Target *qt4Target(static_cast<Qt4Target *>(parent));
732
733     bool ok;
734     QString buildConfigurationName = QInputDialog::getText(0,
735                           tr("New Configuration"),
736                           tr("New configuration name:"),
737                           QLineEdit::Normal,
738                           version->displayName(),
739                           &ok);
740     buildConfigurationName = buildConfigurationName.trimmed();
741     if (!ok || buildConfigurationName.isEmpty())
742         return 0;
743
744     qt4Target->addQt4BuildConfiguration(tr("%1 Debug").arg(buildConfigurationName),
745                                         version,
746                                         (version->defaultBuildConfig() | QtVersion::DebugBuild),
747                                         QString(), QString());
748     BuildConfiguration *bc =
749     qt4Target->addQt4BuildConfiguration(tr("%1 Release").arg(buildConfigurationName),
750                                         version,
751                                         (version->defaultBuildConfig() & ~QtVersion::DebugBuild),
752                                         QString(), QString());
753     return bc;
754 }
755
756 bool Qt4BuildConfigurationFactory::canClone(ProjectExplorer::Target *parent, ProjectExplorer::BuildConfiguration *source) const
757 {
758     if (!qobject_cast<Qt4Target *>(parent))
759         return false;
760     Qt4BuildConfiguration *qt4bc(qobject_cast<Qt4BuildConfiguration *>(source));
761     if (!qt4bc)
762         return false;
763
764     QtVersion *version = qt4bc->qtVersion();
765     if (!version ||
766         !version->supportsTargetId(parent->id()))
767         return false;
768     return true;
769 }
770
771 BuildConfiguration *Qt4BuildConfigurationFactory::clone(Target *parent, BuildConfiguration *source)
772 {
773     if (!canClone(parent, source))
774         return 0;
775     Qt4Target *target(static_cast<Qt4Target *>(parent));
776     Qt4BuildConfiguration *oldbc(static_cast<Qt4BuildConfiguration *>(source));
777     return new Qt4BuildConfiguration(target, oldbc);
778 }
779
780 bool Qt4BuildConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
781 {
782     QString id(ProjectExplorer::idFromMap(map));
783     if (!qobject_cast<Qt4Target *>(parent))
784         return false;
785     return id.startsWith(QLatin1String(QT4_BC_ID_PREFIX)) ||
786            id == QLatin1String(QT4_BC_ID);
787 }
788
789 BuildConfiguration *Qt4BuildConfigurationFactory::restore(Target *parent, const QVariantMap &map)
790 {
791     if (!canRestore(parent, map))
792         return 0;
793     Qt4Target *target(static_cast<Qt4Target *>(parent));
794     Qt4BuildConfiguration *bc(new Qt4BuildConfiguration(target));
795     if (bc->fromMap(map))
796         return bc;
797     delete bc;
798     return 0;
799 }