OSDN Git Service

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