OSDN Git Service

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