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