OSDN Git Service

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