OSDN Git Service

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