OSDN Git Service

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